Add the Lua plugin API v2 core design, its first plan, and the SDK docs rule - #110
Add the Lua plugin API v2 core design, its first plan, and the SDK docs rule#110an0nn30 wants to merge 5 commits into
Conversation
Documents the clean-break redesign of the plugin core: declarative render with explicit invalidation, a serde data bridge replacing the Lua-source codegen that allowed injection via bus event keys, a host event surface, directory packaging with a manifest and scoped require, and structured config. Also adds the plugin SDK documentation rule to CLAUDE.md: doc updates ship in the same commit as the API change, and documentation review is part of branch review.
Six-task TDD plan for piece 1 of the plugin API v2 core: one convert module, then migration of all four hand-rolled converters, then a verification task that includes the SDK documentation review. Corrects the spec's serde conventions table against behavior verified with a characterization spike on mlua 0.10. An empty Lua table serializes to an object, not an array, and JSON null only becomes Lua nil with serialize_unit_to_null and serialize_none_to_null disabled — the default is a lightuserdata sentinel that compares unequal to nil.
Step 1 of the core is merged, so the spec now records it as done and the plan is marked executed rather than reading as outstanding work. Three corrections to the spec, all found while implementing it: - It named three hand-rolled converters; there were four. The fourth, set_lua_table_from_json_map in session.rs, copied only scalars, so nested objects and arrays were silently dropped from session.current() and session.exec_active(). - The vitest dependency note described fix/plugin-widget-html-xss as pending; it merged in #107. - handle_query is recorded as the last hand-rolled JSON edge still open: it hands on_query a JSON string and discards a malformed reply with .ok(). Verified still present on main; belongs with step 4.
SFTP_FILEZILLA_GAP.md is untracked working-tree scratch that predates this branch and has nothing to do with the plugin API spec. It was picked up by an over-broad git add. The file stays on disk, untracked.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f5c332509e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| **Deleted — security:** `html`. It exists as an escape hatch for gaps in the | ||
| widget set; the correct response to those gaps is to close them, not to keep a | ||
| hole that voids the capability model. If it returns, it comes back behind its | ||
| own capability with sanitization. Note this deletion requires migrating | ||
| `examples/plugins/lua-tmux-manager.lua`, which builds its entire UI from it. |
There was a problem hiding this comment.
Migrate the Java HTML widget before deleting it
When the planned removal of html reaches the shared widget schema and frontend, Java plugins using Widgets.html(...) will start rendering the frontend's [unknown widget: html] fallback: the Java SDK currently exposes two such builder methods, but this migration only names the Lua tmux example and says the Java documentation changes only with HostApi. Remove or replace those Java builder methods and update the Java SDK/docs in the same migration so the v2 API does not retain a callable widget that silently renders nothing.
Useful? React with 👍 / 👎.
Docs only — no code changes. Three files.
1. The
CLAUDE.mddocumentation ruleAdds a STRICT subsection under Delivery Standards: any change to the Lua or Java plugin surface updates
docs/plugin-sdk.mdin the same commit, never batched to the end of a branch, and documentation review is an explicit part of branch review — checked in both directions, entries with no function and functions with no entry.The one-directional check is how
ui.panel_imagesurvived as a documented, callable function that rendered the literal text[unknown widget: image]into users' panels.This is the piece worth landing. It currently binds nobody, including Codex.
2. The v2 core design spec
The design #108 was built from. Covers the four findings that motivated it — no reactive model, plugins blind to the terminal, a security model routed around by its own escape hatches, and a duplicated unsafe data bridge — plus the six-step sequence for the core.
3. The serde data bridge plan
The 1150-line plan #108 executed, kept as the record of how step 1 was built.
Reconciled with what actually shipped
The spec had drifted during implementation. Rather than merge a flattering document:
set_lua_table_from_json_mapinsession.rswas not in the original design. It copied only scalars, so nested objects and arrays were silently dropped fromsession.current()andsession.exec_active()— data loss nobody had noticed.Still open, recorded in the spec
handle_queryinrunner.rshandson_querya hand-serialized JSON string and silently discards a malformed reply viaserde_json::from_str(&result).ok(). It is the last hand-rolled JSON edge in the Lua runtime. Verified still present on main; belongs with the services work in step 4.🤖 Generated with Claude Code