| 1 | # Reasonix Plugin Packages |
| 2 | |
| 3 | Reasonix plugin packages bundle skills, hooks, MCP servers, prompts, themes, |
| 4 | and code extensions behind one installable unit. |
| 5 | |
| 6 | ## CLI Mode |
| 7 | |
| 8 | Use `reasonix plugin` when installing or managing plugin packages from a |
| 9 | terminal. Plugin packages are installed globally under the Reasonix home |
| 10 | directory. |
| 11 | |
| 12 | ### Install From CLI |
| 13 | |
| 14 | `install` accepts one source: |
| 15 | |
| 16 | - A GitHub repository, such as `git:github.com/obra/superpowers` or |
| 17 | `https://github.com/obra/superpowers`. |
| 18 | - A GitHub branch or subdirectory URL, such as |
| 19 | `https://github.com/owner/repo/tree/main/path/to/plugin`. |
| 20 | - A local directory that contains `reasonix-plugin.json`, |
| 21 | `.codex-plugin/plugin.json`, or `.claude-plugin/plugin.json`. |
| 22 | |
| 23 | Preview the install plan without writing files: |
| 24 | |
| 25 | ```bash |
| 26 | reasonix plugin install git:github.com/obra/superpowers --dry-run |
| 27 | ``` |
| 28 | |
| 29 | Install a plugin after reviewing the plan: |
| 30 | |
| 31 | ```bash |
| 32 | reasonix plugin install git:github.com/obra/superpowers --yes |
| 33 | ``` |
| 34 | |
| 35 | Install with an explicit name or replace an installed plugin with the same name: |
| 36 | |
| 37 | ```bash |
| 38 | reasonix plugin install git:github.com/obra/superpowers --name superpowers --replace --yes |
| 39 | ``` |
| 40 | |
| 41 | Use a local directory in developer mode: |
| 42 | |
| 43 | ```bash |
| 44 | reasonix plugin install /path/to/plugin --link --replace --yes |
| 45 | ``` |
| 46 | |
| 47 | CLI install flags: |
| 48 | |
| 49 | - `--dry-run` plans and validates the install without writing files. |
| 50 | - `--yes` is required for any install that writes files. |
| 51 | - `--replace` allows the source to replace an installed plugin with the same |
| 52 | name. |
| 53 | - `--name <name>` or `--name=<name>` overrides the name from the plugin |
| 54 | manifest for this install. |
| 55 | - `--link` links a local plugin directory instead of copying it into Reasonix's |
| 56 | plugin storage. Moving or deleting that directory breaks the linked plugin. |
| 57 | |
| 58 | Running `reasonix plugin install <source>` without `--dry-run` or `--yes` |
| 59 | refuses to write files and prints a reminder to rerun with one of those flags. |
| 60 | Install and remove commands print the structured JSON response from the same |
| 61 | install-source backend used by the desktop UI. |
| 62 | |
| 63 | Installed plugin state is stored in: |
| 64 | |
| 65 | ```text |
| 66 | ~/.reasonix/plugin-packages.json |
| 67 | ~/.reasonix/plugins/<name>/ |
| 68 | ``` |
| 69 | |
| 70 | ### Manage From CLI |
| 71 | |
| 72 | List installed plugins: |
| 73 | |
| 74 | ```bash |
| 75 | reasonix plugin list |
| 76 | ``` |
| 77 | |
| 78 | Show one plugin's metadata, root, source, and exported capability counts: |
| 79 | |
| 80 | ```bash |
| 81 | reasonix plugin show superpowers |
| 82 | ``` |
| 83 | |
| 84 | `show` also prints the concrete capability inventory when available: |
| 85 | |
| 86 | - **skills** include suggested `/<plugin>:<skill>` invocations and descriptions. |
| 87 | - **commands** include `/<plugin>:<command>` invocations, argument hints, and |
| 88 | descriptions. |
| 89 | - **hooks** list lifecycle events, matchers, and commands or context files. |
| 90 | - **mcpServers** list server names, transports, and launch targets. |
| 91 | |
| 92 | Check that the manifest and skill roots are readable: |
| 93 | |
| 94 | ```bash |
| 95 | reasonix plugin doctor superpowers |
| 96 | ``` |
| 97 | |
| 98 | For a workspace-wide capability report (skills, hooks, MCP merge, package roots), see |
| 99 | [Capability diagnostics](./CAPABILITY_DIAGNOSTICS.md): |
| 100 | |
| 101 | ```bash |
| 102 | reasonix doctor capabilities --json |
| 103 | # Desktop: Settings → Diagnostics |
| 104 | # Agent: /reasonix-guide |
| 105 | ``` |
| 106 | |
| 107 | Enable or disable a plugin without uninstalling it: |
| 108 | |
| 109 | ```bash |
| 110 | reasonix plugin disable superpowers |
| 111 | reasonix plugin enable superpowers |
| 112 | ``` |
| 113 | |
| 114 | Remove a plugin: |
| 115 | |
| 116 | ```bash |
| 117 | reasonix plugin remove superpowers --yes |
| 118 | ``` |
| 119 | |
| 120 | `remove` also accepts `uninstall` as an alias. It requires `--yes` because it |
| 121 | writes state and removes copied plugin content. For linked local plugins, the |
| 122 | external source directory is left in place. |
| 123 | |
| 124 | ### Use Installed Plugins From CLI |
| 125 | |
| 126 | Installed plugins do not open a separate chat surface. When a plugin is enabled, |
| 127 | Reasonix loads its capabilities into normal interactive sessions: |
| 128 | |
| 129 | - Run `/plugins` inside an interactive session to list installed plugin |
| 130 | packages. Run `/plugins show <name>` to inspect a plugin's exported skills, |
| 131 | hooks, MCP servers, and usage hints without leaving the chat. |
| 132 | - **Skills** appear in `/skills`. Invoke a plugin skill with |
| 133 | `/<plugin>:<skill> [args]`, or ask |
| 134 | naturally and let the agent choose a matching skill by description. |
| 135 | - **Hooks** run automatically at their configured lifecycle events, such as |
| 136 | `SessionStart`, `UserPromptSubmit`, `PreToolUse`, or `PostToolUse`. |
| 137 | - **MCP servers** join the normal MCP/tool flow. Ask for the task you want done; |
| 138 | Reasonix can call the plugin's tools when they are relevant. |
| 139 | |
| 140 | After installing, enabling, disabling, or updating a plugin from a separate |
| 141 | terminal while a session is already running, start a new `reasonix` session or |
| 142 | reopen `/skills` to verify the current session sees the expected skills. |
| 143 | |
| 144 | ## Desktop Settings |
| 145 | |
| 146 | Open **Settings -> Plugins** to install and manage plugin packages without using |
| 147 | the CLI. |
| 148 | |
| 149 | ### Install Plugins |
| 150 | |
| 151 | The installer has two modes: |
| 152 | |
| 153 | - **Local folder**: click **Choose plugin folder** and select a plugin directory |
| 154 | on disk. The selected path is shown next to the button. |
| 155 | - **Git repository**: enter a Git source such as |
| 156 | `git:github.com/obra/superpowers`. **Install name (optional)** can override |
| 157 | the plugin manifest name for this install or overwrite. |
| 158 | |
| 159 | Use the action buttons after choosing the source and options: |
| 160 | |
| 161 | - **Preview** validates the source and shows the planned install actions without |
| 162 | writing files. |
| 163 | - **Install plugin** installs the selected source using the current options. |
| 164 | - **Refresh plugins** reloads the installed-plugin list from disk and config. |
| 165 | |
| 166 | Installer options: |
| 167 | |
| 168 | - **Overwrite same-name plugin** allows the current source to replace an |
| 169 | installed plugin with the same name. Leave it off when duplicate-name installs |
| 170 | should fail instead of replacing existing content. |
| 171 | - **Developer mode: link source folder** appears for **Local folder** installs. |
| 172 | It links the selected directory instead of copying it into Reasonix's plugin |
| 173 | storage. Use it while developing or debugging a plugin. Moving or deleting the |
| 174 | selected directory will break the linked plugin. |
| 175 | |
| 176 | Preview is the safest first step for a new Git source or local plugin directory. |
| 177 | |
| 178 | ### Manage Installed Plugins |
| 179 | |
| 180 | The installed-plugin list shows each plugin package and its exported skills, |
| 181 | hooks, and MCP servers. Use **Refresh plugins** after editing plugin files or |
| 182 | changing config outside the app. |
| 183 | |
| 184 | Expand a plugin row to manage it: |
| 185 | |
| 186 | - Enable or disable the plugin. |
| 187 | - Read **How to use** for the plugin's exported skills, hooks, and MCP servers. |
| 188 | - **Update** pulls or refreshes an installed plugin when an update source is |
| 189 | available. |
| 190 | - **Doctor** checks the plugin manifest and reports warnings or diagnostics. |
| 191 | - **Remove plugin** uninstalls the package after confirmation. |
| 192 | |
| 193 | ### Use Installed Plugins From Desktop |
| 194 | |
| 195 | The desktop settings page uses the same runtime model as the CLI: |
| 196 | |
| 197 | - Expand an installed plugin to see its **How to use** section. |
| 198 | - In any desktop session, type `/plugins` to list installed plugins, or |
| 199 | `/plugins show <name>` to see the same usage details from the chat surface. |
| 200 | - Skills are shown with package-qualified direct commands such as |
| 201 | `/superpowers:writing-plans`; they are also discoverable from `/skills` in a |
| 202 | session. |
| 203 | - Plugin commands are shown and invoked with package-qualified names such as |
| 204 | `/superpowers:plan`. |
| 205 | - Hooks and MCP servers are listed for transparency. They do not need a manual |
| 206 | "run" button: enabled hooks trigger automatically, and MCP tools are available |
| 207 | through ordinary tool use. |
| 208 | - If a currently open session does not reflect a plugin change, refresh the |
| 209 | plugin list and open a new session. |
| 210 | |
| 211 | ## Native Manifest |
| 212 | |
| 213 | Reasonix plugins can declare `reasonix-plugin.json` at the plugin root: |
| 214 | |
| 215 | ```json |
| 216 | { |
| 217 | "name": "example", |
| 218 | "version": "1.0.0", |
| 219 | "description": "Example plugin", |
| 220 | "skills": "skills", |
| 221 | "hooks": { |
| 222 | "SessionStart": [ |
| 223 | { |
| 224 | "command": "hooks/session-start", |
| 225 | "args": [], |
| 226 | "description": "Load startup context" |
| 227 | }, |
| 228 | { |
| 229 | "command": "printf 'ready' && ./hooks/audit", |
| 230 | "shell": "bash", |
| 231 | "description": "Run a compound shell script" |
| 232 | } |
| 233 | ] |
| 234 | }, |
| 235 | "mcpServers": { |
| 236 | "helper": { |
| 237 | "command": "bin/helper" |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | ``` |
| 242 | |
| 243 | Relative paths are resolved inside the plugin root. Reasonix does not run |
| 244 | third-party install scripts during plugin installation. |
| 245 | |
| 246 | Plugin hook execution is explicit: |
| 247 | |
| 248 | - When `args` is present, including `"args": []`, the hook uses **exec form**. |
| 249 | `command` is the executable and every argument is passed literally, without |
| 250 | shell parsing or interpolation. |
| 251 | - When `args` is absent and `shell` is present, the hook uses **shell form**. |
| 252 | The complete `command` is handed unchanged to `bash`, `powershell`/`pwsh`, |
| 253 | `cmd` (Windows only), or `auto`. On Windows, `auto` prefers Git Bash and |
| 254 | falls back to PowerShell. |
| 255 | - Existing native hooks that declare neither field keep the historical |
| 256 | Reasonix shell-command behavior. `shellCommand: true` remains supported as |
| 257 | the legacy spelling of shell form. |
| 258 | |
| 259 | ## Manifest v1 (Extensions) |
| 260 | |
| 261 | A plugin can opt into the v1 manifest by declaring an `apiVersion`: |
| 262 | |
| 263 | ```json |
| 264 | { |
| 265 | "apiVersion": "reasonix.io/plugin/v1", |
| 266 | "name": "example", |
| 267 | "version": "1.0.0", |
| 268 | "description": "Example extension", |
| 269 | "contributes": { |
| 270 | "skills": ["skills"], |
| 271 | "agents": ["agents"], |
| 272 | "commands": ["commands"], |
| 273 | "prompts": ["prompts"], |
| 274 | "hooks": {}, |
| 275 | "mcpServers": {}, |
| 276 | "themes": ["themes/*.reasonix-theme"] |
| 277 | }, |
| 278 | "runtime": { |
| 279 | "command": "${REASONIX_PLUGIN_ROOT}/bin/example", |
| 280 | "args": [], |
| 281 | "env": {}, |
| 282 | "required": true, |
| 283 | "priority": 0, |
| 284 | "intercepts": ["input.receive", "tool.before"], |
| 285 | "replaces": ["system_prompt"], |
| 286 | "capabilities": ["interceptors", "strategies", "providers", "ui"] |
| 287 | } |
| 288 | } |
| 289 | ``` |
| 290 | |
| 291 | Parsing rules: |
| 292 | |
| 293 | - Manifests **without** `apiVersion` parse exactly as before (legacy format, |
| 294 | unknown fields ignored). |
| 295 | - v1 is strict: any unknown field — at the root or nested under |
| 296 | `contributes`/`runtime` — is an error naming the field path, so typos fail |
| 297 | loudly instead of silently disabling a capability. |
| 298 | - Unknown major versions (`reasonix.io/plugin/v2`, …) are rejected. |
| 299 | - v1 may mix legacy top-level fields (`skills`, `hooks`, `mcpServers`, …) |
| 300 | with `contributes`: identical paths are deduplicated; the same key with two |
| 301 | different definitions is a manifest error naming the key. |
| 302 | - All relative paths and globs must stay inside the plugin root: traversal, |
| 303 | absolute paths, escaping symlinks, and non-regular theme files are |
| 304 | rejected. |
| 305 | |
| 306 | New resource types: |
| 307 | |
| 308 | - `prompts` are prompt templates using the same semantics and argument |
| 309 | substitution as commands, invoked as `/<plugin>:<name>`. `commands` remains |
| 310 | a compatible alias. |
| 311 | - `themes` are `.reasonix-theme` files shown read-only in Desktop Settings as |
| 312 | plugin themes (IDs `plugin:<plugin>:<theme>`); they are never copied into |
| 313 | the user theme library. If the plugin is disabled or uninstalled while its |
| 314 | theme is active, the desktop falls back to the base style but keeps the |
| 315 | ID, so reinstalling the same plugin restores the theme. |
| 316 | |
| 317 | The `runtime` block declares a code extension — a sidecar process Reasonix |
| 318 | launches and talks to over the Extension Protocol (JSON-RPC 2.0 over stdio; |
| 319 | see `docs/EXTENSION_PROTOCOL.generated.md` for the method index and |
| 320 | `sdk/go/README.md` for the Go SDK): |
| 321 | |
| 322 | - `command`/`args`/`env` are **exec form only** — the command is the |
| 323 | executable (never shell-interpreted); `${REASONIX_PLUGIN_ROOT}` expands to |
| 324 | the installed plugin root. |
| 325 | - `intercepts` lists the events the extension wants to intercept (for example |
| 326 | `input.receive`, `tool.before`, `permission.decision`); `replaces` declares |
| 327 | the replacement slots it may own (`system_prompt`, `context`, |
| 328 | `provider_request`, `provider_response`, `compaction`, `session_policy`, |
| 329 | `permission`, `frontend_events`, `tool:<name>`, `provider:<ref>`). Each |
| 330 | slot has exactly one owner across all installed plugins; a collision fails |
| 331 | the build with both sources named. |
| 332 | - `capabilities` gates whole feature families: `interceptors`, `strategies`, |
| 333 | `providers`, `ui`. Anything the sidecar announces beyond the manifest is |
| 334 | rejected during the handshake. |
| 335 | - Provider models contributed by an extension appear as |
| 336 | `plugin/<plugin>/<provider>/<model>` in the model picker; the ref also |
| 337 | works as `default_model` (including on first boot) and in `/model`, |
| 338 | Desktop, and ACP model switches. |
| 339 | |
| 340 | **Full trust.** A code extension runs outside the sandbox with the |
| 341 | unfiltered inherited environment. It can read the full session and |
| 342 | environment, bypass permissions, and operate the machine directly; a |
| 343 | `permission.decision` "allow" from an extension overrides a host deny. |
| 344 | Installing, updating, replacing, or `--link`ing a plugin with a `runtime` |
| 345 | block *is* the authorization — there is no second confirmation prompt, and |
| 346 | `--link` keeps trusting changed content automatically. The install preview, |
| 347 | `reasonix plugin show`, capability diagnostics, and the Desktop installer |
| 348 | therefore display a prominent `FULL TRUST` block with the runtime command, |
| 349 | interceptors, replacement slots, and provider/UI capabilities. Review that |
| 350 | block before installing, and only install runtimes you trust completely. |
| 351 | Only plugins installed through the plugin flow can start a runtime; project |
| 352 | configuration can never declare one. |
| 353 | |
| 354 | ## Codex & Claude Compatibility |
| 355 | |
| 356 | Reasonix also reads Codex plugin manifests at `.codex-plugin/plugin.json` and |
| 357 | Claude plugin manifests at `.claude-plugin/plugin.json`. The install preview |
| 358 | reports `full`, `partial`, or `none` compatibility, lists mapped capabilities, |
| 359 | and identifies every skipped entry. A non-native package with no mapped |
| 360 | capabilities is blocked instead of being recorded as an unusable installation. |
| 361 | `full` means every declared capability in the manifest parsed and mapped to a |
| 362 | Reasonix construct; it does not by itself guarantee every runtime decision an |
| 363 | imported hook can make is honored. `PreToolUse`/`PermissionRequest` "deny" and |
| 364 | `PermissionRequest` "allow" are implemented, but a hook's `updatedInput` or |
| 365 | `PreToolUse`'s `ask`/`defer` decisions are chosen by the script's stdout at |
| 366 | call time, not by anything in the manifest, so they can't be flagged during |
| 367 | install; see the hook bullet below for what's implemented. |
| 368 | GitHub-hosted multi-plugin marketplaces with a |
| 369 | `.claude-plugin/marketplace.json` can be installed from the repository root |
| 370 | when their plugin entries use relative string sources such as |
| 371 | `./plugins/example` or `plugins/example`; preview shows one action per plugin |
| 372 | before anything is written. Set the optional install name to a marketplace |
| 373 | plugin name to select only that entry. Object sources are accepted only for a |
| 374 | GitHub repository URL pinned to a full commit SHA. Unpinned external strings, |
| 375 | npm, `strict: false`, and other advanced marketplace protocols are skipped in |
| 376 | a bulk install and rejected when selected by name. For packages |
| 377 | such as Superpowers and Claude-style skill packs, Reasonix maps: |
| 378 | |
| 379 | - `skills` to Reasonix skill roots. A Claude manifest that declares no |
| 380 | `skills` field falls back to the conventional `skills/` (or `.claude/skills/`) |
| 381 | directory, matching Claude's own auto-discovery. Plugin skills are displayed |
| 382 | and invoked canonically as `/<plugin>:<skill>`. An unambiguous `/<skill>` is |
| 383 | still accepted as a hidden compatibility alias; project and user skills keep |
| 384 | their short names, while same-name skills from multiple plugins remain |
| 385 | independently addressable only by their qualified names. This user-facing |
| 386 | namespace does not change the bare skill identifiers in the model skill index |
| 387 | or the `run_skill` tool. |
| 388 | - `commands/` (and `.claude/commands/`) to Reasonix custom slash commands: each |
| 389 | `<name>.md` prompt template is displayed and invoked canonically as |
| 390 | `/<plugin>:<name>`, with frontmatter `description` / `argument-hint` and |
| 391 | `$ARGUMENTS` / `$1..$N` substitution honored. An unambiguous `/<name>` remains |
| 392 | accepted as a hidden compatibility alias, but it is omitted from completion, |
| 393 | help, desktop menus, ACP command discovery, and the model-visible command |
| 394 | list. User- and project-authored commands own their short names, and no short |
| 395 | alias is created when multiple plugins export the same command name. An |
| 396 | explicit custom command can also occupy the qualified name; desktop plugin |
| 397 | details report that conflict. Native `reasonix-plugin.json` manifests can |
| 398 | declare the same thing explicitly with a `"commands"` path list. |
| 399 | - `agents/*.md` to manually invoked, plugin-owned subagent profiles. Claude |
| 400 | model aliases inherit the active Reasonix model; inline `tools` lists map to |
| 401 | Reasonix tool names, including wildcard MCP names such as `mcp__*__search`. |
| 402 | Agents use `/<plugin>:agent:<name>`, so an upstream agent and skill may share |
| 403 | the same name without shadowing one another. |
| 404 | - `hooks/session-start-codex` to the Reasonix `SessionStart` hook when present. |
| 405 | - A plugin-root `CLAUDE.md` file to a built-in `SessionStart` context hook. The |
| 406 | file is read directly by Reasonix, without spawning a shell command. |
| 407 | - `.claude/settings.json` and `hooks/hooks.json` command hooks to Reasonix hook |
| 408 | events when the event names match. `matcher`, `args`, `shell`, `async`, |
| 409 | `env`, and timeout are preserved. Claude's execution contract is retained: |
| 410 | an `args` field (even an empty array) selects exec form and preserves every |
| 411 | argument literally; omitting `args` selects shell form and passes the raw |
| 412 | command to the declared Bash or PowerShell interpreter. `matcher` and the |
| 413 | `tool_name` a hook script sees are |
| 414 | translated between Reasonix's own tool names and Claude's (`bash` ↔ |
| 415 | `Bash`, `write_file` ↔ `Write`, ...), so a matcher like `"Bash"` fires |
| 416 | correctly; every Reasonix subagent-spawning tool (`task`, `read_only_task`, |
| 417 | `parallel_tasks`, and the dedicated `explore`/`research`/`review`/ |
| 418 | `security_review` wrappers) maps to Claude's single `Agent` tool, and a |
| 419 | matcher can still use the legacy `Task` name. Every mapped `Agent` payload |
| 420 | includes Claude's required `prompt` and `description`; Reasonix supplies a |
| 421 | stable operation label when its tool call omitted the optional description. |
| 422 | `tool_input` keys that |
| 423 | Reasonix names differently from Claude are renamed too — `path` becomes |
| 424 | `file_path` for `Read`/`Write`/`Edit`/`MultiEdit` and `notebook_path` for |
| 425 | `NotebookEdit`, `name`/`arguments` become `skill`/`args` for `Skill`, |
| 426 | `job_id` becomes `task_id` for the current `TaskOutput`/`TaskStop`, the |
| 427 | dedicated subagent wrappers' `task` becomes `Agent`'s `prompt`, and |
| 428 | `parallel_tasks` synthesizes `Agent`'s `prompt` from its sub-task prompts |
| 429 | (keeping `tasks` alongside) — so a guard reading `.tool_input.file_path` |
| 430 | or `.tool_input.prompt` sees the target instead of failing open on an |
| 431 | empty value. Legacy `BashOutput`/`KillShell` matchers still fire while the |
| 432 | emitted names and fields use current Claude vocabulary. `bash_output` |
| 433 | supplies `TaskOutput`'s required non-blocking fields; `wait` also maps to |
| 434 | `TaskOutput`, including `task_id` when it waits for exactly one job, and |
| 435 | omits `TaskOutput`'s optional `timeout` for an unbounded wait rather than |
| 436 | claiming a `0`ms budget. |
| 437 | `AskUserQuestion` supplies omitted `multiSelect:false` and empty option |
| 438 | descriptions, while `TodoWrite` derives an omitted `activeForm` from the |
| 439 | task content. `NotebookEdit` also supplies `new_source` from Reasonix's |
| 440 | accepted aliases, or an empty string for delete/empty-cell operations. |
| 441 | Relative `file_path`/`notebook_path` values are resolved |
| 442 | absolute against the payload `cwd`, matching Claude's file-tool contract, |
| 443 | so prefix-matching guards inspect the path the tool actually accesses. A |
| 444 | `Bash` `tool_response` is delivered in Claude's `{stdout, stderr, |
| 445 | interrupted}` shape (Reasonix combines both streams into `stdout`; the |
| 446 | failure error text becomes `stderr`), which the official security-guidance |
| 447 | plugin's commit/push checks read; other tools' responses pass through as |
| 448 | the raw result. Imported hooks receive Claude-compatible snake_case stdin |
| 449 | payloads, including `hook_event_name`. Before process launch, the host |
| 450 | expands `${CLAUDE_PLUGIN_ROOT}` and `${REASONIX_PLUGIN_ROOT}` (plus their |
| 451 | unbraced `$NAME` and Windows `%NAME%` spellings), so plugin-relative paths |
| 452 | do not depend on the target shell's environment-variable syntax. On Windows, |
| 453 | shell-form hooks without an explicit shell use the same Git Bash-first, |
| 454 | PowerShell-fallback selection as Reasonix's shell tool. Explicit Bash hooks |
| 455 | and legacy bare `sh -c`/`bash -c` hooks are routed through a discovered Git |
| 456 | for Windows Bash even when it is not on `cmd.exe`'s `PATH`; an explicit |
| 457 | interpreter path remains untouched. If no usable Bash is installed, the hook |
| 458 | reports a clear prerequisite error instead of the localized `sh is not |
| 459 | recognized` output. A non-standard or portable Bash configured with |
| 460 | `[tools.shell] prefer = "bash"` and `path = ".../bash.exe"` is reused by |
| 461 | explicit Bash hooks. `reasonix plugin doctor <name>` and |
| 462 | `reasonix doctor capabilities` report a missing required shell before the |
| 463 | first hook invocation. Captured legacy-code-page output is normalized to |
| 464 | UTF-8 before it reaches the UI. A `PreToolUse` or |
| 465 | `UserPromptSubmit` hook can still deny via exit code 2 or its JSON deny |
| 466 | shape on exit 0 (`hookSpecificOutput.permissionDecision` for `PreToolUse`, |
| 467 | top-level `decision:"block"` for `UserPromptSubmit`); an imported |
| 468 | `PermissionRequest` hook additionally answers the permission dialog itself |
| 469 | (deny or auto-allow, rather than only notifying) via exit code 2 or |
| 470 | `hookSpecificOutput.decision.behavior`, matching Claude's own contract. |
| 471 | `updatedInput` is not yet applied to the tool call, and a hook's `if` |
| 472 | condition or `asyncRewake` field is not evaluated. A package reports partial |
| 473 | compatibility with a structured warning when it declares either field, a |
| 474 | `Stop`/`SubagentStop` hook (which cannot block the turn in Reasonix), or a |
| 475 | matcher that covers one of three inputs Reasonix cannot losslessly express: |
| 476 | `WebFetch.prompt`, `NotebookEdit.cell_id` for a Reasonix `cell_number` call, |
| 477 | or `TaskOutput.task_id` when Reasonix `wait` covers multiple/all jobs. Each |
| 478 | structural gap is reported once per hooks file, so a wildcard-matcher |
| 479 | plugin sees one warning per gap instead of one per hook. |
| 480 | - A plugin-root `.mcp.json` to installed MCP entries. Claude `local` maps to |
| 481 | stdio, non-ASCII display names receive stable internal IDs, and duplicate |
| 482 | declarations are deduplicated. Imported servers default to |
| 483 | `auto_start=false`; users connect them on demand so startup does not change |
| 484 | the provider-visible tool schema. |
| 485 | |
| 486 | Unsupported Claude hook item types are skipped with a warning. Reasonix does not |
| 487 | run third-party install scripts. |
| 488 | |
| 489 | Plugin hooks receive these environment variables: |
| 490 | |
| 491 | - `REASONIX_PLUGIN_ROOT` |
| 492 | - `REASONIX_PLUGIN_NAME` |
| 493 | - `REASONIX_PLUGIN_VERSION` |
| 494 | - `REASONIX_HOME` |
| 495 | - `REASONIX_WORKSPACE_ROOT` |
| 496 | - `CLAUDE_PROJECT_DIR` |
| 497 | - `CLAUDE_PLUGIN_ROOT` |
| 498 | |
| 499 | ## Desktop Backend Methods |
| 500 | |
| 501 | Desktop exposes plugin package operations through Wails methods: |
| 502 | |
| 503 | - `Plugins` |
| 504 | - `PlanPluginInstall` |
| 505 | - `InstallPlugin` |
| 506 | - `RemovePlugin` |
| 507 | - `SetPluginEnabled` |
| 508 | - `UpdatePlugin` |
| 509 | - `PluginDoctor` |
| 510 |