Skip to content

feat(agents+installer): narrowing-role subagents (Phase 5) + spellbook-cco fork wiring (Phase 7)#284

Merged
elijahr merged 61 commits into
mainfrom
security-architecture-phase-5
May 18, 2026
Merged

feat(agents+installer): narrowing-role subagents (Phase 5) + spellbook-cco fork wiring (Phase 7)#284
elijahr merged 61 commits into
mainfrom
security-architecture-phase-5

Conversation

@elijahr

@elijahr elijahr commented May 7, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Ships Work Item 5 of the security architecture: 9 narrowing-role subagent definitions in agents/ plus a symlink-based discovery installer that bridges $SPELLBOOK_DIR/agents/ to $CLAUDE_CONFIG_DIR/agents/, since Claude Code 2.1.x discovers agents only from the latter.

Related issue

Checklist

  • Tests pass locally
  • Documentation updated (if applicable)

What this branch ships

  • 9 narrowing-role agents in agents/: implementer, web-researcher, git-committer, git-pusher, pr-creator, pr-merger, jira-reader, jira-mutator, test-runner. Each declares a narrowing tools: list — the effective tool set is (parent_tools ∩ frontmatter_tools) — so a subagent can never gain a capability the parent does not already hold.
  • Symlink installer (installer/components/agents.py): idempotent install_agents / uninstall_agents that symlink $SPELLBOOK_DIR/agents/*.md into $CLAUDE_CONFIG_DIR/agents/. Wired into installer/platforms/claude_code.py per-config-dir loop. User-authored agent files at the target path are preserved; only spellbook-pointing symlinks (including broken ones) are removed on uninstall.
  • Schema validation (tests/test_security/test_agent_frontmatter.py): enforces the canonical 5-section body contract (Purpose / Tools / Output Schema / Guardrails / Constraints) and SHA-256-snapshots the existing 7 agents to catch unintended modification.
  • 27 integration + unit tests (tests/installer/test_agents_symlink.py): all idempotence branches (unchanged / upgraded / skipped-user-symlink / skipped-user-regular-file / installed) and uninstall safety (only removes spellbook-pointing symlinks; preserves user files).

Why the scope was reframed

Two pre-implementation verification spikes (Sec 9.1 and 9.2) corrected the original framing:

  • Sec 9.1: tools: in agent frontmatter is a narrowing list, not a capability granter. The original "capability escalation" framing was dead on arrival; this branch ships narrowing-role agents instead.
  • Sec 9.2: Claude Code 2.1.x does not auto-discover agents from $SPELLBOOK_DIR/agents/ — discovery is rooted at $CLAUDE_CONFIG_DIR/agents/. Hence the symlink installer step.

Drive-by fix (test isolation)

tests/test_hooks/test_memory_auto_store.py had a latent test-order bug: STOP_HARVEST_CACHE_PATH was bound to a real ~/.local/spellbook/cache/... file at import time, which let pytest tmp-dir reuse silently short-circuit _handle_stop via the idempotency cache. Added an autouse=True class fixture that rebinds the cache path per-test and forces feature_enabled("transcript_harvest") to False, immunizing the regex-path tests from worker-LLM config leakage.

Deferred / out of scope

  • Manual claude smoke test in a fresh CLAUDE_CONFIG_DIR=$(mktemp -d) — operator post-merge verification.
  • web-researcher is authored with the correct tools: list but explicitly flagged in its body as requires WI-8 (devcontainer) before being safe to dispatch in production.
  • Bringing the existing code-reviewer and justice-resolver agents into tools:-frontmatter compliance — separate cleanup task per the brief.

Verification

  • Full test suite: 4566 passed, 132 skipped, 531 deselected.
  • Combined WI-5 surface: 82 passed, 1 skipped (regen helper, expected) — tests/test_security/test_agent_frontmatter.py + tests/installer/test_agents_symlink.py.
  • Schema test enforces canonical tools: mapping for all 9 new agents (parametrized over EXPECTED_NEW_AGENTS); byte-snapshot test guards the 7 existing agents.
  • Forbidden-term scans (no L4, tier classifier, tier-based, capability escalation, WI-4) and forbidden-claim scans (no over-attribution of git/gh subcommand blocks to the bash gate) both clean.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant