Date: 2026-04-23
Status: Bootstrap (will be regenerated by /spear:init at v0.1.0)
Owner: BadgersMC
Reflects the design §3.1 layout with the §9 amendment (single polyglot hook script, no .ps1).
spear-plugin/
├── .claude-plugin/
│ └── marketplace.json
├── plugins/
│ └── spear/
│ ├── .claude-plugin/
│ │ └── plugin.json
│ ├── skills/
│ │ ├── using-spear/SKILL.md
│ │ ├── init/SKILL.md
│ │ ├── spec/SKILL.md
│ │ ├── prove/SKILL.md
│ │ ├── engine/SKILL.md
│ │ ├── arch/SKILL.md
│ │ └── refine/SKILL.md
│ ├── hooks/
│ │ ├── hooks.json
│ │ ├── run-hook.cmd # polyglot wrapper (cmd.exe + bash)
│ │ ├── session-start # extensionless POSIX bash
│ │ └── lib/ # shared bash helpers (state.sh, probe.sh)
│ ├── templates/
│ │ ├── tech-stack.md
│ │ ├── requirements.md
│ │ ├── implementation.md
│ │ ├── tasks.md
│ │ └── LayerRulesTest.kt
│ └── migrations/
│ └── README.md # placeholder; first migration ships when schema bumps
├── tests/
│ ├── hooks/ # Bats fixtures + driver
│ │ ├── fixtures/
│ │ │ ├── idle/
│ │ │ ├── prove/
│ │ │ ├── engine/
│ │ │ └── stale-state/ # includes fake gradle on PATH
│ │ └── *.bats
│ ├── skills/ # Node skill-content lint
│ │ └── lint.mjs
│ ├── state/ # Node state-machine simulator
│ │ ├── state-machine.test.mjs
│ │ └── helpers.mjs
│ └── fixtures/
│ └── layer-violation/ # canonical Kotlin layer-violation
├── .github/workflows/ci.yml
├── docs/
│ ├── design/
│ ├── tech-stack.md
│ ├── requirements.md
│ ├── implementation.md
│ └── tasks.md
├── .gitignore
├── README.md
├── CONTRIBUTING.md
└── TESTING.md
Even though this plugin has no compiled JVM domain code, the SPEAR layering principle is mapped onto the artifact types. spear:arch does not run against this repo's own files (the repo ships the rules; it does not consume them). The mapping below is descriptive and used by reviewers.
| "Layer" | Concrete files | May depend on |
|---|---|---|
domain/ (rules-of-the-game) |
docs/requirements.md, docs/tech-stack.md |
nothing |
application/ (workflow prose) |
plugins/spear/skills/**/SKILL.md, plugins/spear/templates/** |
domain/ only — skills cite REQ-IDs but contain no script paths |
infrastructure/ (executable shell + JS) |
plugins/spear/hooks/**, tests/**, .github/workflows/** |
anything |
A skill SKILL.md referencing a hook script path by absolute path (e.g. embedding ${CLAUDE_PLUGIN_ROOT}/hooks/... in skill prose) is a layer violation: skills speak in terms of REQ-IDs and procedural intent; the hook layer owns paths. Reviewers enforce this; CI does not (no AST to scan in markdown).
(Empty — this plugin has no JVM domain code. Section retained because the spear:init template emits an empty section in this exact shape, and the meta-test in REQ-121 will diff against this file.)
# Add JVM-style framework package globs here when SPEAR is applied to a JVM project.
forbidden: []Schema reference: context7 /websites/code_claude_en_plugins-reference + superpowers@5.0.4 example. Required fields: name, owner, plugins[]. Each plugins[] entry needs at minimum name, description, version, source. source: "./plugins/spear" because the plugin lives at that path.
Required field: name. Carry version here (per docs, plugin.json takes priority over marketplace entry when both set). Carry description, author, repository, license, keywords, and the hooks pointer "./hooks/hooks.json". Skills are auto-discovered under ./skills/.
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|clear|compact",
"hooks": [
{
"type": "command",
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
"async": false
}
]
}
]
}
}Mirrors superpowers@5.0.4 exactly. async: false ensures stdout reaches the session before the first user turn.
Mirrors superpowers/hooks/run-hook.cmd byte-for-byte (modulo plugin-name comments). Rationale: Claude Code on Windows auto-prepends bash to any command containing .sh, so we use extensionless POSIX scripts and a .cmd dispatcher; the .cmd is also a valid bash script via the : << 'CMDBLOCK' … CMDBLOCK heredoc trick.
POSIX bash, set -euo pipefail. Responsibilities (REQ-080..REQ-085, REQ-049, REQ-050, REQ-021):
1. Resolve PLUGIN_ROOT and PROJECT_ROOT (PROJECT_ROOT = $PWD).
2. If PROJECT_ROOT lacks both docs/requirements.md and docs/tasks.md → emit short notice, exit 0.
3. Run any pending state-file migrations from plugins/spear/migrations/.
4. Read .claude/spear-state.json if present.
5. If state.testFile is set: re-run the test; reconcile state.testStatus.
6. Probe for context7 / mgrep / semgrep (presence-only check via env / known cache paths).
7. Read using-spear/SKILL.md body.
8. Compose payload: cycle rules + probe results + current task summary + current phase + deferral list.
9. Truncate per REQ-014 if payload approaches 4096 bytes.
10. Escape for JSON (mirroring escape_for_json from superpowers).
11. Emit hookSpecificOutput.additionalContext (Claude Code) or additional_context (Cursor).
12. Exit 0 even on internal error (REQ-085).
Shared bash helpers go in hooks/lib/ so each helper is unit-testable in isolation by Bats (see §4.2).
Functions exposed to skills (skills shell out to these via ${CLAUDE_PLUGIN_ROOT}/hooks/lib/state.sh <fn> <args>):
state_read— print currentphase,currentTaskId,reqIdas JSON.state_assert_phase <expected>— exit 1 with REQ-043 message if mismatch.state_set_phase <new>— atomic write of.claude/spear-state.json.state_record_test <file> <name> <status>— used byprove/engine.state_clear— REQ-048 reset.
All jq-backed for atomicity. Atomic write = write to .claude/spear-state.json.tmp then mv.
Each skill is a markdown file with YAML frontmatter:
---
name: spear:<name>
description: <one-line trigger>
---The body describes the procedure in prose. Where state mutation is required, the skill instructs the agent to invoke ${CLAUDE_PLUGIN_ROOT}/hooks/lib/state.sh <fn> via the Bash tool. Skills do not re-implement state logic.
using-spear/SKILL.md is special: its body is the canonical session-start payload and is pulled by the hook script. It must stay under 4096 bytes (REQ-013).
Five files, used only by spear:init. Each is a literal copy of the v0.1.0-bootstrap form of the four SPEAR docs plus the Konsist template. The tasks.md template is parameterised on the detected language (Kotlin vs TS vs Py vs Go vs Rust) — language-specific blocks are gated by {{#if jvm}} … {{/if}} style conditionals processed by a small bash templater (hooks/lib/template.sh).
Empty for v1.0.0 (schema starts at version 1). When the schema bumps, a 1-to-2.sh script lands here that takes a state-file path, transforms it, writes it back. The session-start hook iterates migrations/ in lex order and runs any whose source version matches the current state file's version field.
Claude Code starts
→ fires SessionStart hook
→ run-hook.cmd dispatches session-start (bash)
→ migrate state if needed
→ reconcile testStatus
→ probe optional tools
→ emit JSON to stdout
→ Claude Code injects additionalContext into session
→ agent sees "using-spear" and tool probe results
agent invokes /spear:spec
→ reads requirements.md, picks REQ-ID
→ drafts tasks.md entry with References + Evidence
→ state.sh state_set_phase spec-done
agent invokes /spear:prove
→ state.sh state_assert_phase spec-done
→ writes failing test, runs it
→ import-diff vs Evidence (REQ-031)
→ state.sh state_record_test <file> <name> red
→ state.sh state_set_phase prove-done
agent invokes /spear:engine
→ state.sh state_assert_phase prove-done
→ writes minimum impl, runs test
→ import-diff vs Evidence
→ state.sh state_record_test <file> <name> green
→ state.sh state_set_phase engine-done
agent invokes /spear:arch
→ state.sh state_assert_phase engine-done
→ scans imports in changed files vs Layer Dependency Rules
→ checks denylist
→ state.sh state_set_phase arch-done
agent invokes /spear:refine
→ state.sh state_assert_phase arch-done
→ refactor + full suite green
→ marks task [x] in tasks.md
→ state.sh state_clear
spec → spec-done then directly to arch → arch-done → refine → idle. The spec-done → arch edge is added explicitly (REQ-045) so the same arch skill code does not need to know task tag — it asserts phase ∈ {engine-done, spec-done}.
When Opus dispatches Sonnet/Haiku workers to write hook scripts, skill bodies, or test files for this plugin, every Agent tool prompt carries the design §5.3 fields:
- Files to create/modify: absolute paths.
- Pre-verified signatures: for hook helpers, the bash function signatures from §3.6; for skill markdown, the frontmatter shape from §3.7.
- Failing test: path + test name (when TDD task).
- Acceptance criteria: which Bats / Node test must go green; "no other files changed".
- Forbidden actions: "do not edit any file outside the listed paths"; "do not add error handling not asserted by the test"; "do not invent fields not in
plugin.jsonschema". - Evidence block: copied verbatim from the task in
tasks.md.
Worker model picked per design §5.3 table: Sonnet for prove/refine; Haiku for engine when test fully constrains; Opus retained for arch and spec.
Plugin starts at 0.1.0 (bootstrap milestone). Bumps per semver. State-file schema starts at version: 1; bump only on a non-additive change.
- Per-skill prose bodies — owned by
plugins/spear/skills/**/SKILL.md. Architecture only specifies the contract (frontmatter shape, where state I/O goes). - CI YAML — owned by
.github/workflows/ci.yml. Architecture only specifies which jobs exist (§7 oftech-stack.md). - Konsist test internals — owned by
plugins/spear/templates/LayerRulesTest.kt. This doc only states it must reflect the layer map.