Claude Code setup
Native plugin
This checkout is also a Claude Code plugin. .claude-plugin/plugin.json registers the shared skills/, the hooks/hooks.json session hook, and the two agents/claude/ roles. .claude-plugin/marketplace.json lists it as zstack@zstack-local with source ./, so Claude Code loads the plugin in place from this checkout. There is no packaging step. The hook needs uv on the execution host.
If you already installed linked skills, preview and apply removal using the original scope first:
uv run scripts/install.py uninstall --host claude
uv run scripts/install.py uninstall --host claude --applyInclude the original --home or --project option if used, and preserve the same CLAUDE_CONFIG_DIR value for both commands if used. Keeping both installations enabled duplicates every skill and agent role.
From this checkout, register the local marketplace and install the plugin:
claude plugin marketplace add "$PWD"
claude plugin install zstack@zstack-localStart a new session. Skills appear as /zstack:how, /zstack:z-mode, and so on; agent roles appear as zstack:z-agent and zstack:comment-sicko. Every skill except setup-zstack keeps disable-model-invocation: true, so how, why, z-mode, and the other workflows remain explicit in Claude Code; setup-zstack permits automatic selection there. Installation does not activate z-mode.
Session hook
Claude Code runs the shared SessionStart Python helper through hooks/hooks.json. Its exec-form command passes ${CLAUDE_PLUGIN_ROOT}/hooks/session_start.py directly to uv as one argument, without shell expansion, including on Windows without Git Bash. Codex uses its own launcher in hooks/codex.json. Claude Code runs an enabled plugin's hooks without a separate trust review, so read hooks/hooks.json and hooks/session_start.py before installing. See Claude's exec-form hook reference.
The hook supplies session-specific enable/disable commands. On explicit z-mode invocation the skill runs enable; on stop z-mode or a style switch it runs disable. Activation is restored on resume and compaction. Forked sessions (--fork-session, /branch) get child-scoped controls and do not inherit activation. Clearing resets it. Later user instructions take precedence over stored state.
The launcher explicitly selects the Claude host, so state lives in CLAUDE_PLUGIN_DATA/z-mode/<session-id>.json, by default ~/.claude/plugins/data/zstack-zstack-local/, even when the environment contains an unrelated PLUGIN_DATA. Uninstalling the plugin deletes that directory unless you pass --keep-data.
The hook supplies one labeled POSIX sh and one PowerShell control template; replace only the final ACTION argument with enable, disable, herdr, or native. Leave every other argument unchanged, including ACTION within paths or session IDs. Use the variant matching the executing tool: POSIX sh for Bash, PowerShell for the PowerShell tool. This preserves paths containing apostrophes in either shell without guessing which tool is active. Claude can use PowerShell on Windows without Git Bash and can enable it on other platforms; see the PowerShell tool reference. Controls write outside the project, so Claude Code may ask for permission first. With filesystem isolation on, the Bash sandbox denies writes to plugin data in ~/.claude, and allowWrite cannot reopen it. A sandboxed control then fails with Operation not permitted on macOS or Read-only file system on Linux and WSL2. The session context tells Claude to request one unsandboxed rerun through the normal permission flow. If you, the auto mode classifier, or strict sandbox mode refuse it, Claude stops retrying controls for the session and gives you the command. Run it with the ! prefix or in a terminal outside Claude Code; background sessions and strict Linux sessions also sandbox ! commands. Until a control succeeds, its selection persists only in the conversation, and a blocked Disable leaves stored activation for resume. Controls run the base Python interpreter fixed when the hook starts, not uv, so a symlinked or copied .venv changed after the hook starts cannot supply the interpreter for an unsandboxed rerun. A .venv present when the hook starts already chooses the hook's own interpreter through uv, and so its base interpreter too. The helper itself is protected only when it lives outside the session's writable directories. If a session can write the plugin checkout, such as when developing zstack in place, sandboxed commands can change files that Claude Code runs unsandboxed at the next session start or compaction. Inspect the checkout before approving a rerun there. Missing or corrupt state means inactive. The hook does not authorize delegation or external actions.
Herdr execution
For Herdr execution, explicitly request "use z-mode with Herdr". The shared hook also supplies Herdr/Native controls in both shells. Herdr changes execution without activating z-mode; Native disables Herdr while retaining the mode. Enable preserves execution; Disable (stopping or switching away from active z-mode) and clear reset both, so a Herdr-only selection survives a style switch. The same-ID preference is a marker beside the mode JSON and does not transfer to children. The hook never launches agents or probes Herdr. Operation requires HERDR_ENV=1 and remains subject to Claude permissions; older installed hooks retain selection conversationally until refreshed.
Codex adversarial review
OpenAI's Codex plugin for Claude Code adds /codex:adversarial-review, a review that challenges the chosen design and its assumptions. Zstack does not bundle or call it. The command sets disable-model-invocation: true, so only you can run it, and it returns Codex's output without verification. Run it yourself as a second-provider check beside /zstack:interrogate, and treat its findings as leads until a run reproduces them. Arena and interrogate reach another model family through the installed Codex CLI instead, using the other-provider route; they do not need the Codex plugin.
Plugin update and removal
Because the plugin loads in place, checkout edits take effect at the next session start or after /reload-plugins. You do not need a version bump to pick up local edits, but changes to packaged content still bump the shared version under the README versioning policy. Keep the checkout at a stable path, because the marketplace records it.
claude plugin uninstall zstack@zstack-local
claude plugin marketplace remove zstack-localRemoving the marketplace also uninstalls its plugins. These commands manage the native plugin; the Python uninstall command manages the linked installation.
Check the plugin and troubleshoot
claude plugin validate . --strict
claude plugin listConfirm zstack@zstack-local is enabled. In a new session, run /agents to confirm the namespaced roles and check the command list for namespaced skills.
| Symptom | Check |
|---|---|
Duplicate /how and /zstack:how | Remove the old linked installation in its original scope. |
claude plugin details zstack reports Agents (0) | On Claude Code 2.1.288 the inventory omits agents listed in the manifest. Check /agents; the session still loads both roles. |
| Skills load but mode persistence is unavailable | Check that uv is on PATH, then look for hook errors in /plugin or a claude --debug log. |
A control reports z-mode state not changed with Operation not permitted or Read-only file system | The Bash sandbox blocks plugin data writes. Approve the unsandboxed rerun, or run the control with the ! prefix or outside Claude Code. |
| New agent file is missing | plugin.json must list every agents/claude/*.md file; uv run scripts/validate.py reports omissions. |
Enabled status proves registration, not skill execution. See the validation record for observed host behavior and remaining gaps.
Install
The linked installation remains available for hosts without plugin support and for project-scoped installs. Use one method, not both.
Install Git, uv, and Claude Code, then clone to a stable location. From the library checkout, preview the personal installation, inspect the output, then apply it:
uv run scripts/install.py --host claude
uv run scripts/install.py --host claude --applyFor an existing project, use the same scope in both commands:
uv run scripts/install.py --host claude --project "/absolute/path/to/project"
uv run scripts/install.py --host claude --project "/absolute/path/to/project" --applyUse --host both to include Codex. Collisions stop installation before any writes; back up custom files and resolve the named conflicts or choose another scope. The installer cannot adopt another checkout's receipt.
INFO
Empty --home or --project values are rejected before any writes.
Locations
| Scope | Skills | Agents |
|---|---|---|
| Personal | $CLAUDE_CONFIG_DIR/skills/<name> (default ~/.claude/skills/<name>) | That root's agents/ |
| Project | .claude/skills/<name> | .claude/agents/ |
Skills are links; native agents are copies. Explicit --home uses that root's .claude, ignoring the environment override so fixture installations stay isolated. A new session discovers these sources. See the native configuration-directory setting.
Invoke
Start a new session in the target project. Confirm how appears in the command list, then invoke /how explain how this command parses arguments; read-only, cite the source. Verify the response uses the intended skill and target source. Invoke /z-mode when ready to route broader work. Explicit-only skills retain disable-model-invocation: true. When the selected mode needs a companion, it reads that installed skill's instructions deliberately.
WARNING
Do not assume an explicit-only skill can be silently auto-selected.
Update and remove
From the original checkout, run git pull --ff-only, then repeat the preview/apply installation commands with the original scope. Skills update through their links; unchanged owned agent copies update on reinstall, while edited copies collide. Restart the session afterward.
To remove, preview uv run scripts/install.py uninstall --host claude, then repeat with --apply. Include the original --project or --home option and preserve the same CLAUDE_CONFIG_DIR value if used. Only this checkout's links and unchanged owned agent copies are removed; modified files remain. Uninstall all scopes before moving the checkout.
Agents
Agent roles use Markdown frontmatter and model: inherit. Prefer zstack:z-agent and zstack:comment-sicko in plugin installations, or z-agent and comment-sicko in linked installations, when exposed. Otherwise use an available native worker with the same scoped brief. Report missing delegation or capability gaps that affect the requested work. Queue work within actual nesting and concurrency limits.
Not a complete sandbox
The comment reviewer excludes Write and Edit and is instructed to avoid all writes, including Bash and MCP. Those exclusions alone are not a complete sandbox.
New tasks, fix rounds, and retries use fresh agents with consolidated briefs. Reuse requires costly agent-held state; stop or drain an old writer before assigning its files to a replacement. See the native lifecycle contract.
Model overrides
Use native model and effort configuration for requested overrides. Modified owned copies are preserved, and future installer runs report collisions.
INFO
The installer does not touch permissions, model settings, hooks, plugins, or MCP configuration.
Project instructions
Claude Code 2.1.281+ supports native AGENTS.md in the documented configurations. If a parent or project CLAUDE.md takes precedence or AGENTS.md support is disabled, use the documented project-instructions option or an explicit CLAUDE.md containing @AGENTS.md. Do not duplicate maintenance rules. This checkout supplies AGENTS.md only.
Resume
claude --resume <id>
claude --continueIf history cannot be verified, use a labeled digest or handoff. Skill resources resolve from their real directory while target commands retain the project cwd.