Skip to content

Latest commit

 

History

History
404 lines (327 loc) · 25.3 KB

File metadata and controls

404 lines (327 loc) · 25.3 KB

Otto — Install into Claude Code

Installing Otto has two phases:

  • Part A · Global (once per machine) — the source toolchains/plugins, Otto's own skills, and the session hook. Lives under ~/.claude/ (%USERPROFILE%\.claude\ on Windows).
  • Part B · Per-repo (in each project Otto drives) — spec-kit scaffolding, Pocock's repo config, and Otto's memory bootstrap. Lives under the repo's .claude/, .specify/, and root.

Paths below use ~ for your home dir. On Windows that's %USERPROFILE% (PowerShell $HOME). Substitute <OTTO_HOME> (and every <LOCAL-PATH> below) with your own clone path.

At a glance — what goes where

Piece Scope Where How
specify CLI (spec-kit) global machine PATH uv tool install …
agent-skills plugin global ~/.claude plugins /plugin install … (bundles a SessionStart hook)
Pocock skills global ~/.claude/skills/ npx skills@latest add …
Otto skills (/flow, recipes, conductor, sync, distill) global ~/.claude/skills/ register-skills script
Otto session hook global ~/.claude/settings.json edit + otto-session-start script
spec-kit project files (.specify/, /speckit-* skills, CLAUDE.md block) per-repo repo .claude/ + .specify/ specify init . --integration claude --script ps
Pocock repo config (docs/agents/*, CLAUDE.md block) per-repo repo root + docs/agents/ /setup-matt-pocock-skills
Otto memory (constitution, CONTEXT, stack.yaml, learnings.md, ADRs) per-repo repo root + .specify/ copy memory/templates/ (never overwrite)
Git disposition — team or private mode per-repo .gitignore or .git/info/exclude choose in B6
Footprint manifest (.otto-manifest.md) per-repo repo root copy + fill template (B8)
Workspace memory (multi-repo efforts) per-workspace coordination dir see scope.md

Prerequisites (global)

  • Claude Code — the VS Code / JetBrains extension or the standalone claude CLI. (The claude command is only on PATH if you installed the CLI; the extension doesn't add it, and that's fine — Otto works in either.)
  • git.
  • Python 3.11+ and uv (or pipx) — for spec-kit's CLI.
  • Node.js / npx — for Pocock's installer.
  • jq — required by agent-skills' SessionStart hook (and used by Otto's hook on macOS/Linux). On Windows the Otto hook uses PowerShell instead, so jq is only needed for agent-skills.
  • Install only the sources you'll use — Otto degrades gracefully and reports what's missing.

Part A — Global installation (once)

A1. Install the source toolchains

A1.1 spec-kit (the specify CLI)

uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z
specify version            # verify
  • Pin a release tag (see ../sources/sources.md for the ref Otto is validated against). pipx works too: pipx install ….
  • PATH (Windows): uv tool install drops specify.exe in %USERPROFILE%\.local\bin, which may not be on PATH. Run uv tool update-shell (or add that dir to PATH), then fully quit + reopen VS Code — a window reload won't refresh PATH for integrated terminals. Stopgap: invoke by full path, %USERPROFILE%\.local\bin\specify.exe.
  • This CLI is spec-kit's only global piece; everything else it does is per-repo (Part B1).

A1.2 agent-skills (Claude Code plugin)

Inside Claude Code:

/plugin marketplace add addyosmani/agent-skills
/plugin install agent-skills@addy-agent-skills
  • Bundles 23 skills, 7 commands (/spec /plan /build /test /review /code-simplify /ship — may appear namespaced as /agent-skills:<cmd>), 3 review personas, and a SessionStart hook that auto-loads its meta-skill. The hook needs jq on PATH; without it the skills still work but the auto-loader degrades.
  • Local-dev alternative: git clone … && claude --plugin-dir <path>.
  • Fully global — no per-repo step.

A1.3 Pocock skills

npx skills@latest add mattpocock/skills
  • Interactive picker — select the skills you want and setup-matt-pocock-skills (you'll need it per-repo in B2). Installs into your user skills.
  • Global; its engineering skills expect a per-repo config (Part B2).

A2. Register Otto's own skills (global)

Clone Otto and point a stable env var at it, then run the register script (it copies Otto's 14 invokable units into ~/.claude/skills/<name>/SKILL.md, appending a note so each resolves its relative links back to the source):

PowerShell (Windows):

$env:OTTO_HOME = "<LOCAL-PATH>"
[Environment]::SetEnvironmentVariable("OTTO_HOME", $env:OTTO_HOME, "User")   # persist
& "$env:OTTO_HOME\install\register-skills.ps1"

bash (macOS/Linux/Git-Bash):

export OTTO_HOME="$HOME/otto-dev"          # add to ~/.bashrc / ~/.zshrc to persist
bash "$OTTO_HOME/install/register-skills.sh"

This registers: /flow, /otto-conductor, /otto-sync, /otto-distill, and the 11 recipes (/otto-greenfield, /otto-feature, /otto-bugfix, /otto-hardening, /otto-refactor, /otto-release, /otto-onboarding, /otto-migration, /otto-assess, /otto-extract, /otto-inception). Re-run it after ANY otto-dev change (pull or local edit) — registered skills are copies, and a stale copy means the host runs old protocol. bash install/verify-otto.sh check 7 detects this drift mechanically (added 2026-07-15, finding R2).

Minimal alternative: register only /flow and let it route you to the rest on demand (everything is reachable through routing once the hook in A3 is active). Edit the script's unit list, or copy just router/flow.md → ~/.claude/skills/flow/SKILL.md.

A3. Register Otto's session hook (global)

The hook is Otto's agentic face: on every session it injects the routing brain (a pointer to the policy + registry + recipes) and the global learnings/ slice as hints-to-verify.

  1. The hook scripts ship in <OTTO_HOME>/install/ — otto-session-start.sh (bash) and otto-session-start.ps1 (PowerShell). They read $OTTO_HOME and no-op if Otto isn't present.
  2. Add the hook to ~/.claude/settings.json (create the file if absent). Use the script for your shell:

macOS / Linux:

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume",
        "hooks": [
          { "type": "command", "command": "bash ~/otto-dev/install/otto-session-start.sh" }
        ]
      }
    ]
  }
}

Windows (PowerShell):

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume",
        "hooks": [
          { "type": "command", "command": "powershell -NoProfile -ExecutionPolicy Bypass -File <LOCAL-PATH>\\install\\otto-session-start.ps1" }
        ]
      }
    ]
  }
}
  • Use the absolute path to your OTTO_HOME so updates are picked up automatically.
  • Pick the interpreter you actually have: Windows ships powershell (5.1, used above); pwsh (PowerShell 7) is not installed by default — check with where pwsh. Using a missing interpreter makes the hook fail silently.
  • If you already run the agent-skills plugin (which adds its own SessionStart hook), that's fine — Claude Code merges hooks from all scopes; both run.
  • Extension caveat (important): in the VS Code / JetBrains extension, SessionStart additionalContext may not surface into the chat — the hook is reliable mainly for the claude CLI. If a fresh session shows no Otto context, that's expected in the extension; use A4's CLAUDE.md pointer instead (hook-free, always loaded). The hook also no-ops unless OTTO_HOME is set in the environment the editor launched with.

A3b. Register the learnings-capture nudge (Stop hook, recommended)

The auto-append rule's known failure mode is forgetting to capture. This hook backstops it: once per substantial session (transcript > ~100 KB, at most one nudge per session via a temp marker) it blocks the stop and reminds the agent to append any durable lesson to learnings before finishing. If nothing qualifies, the agent just finishes — you see at most one extra beat per session.

Scripts: otto-learnings-nudge.ps1 (Windows) / otto-learnings-nudge.sh (macOS/Linux — needs jq, no-ops without it). Add to ~/.claude/settings.json alongside the A3 hook:

Windows (PowerShell):

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          { "type": "command", "command": "powershell -NoProfile -ExecutionPolicy Bypass -File <LOCAL-PATH>\\install\\otto-learnings-nudge.ps1" }
        ]
      }
    ]
  }
}

macOS / Linux:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          { "type": "command", "command": "bash ~/otto-dev/install/otto-learnings-nudge.sh" }
        ]
      }
    ]
  }
}
  • Merge the "Stop" key into the same "hooks" object as A3's "SessionStart" — don't create a second hooks block.
  • The hook never breaks a session: on any parse error, missing field, or missing jq it exits 0 silently.
  • VS Code extension: hooks require a FULL restart. The extension process loads hooks at VS Code startup — a hook added while VS Code is running fires in no session (even new chats) until you fully quit + reopen (a window reload is not enough; the CLI picks changes up per-invocation). Verified 2026-07-15: installed hook, 551 KB session, zero fires; script proven sound by direct invocation. Same class as the A1.1 PATH caveat.

A4. Make Otto active via ~/.claude/CLAUDE.md (recommended — hook-free)

~/.claude/CLAUDE.md is auto-loaded into every session (extension and CLI) with no hook and no OTTO_HOME dependency — so this is the reliable baseline, especially for the VS Code / JetBrains extension where the SessionStart hook (A3) may not surface. Append this block (it only adds a section; your existing preferences stay untouched):

## Otto (dev framework)
- Otto is a recipe-driven dev-workflow system at <LOCAL-PATH>.
  For any non-trivial dev task, route through it: invoke /flow (or the right
  /otto-<recipe>), following <LOCAL-PATH>\router\routing-policy.md.
- Capability map: <LOCAL-PATH>\registry\capabilities.yaml ;
  recipes: <LOCAL-PATH>\workflows\recipes\.
- At the start of Otto work, read <LOCAL-PATH>\learnings\global.md
  and treat its entries as hints-to-verify (re-check named files/flags/versions).
- Gates are evidence-based; never auto-commit (propose the git command, I run it).

Substitute your OTTO_HOME path if different. Per-repo rules go in the repo's own CLAUDE.md (Part B3).

Verify the global install

  • Start a new session (a new chat in the VS Code / JetBrains extension, or claude if you have the CLI). The hook injects context silently into the agent — it is NOT printed to you. Verify by asking the agent: "what does your context say about Otto?" — it should describe Otto + the global learnings. (To eyeball the hook output directly, run the script manually: powershell -File <OTTO_HOME>\install\otto-session-start.ps1.)
  • Type /flow → it should be recognized.
  • /plugin → agent-skills listed/enabled. specify version → prints. ~/.claude/skills/ → contains the Otto + Pocock skills.

Part B — Per-repo setup (each project)

Run these inside a target repository.

B0. Quick path — otto-init (one command)

The whole of Part B (B1–B3, B5–B8) in one pass, with a per-repo verify and a printed card of the remaining human steps. From the target repo root:

PowerShell (Windows):

& "$env:OTTO_HOME\install\otto-init.ps1"                 # defaults: -Mode team -Tracker auto
& "$env:OTTO_HOME\install\otto-init.ps1" -Mode private -Bug -GitInit   # example: private repo, bug ext, init git

bash (macOS/Linux/Git-Bash):

bash "$OTTO_HOME/install/otto-init.sh"                   # defaults: --mode team --tracker auto
bash "$OTTO_HOME/install/otto-init.sh" --mode private --bug --git-init

Flags: -Mode team|private (B6) · -Tracker auto|github|gitlab|local (B2 default; auto reads the git remote) · -Bug (B5) · -SkipSpecKit · -SkipGuardrails · -GitInit · -Force (re-init spec-kit; append a fresh manifest run section — managed blocks are static; delete a sentinel block to re-stamp it).

What it does not do (by design — these are yours): author the constitution (/speckit-constitution), fill stack.yaml, custom PK decisions (run /setup-matt-pocock-skills to override the stamped defaults), Part A globals (preflight reports gaps + install commands), and any git commit. Never overwrites authored files; re-runs are idempotent. B1–B8 below remain the reference for what each phase writes and why.

B1. spec-kit scaffolding

specify init . --integration claude --script ps   # current repo, Windows  (use --script sh on macOS/Linux)
# specify init . --integration claude --script ps --ignore-agent-tools   # if the `claude` binary isn't on PATH
# specify init . --force --integration claude --script ps                # merge into a non-empty repo
  • --integration claude is required — the non-interactive default is copilot, not Claude.
  • --script ps|sh is required in any non-TTY shell (agent, CI, redirected stdin). Without it, init opens an invisible arrow-key script-type picker and blocks forever at zero CPU right after the setup panel — on Windows, isatty() is true even for NUL/pipes, so spec-kit's _stdin_is_interactive() can't tell it isn't interactive (spec-kit commands/init.py:375, verified v0.9.5, 2026-07-15). Harmless in a real terminal; always pass it.
  • VS Code / JetBrains extension users: add --ignore-agent-tools. spec-kit's "Agent Detection" check looks for the standalone claude binary on PATH, which the extension doesn't install — without the flag, init aborts with "claude not found." The flag skips only that check; scaffolding is identical.
  • Scaffolds into the repo: .claude/skills/speckit-*/SKILL.md (9 skills), a managed block in CLAUDE.md (between <!-- SPECKIT … --> markers — your own content is preserved), and .specify/{scripts,templates,memory,workflows,extensions,integrations} (incl. .specify/memory/constitution.md and init-options.json). spec-kit auto-installs its git and agent-context extensions here (git is opt-out via the deprecated --no-git).
  • Command naming: in Claude Code, spec-kit commands install as skills invoked with a hyphen — /speckit-specify, /speckit-plan, /speckit-tasks, /speckit-implement, etc. Otto's docs use the canonical dotted form (/speckit.specify); they refer to the same command — the hyphen is just how Claude renders the skill.

B2. Pocock repo config

Inside Claude Code, in the repo:

/setup-matt-pocock-skills
  • Prompt-driven; writes docs/agents/{issue-tracker,triage-labels,domain}.md and an ## Agent skills block into the repo's CLAUDE.md (or AGENTS.md). Required before the engineering skills (/triage, /to-issues, /diagnose, …) behave correctly.
  • Build/extend the shared-language doc with /grill-with-docs → CONTEXT.md.

B3. Otto memory bootstrap

Seed any missing memory member from ../memory/templates/ — never overwrite an existing one (validate/extend instead). See ../memory/memory-stack.md for what each does.

  • constitution.md → best generated by /speckit-constitution (B1 already seeds .specify/memory/constitution.md); the template is a fallback.
  • CONTEXT.md → from /grill-with-docs (B2), or the template.
  • CLAUDE.md → the repo rule file (spec-kit + Pocock both write managed blocks into it; add your own conventions around them).
  • stack.yaml → fill this in early — it pins runtimes/frameworks/packages + authoritative docs, and drives source-ground. Copy from memory/templates/stack.yaml.
  • learnings.md → optional to pre-create; Otto auto-appends to it on first lesson. (Tracked in git; the session hook reads it.)
  • docs/adr/ → create on first decision (template: memory/templates/ADR.md).

B4. (Workspace / multi-repo efforts)

For a coordinated effort across several repos, also create the workspace-level constitution + CONTEXT + stack.yaml in your chosen coordination location, and a workspace spec with the inter-repo contracts. See ../workflows/scope.md.

B5. (Optional) spec-kit extensions

Enable per repo with specify extension add <id>:

  • bug (opt-in) → the /speckit-bug-assess → /speckit-bug-fix → /speckit-bug-test triage workflow, artifacts under .specify/bugs/<slug>/. Otto surfaces it as an alternate path in the bugfix recipe.
  • git (auto-installed on init) → /speckit-git-validate and /speckit-git-remote are read-only helpers; initialize / feature / commit mutate git and stay human-gated. Keep its auto_commit hook disabled (the default) so Otto never auto-commits.
  • agent-context (auto-installed) → auto-refreshes the <!-- SPECKIT --> block in CLAUDE.md after specify/plan. Background plumbing — no action needed.

specify preset add lean swaps spec-kit's core templates for minimal versions (orthogonal to Otto; affects the spec-kit artifacts, not Otto's routing).

B6. Git disposition — team mode (default) or private mode

Decide who owns Otto's footprint in this repo's history before the first commit, and record the choice in .otto-manifest.md (B8) — its disposition columns are the source of truth for the ignore/exclude lines below.

Team mode (default) — Otto's governance is shared project state

The rule is ignore regenerable/personal tooling, keep governance + artifacts tracked. Add these to the repo's .gitignore (Otto's per-repo setup appends them; create the file if absent):

# spec-kit / Claude Code scaffolding (Otto)
.claude/settings.local.json     # personal/machine-local; never commit
.specify/scripts/               # vendored; regenerated by specify init
.specify/templates/             # vendored; regenerated by specify init

Keep tracked (do NOT ignore): .specify/memory/constitution.md (Otto's governance member), specs/ (spec/plan/tasks artifacts), .claude/skills/, .claude/settings.json, docs/agents/, CLAUDE.md, learnings.md, .otto-manifest.md. Blanket-ignoring .claude/ or .specify/ would drop the constitution + specs from version control — contradicting the memory stack.

Private mode — Otto leaves no trace in the repo's history

For repos where Otto is your tooling, not the project's (client codebases, OSS you contribute to). Goal: the files work locally exactly as in team mode, git never sees them, and no committed line reveals Otto exists — which rules out .gitignore, since an Otto entry there is itself committed and visible to every clone.

The mechanics rest on one git property: ignore rules never apply to tracked files. Exclusions are therefore only "live" where Otto's files were never committed (private repos) and inert in your own repos where they already are tracked — so you can be aggressive without risk:

  • Per-clone: append the block below to .git/info/exclude — identical syntax to .gitignore, but it lives inside .git/, which is never committed or pushed. Invisible to every other clone.
  • Per-machine (optional): put the same block in a global excludes file (git config --global core.excludesFile ~/.config/git/ignore) — set once, covers every repo you ever clone, no per-repo step at all.
# Otto footprint (private mode) — mirror of .otto-manifest.md
.claude/
.specify/
specs/
docs/agents/
CONTEXT.md
stack.yaml
learnings.md
.otto-manifest.md

Rules of private mode:

  1. Never propose commits of Otto files. Git is always human-run (no-auto-git rule); in private mode Otto additionally stops proposing git add/commit for any manifest row — the memory members exist on disk only.
  2. The CLAUDE.md leak. B1 and B2 write managed blocks into the repo's CLAUDE.md. If that file is already tracked, no exclude rule can hide your edits (ignore rules don't apply to tracked files) — skip the block-writing steps and carry the rules in ~/.claude/CLAUDE.md (global, invisible to the repo) or an excluded CLAUDE.local.md instead. If CLAUDE.md is untracked, just exclude the whole file.
  3. No safety net. Excluded files have no history and no remote copy — and git clean -dx deletes ignored files; never run it in a private-mode repo. Anything durable across projects belongs in otto-dev/learnings/global.md, which is versioned and pushed.
  4. Exclude specific paths, not parents. The project may have its own docs/ or .claude/ content; if so, narrow the patterns (e.g. docs/agents/, .claude/skills/speckit-*/) to what the manifest lists rather than excluding a shared parent dir.

B7. git-safety guardrail (strongly recommended)

Otto's "never auto-commit" rule is a policy; the PK git-safety capability makes it mechanical — install it early (before any BUILD/SHIP work) so a stray agent git call is blocked, not just discouraged:

  • In Claude Code, in the repo, invoke /git-guardrails-claude-code (Pocock skill — add it via npx skills@latest add mattpocock/skills if it isn't already installed).
  • It writes a PreToolUse hook to .claude/hooks/block-dangerous-git.sh that blocks dangerous / state-changing git. Keep .claude/hooks/ tracked — it's a shared safety net, not personal config.
  • Backstops spec-kit's git extension (B5): keep that extension's auto_commit disabled; this hook catches anything that slips through. Pairs with the advisory git-practice capability (Otto proposes; you run).

B8. Write the footprint manifest

Finish per-repo setup by writing .otto-manifest.md at the repo root — one row per path the setup created or modified, plus the chosen disposition mode and install date. Copy ../memory/templates/otto-manifest.md (pre-filled with the standard B1–B7 rows) and adjust it to what was actually installed — delete rows for skipped steps, add rows for extras (e.g. the bug extension's .specify/bugs/). Update it whenever a later step adds an artifact.

The manifest is what makes the footprint legible — every operation on it becomes mechanical:

  • Excluding — the B6 ignore/exclude lines are generated from its disposition columns.
  • Uninstalling — walk it bottom-up (see Uninstall below).
  • Auditing — "what did Otto touch here?" is one file read; check it before pushing from a repo you don't own.
  • Drift — /otto-sync diffs its rows against disk to spot scaffolding a source release moved.

Team mode: commit it — it documents the scaffolding for the team. Private mode: it's excluded and lists itself.

Verify the per-repo setup

  • /flow "add a small endpoint" → returns a routing card pointing at feature/SPEC.
  • /speckit-specify (hyphen) is available; .specify/ and the CLAUDE.md managed block exist.
  • docs/agents/*.md exist (from B2); stack.yaml is filled.
  • /git-guardrails-claude-code has been run (B7); .claude/hooks/block-dangerous-git.sh exists.
  • .otto-manifest.md exists, states the disposition mode (B6), and matches what's on disk; in private mode, git status shows none of its rows.

Precedence & gotchas

  • Scope precedence: personal (~/.claude/) > project (.claude/) > plugin (namespaced). So a project skill named flow would shadow the global one — Otto's names are prefixed otto- (except /flow) to avoid clashes.
  • Settings merge: ~/.claude/settings.json (user) merges with <repo>/.claude/settings.json (project) and .claude/settings.local.json (local, gitignored). Hooks from all scopes run — Otto's global hook + agent-skills' plugin hook coexist.
  • Plugin commands are namespaced — agent-skills commands may appear as /agent-skills:spec as well as /spec.
  • spec-kit hyphen vs dot — see B1; /speckit-specify in Claude, /speckit.specify in the canonical docs.
  • jq — only the agent-skills hook hard-requires it; Otto's bash hook degrades to plain stdout without it (and the Windows hook doesn't use it).

Updating & re-syncing

  • After git pull in OTTO_HOME: re-run the register-skills script (A2) and run /otto-sync to re-pin source refs + reconcile the registry.
  • After updating a source (new spec-kit release, etc.): /otto-sync --drift flags any renamed/removed unit that breaks a registry invocation.

Uninstall

  • Otto skills: delete the registered dirs under ~/.claude/skills/ (flow, otto-*). Remove the SessionStart hook block from ~/.claude/settings.json.
  • Sources: /plugin uninstall agent-skills; uv tool uninstall specify-cli; remove Pocock skills from ~/.claude/skills/.
  • Per-repo: walk .otto-manifest.md bottom-up — delete created paths, revert modified ones (the CLAUDE.md managed blocks, the .gitignore block), remove any .git/info/exclude block (private mode), then delete the manifest itself. Repos installed before the manifest existed: delete .specify/, the CLAUDE.md managed blocks, and docs/agents/; check for CONTEXT.md, stack.yaml, learnings.md, docs/adr/ before deleting — they may hold authored content worth keeping.