@nklisch/pi-agile-workflow 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +10 -0
- package/.codex-plugin/plugin.json +28 -0
- package/CHANGELOG.md +591 -0
- package/README.md +107 -0
- package/docs/ARCHITECTURE.md +716 -0
- package/docs/MIGRATION.md +419 -0
- package/docs/PRINCIPLES.md +464 -0
- package/docs/ROADMAP.md +95 -0
- package/docs/SPEC.md +855 -0
- package/docs/VISION.md +106 -0
- package/extensions/agile-workflow.test.ts +419 -0
- package/extensions/agile-workflow.ts +467 -0
- package/hooks/hooks.json +52 -0
- package/hooks/scripts/prompt-context.py +628 -0
- package/hooks/scripts/substrate-maintainer.py +359 -0
- package/hooks/scripts/test_prompt_context.py +757 -0
- package/package.json +30 -0
- package/scripts/install-work-view.sh +165 -0
- package/scripts/tests/agent-metadata.test.sh +75 -0
- package/scripts/tests/bump-version.test.sh +552 -0
- package/scripts/tests/channel-parity.test.sh +117 -0
- package/scripts/tests/convert-content-integrity.test.sh +246 -0
- package/scripts/tests/convert-install-routing.test.sh +159 -0
- package/scripts/tests/install-work-view.test.sh +411 -0
- package/scripts/tests/pi-package-metadata.test.sh +119 -0
- package/scripts/tests/work-board-shim.test.sh +239 -0
- package/scripts/tests/work-view-dist-version.test.sh +105 -0
- package/scripts/work-board.sh +64 -0
- package/scripts/work-view.sh +423 -0
- package/skills/autopilot/SKILL.md +330 -0
- package/skills/autopilot/agents/openai.yaml +6 -0
- package/skills/board/SKILL.md +62 -0
- package/skills/board/agents/openai.yaml +6 -0
- package/skills/bold-refactor/SKILL.md +244 -0
- package/skills/bold-refactor/agents/openai.yaml +6 -0
- package/skills/bug-scan/SKILL.md +378 -0
- package/skills/bug-scan/agents/openai.yaml +6 -0
- package/skills/bug-scan/references/async-promises.md +119 -0
- package/skills/bug-scan/references/concurrency-races.md +148 -0
- package/skills/bug-scan/references/data-layer.md +167 -0
- package/skills/bug-scan/references/error-handling.md +197 -0
- package/skills/bug-scan/references/gate-item-template.md +94 -0
- package/skills/bug-scan/references/language-footguns.md +219 -0
- package/skills/bug-scan/references/parked-item-template.md +103 -0
- package/skills/bug-scan/references/report-template.md +115 -0
- package/skills/bug-scan/references/resource-leaks.md +199 -0
- package/skills/bug-scan/references/state-closures.md +148 -0
- package/skills/bug-scan/references/time-numbers.md +158 -0
- package/skills/convert/SKILL.md +1463 -0
- package/skills/convert/agents/openai.yaml +6 -0
- package/skills/convert/references/legacy-overlap-migration.md +179 -0
- package/skills/deep-code-scan/SKILL.md +378 -0
- package/skills/deep-code-scan/agents/openai.yaml +6 -0
- package/skills/deep-code-scan/references/artifact-ledger.md +148 -0
- package/skills/deep-code-scan/references/consolidation.md +91 -0
- package/skills/deep-code-scan/references/decomposition.md +127 -0
- package/skills/deep-code-scan/references/item-templates.md +263 -0
- package/skills/deep-code-scan/references/lane-catalog.md +129 -0
- package/skills/deep-code-scan/references/review-gauntlet.md +108 -0
- package/skills/deep-code-scan/references/scanner-brief.md +152 -0
- package/skills/e2e-test-design/SKILL.md +517 -0
- package/skills/e2e-test-design/references/anti-tautology.md +261 -0
- package/skills/e2e-test-design/references/service-mocks.md +234 -0
- package/skills/e2e-test-design/references/test-taxonomy.md +211 -0
- package/skills/epic-design/SKILL.md +476 -0
- package/skills/epicize/SKILL.md +210 -0
- package/skills/epicize/agents/openai.yaml +6 -0
- package/skills/feature-design/SKILL.md +472 -0
- package/skills/fix/SKILL.md +173 -0
- package/skills/gate-cruft/SKILL.md +258 -0
- package/skills/gate-docs/SKILL.md +278 -0
- package/skills/gate-patterns/SKILL.md +389 -0
- package/skills/gate-refactor/SKILL.md +408 -0
- package/skills/gate-security/SKILL.md +275 -0
- package/skills/gate-tests/SKILL.md +367 -0
- package/skills/groom/SKILL.md +162 -0
- package/skills/groom/agents/openai.yaml +6 -0
- package/skills/ideate/SKILL.md +185 -0
- package/skills/ideate/agents/openai.yaml +6 -0
- package/skills/implement/SKILL.md +288 -0
- package/skills/implement-orchestrator/SKILL.md +604 -0
- package/skills/park/SKILL.md +111 -0
- package/skills/perf-design/SKILL.md +427 -0
- package/skills/perf-scout/SKILL.md +404 -0
- package/skills/perf-scout/agents/openai.yaml +6 -0
- package/skills/perf-scout/references/algorithmic-and-data-structures.md +126 -0
- package/skills/perf-scout/references/approximation-and-precomputation.md +136 -0
- package/skills/perf-scout/references/caching-and-memoization.md +123 -0
- package/skills/perf-scout/references/compiler-runtime-and-language.md +136 -0
- package/skills/perf-scout/references/database-and-storage-internals.md +144 -0
- package/skills/perf-scout/references/distributed-systems.md +150 -0
- package/skills/perf-scout/references/game-engine-and-realtime.md +136 -0
- package/skills/perf-scout/references/gpu-and-accelerators.md +130 -0
- package/skills/perf-scout/references/idea-ranking.md +75 -0
- package/skills/perf-scout/references/io-and-batching.md +135 -0
- package/skills/perf-scout/references/memory-and-data-locality.md +137 -0
- package/skills/perf-scout/references/parallelism-and-vectorization.md +126 -0
- package/skills/perf-scout/references/parked-item-template.md +117 -0
- package/skills/perf-scout/references/peer-review-pass.md +150 -0
- package/skills/perf-scout/references/report-template.md +148 -0
- package/skills/principles/SKILL.md +678 -0
- package/skills/principles/references/models.md +191 -0
- package/skills/principles/references/subagents.md +158 -0
- package/skills/prose-author/SKILL.md +185 -0
- package/skills/refactor-conventions-creator/SKILL.md +359 -0
- package/skills/refactor-conventions-creator/agents/openai.yaml +6 -0
- package/skills/refactor-conventions-creator/references/common-structures.md +91 -0
- package/skills/refactor-conventions-creator/references/common-styles.md +90 -0
- package/skills/refactor-design/SKILL.md +384 -0
- package/skills/release-deploy/SKILL.md +667 -0
- package/skills/release-deploy/agents/openai.yaml +6 -0
- package/skills/research/SKILL.md +166 -0
- package/skills/research/agents/openai.yaml +6 -0
- package/skills/review/SKILL.md +267 -0
- package/skills/review/references/deep-review.md +98 -0
- package/skills/review/references/review-lenses.md +68 -0
- package/skills/review/references/substrate-side-effects.md +161 -0
- package/skills/review/references/target-resolution.md +52 -0
- package/skills/scope/SKILL.md +486 -0
- package/work-view/Cargo.lock +486 -0
- package/work-view/Cargo.toml +9 -0
- package/work-view/crates/cli/.work-view-version +1 -0
- package/work-view/crates/cli/Cargo.toml +18 -0
- package/work-view/crates/cli/src/actionable.rs +500 -0
- package/work-view/crates/cli/src/args.rs +792 -0
- package/work-view/crates/cli/src/board/assets/board.css +855 -0
- package/work-view/crates/cli/src/board/assets/board.js +259 -0
- package/work-view/crates/cli/src/board/assets/card.js +139 -0
- package/work-view/crates/cli/src/board/assets/components.css +290 -0
- package/work-view/crates/cli/src/board/assets/dependency.js +1193 -0
- package/work-view/crates/cli/src/board/assets/detail.js +256 -0
- package/work-view/crates/cli/src/board/assets/filters.js +389 -0
- package/work-view/crates/cli/src/board/assets/index.html +77 -0
- package/work-view/crates/cli/src/board/assets/kanban.js +231 -0
- package/work-view/crates/cli/src/board/assets/markdown.js +260 -0
- package/work-view/crates/cli/src/board/assets/motion.css +131 -0
- package/work-view/crates/cli/src/board/assets/state.js +245 -0
- package/work-view/crates/cli/src/board/assets/table.js +304 -0
- package/work-view/crates/cli/src/board/assets/tokens.css +602 -0
- package/work-view/crates/cli/src/board/assets/views.js +41 -0
- package/work-view/crates/cli/src/board/assets.rs +162 -0
- package/work-view/crates/cli/src/board/feed.rs +204 -0
- package/work-view/crates/cli/src/board/mod.rs +246 -0
- package/work-view/crates/cli/src/board/open.rs +144 -0
- package/work-view/crates/cli/src/board/server.rs +407 -0
- package/work-view/crates/cli/src/main.rs +195 -0
- package/work-view/crates/cli/src/render.rs +354 -0
- package/work-view/crates/cli/src/scope.rs +157 -0
- package/work-view/crates/cli/src/stale.rs +581 -0
- package/work-view/crates/cli/tests/board-js/dependency-table.test.mjs +64 -0
- package/work-view/crates/cli/tests/board-js/expanded-browsing.test.mjs +79 -0
- package/work-view/crates/cli/tests/board-js/harness-smoke.test.mjs +11 -0
- package/work-view/crates/cli/tests/board-js/harness.mjs +437 -0
- package/work-view/crates/cli/tests/board-js/kanban-detail.test.mjs +75 -0
- package/work-view/crates/cli/tests/board-js/markdown-filter.test.mjs +60 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/CONVENTIONS.md +3 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/active/epics/epic-alpha.md +16 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/active/features/feat-a.md +16 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/active/features/feat-b.md +16 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/active/stories/story-alpha-1.md +16 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/active/stories/story-research-1.md +19 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/archive/feat-done.md +16 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/archive/feat-shipped.md +18 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/backlog/idea-backlog.md +7 -0
- package/work-view/crates/cli/tests/fixtures/golden/.work/releases/v1.0/v1.0.md +16 -0
- package/work-view/crates/cli/tests/fixtures/ready-drafting/.work/CONVENTIONS.md +6 -0
- package/work-view/crates/cli/tests/fixtures/ready-drafting/.work/active/features/feat-dep-done.md +17 -0
- package/work-view/crates/cli/tests/fixtures/ready-drafting/.work/active/features/feat-design-ready.md +17 -0
- package/work-view/crates/cli/tests/fixtures/ready-drafting/.work/active/features/feat-impl-ready.md +17 -0
- package/work-view/crates/cli/tests/fixtures/ready-drafting/.work/active/stories/story-review-ready.md +17 -0
- package/work-view/crates/cli/tests/fixtures/with-malformed/.work/CONVENTIONS.md +4 -0
- package/work-view/crates/cli/tests/fixtures/with-malformed/.work/active/epics/malformed-no-closing-fence.md +8 -0
- package/work-view/crates/cli/tests/fixtures/with-malformed/.work/active/features/good-item.md +16 -0
- package/work-view/crates/cli/tests/integration.rs +2833 -0
- package/work-view/crates/core/Cargo.toml +13 -0
- package/work-view/crates/core/src/error.rs +61 -0
- package/work-view/crates/core/src/filter.rs +804 -0
- package/work-view/crates/core/src/graph.rs +324 -0
- package/work-view/crates/core/src/index.rs +590 -0
- package/work-view/crates/core/src/lib.rs +54 -0
- package/work-view/crates/core/src/model.rs +202 -0
- package/work-view/crates/core/src/parse.rs +494 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/CONVENTIONS.md +15 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/active/epics/epic-core.md +16 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/active/features/feat-parser.md +16 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/active/features/feat-query.md +16 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/active/stories/malformed-no-id.md +15 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/active/stories/story-parse-unit.md +16 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/active/stories/story-security-gate.md +16 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/archive/feat-old.md +16 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/archive/feat-parser.md +17 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/backlog/idea-future-board.md +7 -0
- package/work-view/crates/core/tests/fixtures/golden/.work/releases/v1.0/v1.0.md +16 -0
- package/work-view/crates/core/tests/fixtures/precedence/.work/CONVENTIONS.md +10 -0
- package/work-view/crates/core/tests/fixtures/precedence/.work/archive/dup-item.md +18 -0
- package/work-view/crates/core/tests/fixtures/precedence/.work/releases/v2.0/dup-item.md +18 -0
- package/work-view/crates/core/tests/integration.rs +541 -0
- package/work-view/dist/.gitattributes +1 -0
- package/work-view/dist/README.md +42 -0
- package/work-view/dist/aarch64-apple-darwin/work-view +0 -0
- package/work-view/dist/aarch64-unknown-linux-musl/work-view +0 -0
- package/work-view/dist/x86_64-apple-darwin/work-view +0 -0
- package/work-view/dist/x86_64-unknown-linux-musl/work-view +0 -0
package/docs/SPEC.md
ADDED
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
# SPEC: agile-workflow
|
|
2
|
+
|
|
3
|
+
Technical contracts for the agile-workflow plugin: manifest, frontmatter,
|
|
4
|
+
file layouts, distribution, scripts, hooks, tooling. Implementation must
|
|
5
|
+
conform to this spec; deviations are bugs.
|
|
6
|
+
|
|
7
|
+
## Plugin manifest
|
|
8
|
+
|
|
9
|
+
Located at `plugins/agile-workflow/.claude-plugin/plugin.json`:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"name": "agile-workflow",
|
|
14
|
+
"description": "Markdown-based work-tracking substrate for AI-driven projects. Items as files in .work/, late-binding releases, gates that produce items, goal-backed autopilot queue runner. See docs/VISION.md.",
|
|
15
|
+
"version": "0.10.0",
|
|
16
|
+
"author": { "name": "nklisch" },
|
|
17
|
+
"repository": "https://github.com/nklisch/skills",
|
|
18
|
+
"license": "MIT"
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Auto-discovery picks up:
|
|
23
|
+
- `commands/*.md` — slash commands
|
|
24
|
+
- `skills/<name>/SKILL.md` — skills
|
|
25
|
+
- `hooks/hooks.json` — hook configurations
|
|
26
|
+
- `scripts/` — utility scripts (referenced via `${CLAUDE_PLUGIN_ROOT}`)
|
|
27
|
+
|
|
28
|
+
For hook script paths, use the portable plugin-root form
|
|
29
|
+
`${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}`. Codex sets `PLUGIN_ROOT` /
|
|
30
|
+
`PLUGIN_DATA` and also exports Claude-compatible variables; Claude sets
|
|
31
|
+
`CLAUDE_PLUGIN_ROOT` / `CLAUDE_PLUGIN_DATA`.
|
|
32
|
+
|
|
33
|
+
## Frontmatter contract
|
|
34
|
+
|
|
35
|
+
Every item file in `.work/active/` and `.work/releases/` has YAML
|
|
36
|
+
frontmatter at the top, validated by every skill that reads or writes items.
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
---
|
|
40
|
+
id: <slug> # required, unique within active tier
|
|
41
|
+
kind: epic|feature|story|release # required
|
|
42
|
+
stage: <see stage flow> # required
|
|
43
|
+
tags: [<tag>, ...] # required (may be [])
|
|
44
|
+
parent: <slug>|null # required (null for top-level)
|
|
45
|
+
depends_on: [<slug>, ...] # required (may be [])
|
|
46
|
+
release_binding: <version>|null # required
|
|
47
|
+
gate_origin: <gate-name>|null # required (null unless gate-produced)
|
|
48
|
+
research_refs: [<slug>...] # optional (research artifacts this item tracks/consumes)
|
|
49
|
+
research_origin: <slug>|null # optional (research artifact that spawned this item)
|
|
50
|
+
scan_origin: <slug>|null # optional (scan campaign that spawned this item)
|
|
51
|
+
created: YYYY-MM-DD # required
|
|
52
|
+
updated: YYYY-MM-DD # required, auto-bumped by PostToolUse hook
|
|
53
|
+
---
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Field semantics
|
|
57
|
+
|
|
58
|
+
| Field | Type | Notes |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `id` | slug string | kebab-case. Unique within `.work/active/`. Child slugs qualify with parent prefix (e.g., `playout-architecture-phase1`, not `phase1`). |
|
|
61
|
+
| `kind` | enum | `epic`, `feature`, `story`, or `release`. `task` items have no files — they're checklist lines in a parent's body. |
|
|
62
|
+
| `stage` | enum | Per-kind valid values; see Stage flow below. |
|
|
63
|
+
| `tags` | array of slug strings | Routing tags from the project's taxonomy in `.work/CONVENTIONS.md`. May be empty. Kebab-case. |
|
|
64
|
+
| `parent` | slug or null | **Hierarchy.** `null` for top-level. Points to a parent item's `id`. |
|
|
65
|
+
| `depends_on` | array of slugs | **Sequencing.** Items this cannot start until all listed are at `stage: done`. May be empty. Distinct from `parent`. |
|
|
66
|
+
| `release_binding` | version string or null | Late-binding. `null` until the user binds. Format matches the release file's version (e.g., `v1.2.0`). |
|
|
67
|
+
| `gate_origin` | gate name or null | `null` for user-scoped items. One of `security`, `tests`, `cruft`, `docs`, `patterns`, `refactor` when produced by a gate (`refactor` is the opt-in gate's value). |
|
|
68
|
+
| `research_refs` | array of slug strings | **Optional; defaults to `[]`.** The research artifacts (`.research/` slugs or handles) this work item tracks or consumes — the Arrow 1 coordination link. Missing → `[]`. Query: `work-view --research-refs <slug>` (membership). See `plugins/agentic-research/docs/HANDOFF.md` for the cross-tier contract. |
|
|
69
|
+
| `research_origin` | slug or null | **Optional; defaults to `null`.** The research artifact that spawned this work item — the Arrow 2 grounding link. Mirrors `gate_origin`. Missing/empty/`"null"` → `null`. Query: `work-view --research-origin <slug>` (or `null`). See `plugins/agentic-research/docs/HANDOFF.md`. |
|
|
70
|
+
| `scan_origin` | slug or null | **Optional; defaults to `null`.** The scan campaign (`scan-<goal>`) that produced this work item — the `deep-code-scan` linkage. Mirrors `research_origin`. Missing/empty/`"null"` → `null`. Query: `work-view --scan-origin <slug>` (or `null`). |
|
|
71
|
+
| `created` | ISO date | `YYYY-MM-DD`. Set on creation; never modified. FIFO tie-break in autopilot. |
|
|
72
|
+
| `updated` | ISO date | `YYYY-MM-DD`. Auto-bumped by PostToolUse hook on every item edit. |
|
|
73
|
+
|
|
74
|
+
### Stage flow per kind
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
epic: drafting → implementing → review → done
|
|
78
|
+
feature: drafting → implementing → review → done
|
|
79
|
+
story: implementing → review → done (often skips drafting)
|
|
80
|
+
release: planned → quality-gate → released
|
|
81
|
+
task: [ ] → [x] (checklist line in parent body)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Stages advance only when work completes. No pre-population.
|
|
85
|
+
|
|
86
|
+
### Backlog item shape
|
|
87
|
+
|
|
88
|
+
Items in `.work/backlog/` are leaner — `kind` and `stage` are unknown until
|
|
89
|
+
a scoping pass fixes them.
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
---
|
|
93
|
+
id: <slug>
|
|
94
|
+
created: YYYY-MM-DD
|
|
95
|
+
updated: YYYY-MM-DD # optional; written by park (== created), bumped by the hook on edit
|
|
96
|
+
tags: [<tag>, ...]
|
|
97
|
+
---
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`updated` is **optional** on the backlog contract (it is not in
|
|
101
|
+
`BACKLOG_REQUIRED`). `park` writes it equal to `created` at creation, and the
|
|
102
|
+
PostToolUse hook bumps it on every edit. When absent (e.g. a legacy item parked
|
|
103
|
+
before this contract), consumers treat the last-touched date as `created`. This
|
|
104
|
+
gives a backlog grooming/staleness query a reliable last-touched signal without
|
|
105
|
+
requiring the field — see `backlog_staleness_days` under §`.work/CONVENTIONS.md`.
|
|
106
|
+
|
|
107
|
+
Body: an unscoped capture sized to the input. Simple ideas can be one
|
|
108
|
+
paragraph; richer context notes or roadmap-style multi-arc thoughts can keep
|
|
109
|
+
bullets, references, and current-situation context. Kind, stage, parent,
|
|
110
|
+
dependencies, release binding, and decomposition remain unknown until `scope`
|
|
111
|
+
promotes the item.
|
|
112
|
+
|
|
113
|
+
## Substrate file contracts
|
|
114
|
+
|
|
115
|
+
### `.work/CONVENTIONS.md`
|
|
116
|
+
|
|
117
|
+
Project-owned file written by `convert` interactively. Every operational
|
|
118
|
+
skill reads this at session start (via the SessionStart hook or directly).
|
|
119
|
+
|
|
120
|
+
```markdown
|
|
121
|
+
# Project Conventions
|
|
122
|
+
|
|
123
|
+
## Release mapping
|
|
124
|
+
<branch-held | tag-based | release-branch | none>
|
|
125
|
+
|
|
126
|
+
## Tag taxonomy
|
|
127
|
+
<list of tags this project uses, with one-line semantics>
|
|
128
|
+
- security auth, validation, secrets, supply chain
|
|
129
|
+
- perf throughput, latency, memory — routes to perf-design
|
|
130
|
+
- refactor behavior-preserving structural change ONLY — fails the black-box test (any observable behavior change for callers) means NOT a refactor — routes to refactor-design
|
|
131
|
+
- prose no-code-surface deliverable (docs, conventions, copy) — routes to prose-author (lean authoring lane: brief-as-design, inline implement) # optional — omit if `prose` already means something else in your project (token name may change before v1.0)
|
|
132
|
+
- research grounded research engagement — an input, not a shippable — routes cross-plugin to agentic-research:research-orchestrator; carries a research_dials: block (the commissioning subset of the registration), does not bind to a release, gates run inline (only when the agentic-research plugin is installed)
|
|
133
|
+
|
|
134
|
+
## Slug conventions
|
|
135
|
+
<format and prefix rules>
|
|
136
|
+
|
|
137
|
+
## Stage overrides
|
|
138
|
+
<only if the project deviates from the master>
|
|
139
|
+
|
|
140
|
+
## Terminal-tier retention
|
|
141
|
+
<delete-refs | retain-bodies>
|
|
142
|
+
|
|
143
|
+
## Gate config
|
|
144
|
+
gates_for_release: [security, tests, cruft, docs, patterns]
|
|
145
|
+
gate_finding_routing:
|
|
146
|
+
critical: implementing
|
|
147
|
+
high: implementing
|
|
148
|
+
medium: drafting
|
|
149
|
+
low: backlog
|
|
150
|
+
info: skip
|
|
151
|
+
gate_refactor_scan_library_roots:
|
|
152
|
+
- .agents/skills
|
|
153
|
+
- .claude/skills
|
|
154
|
+
binding_guard: warn
|
|
155
|
+
epic_cohesion: phased
|
|
156
|
+
backlog_staleness_days: 90
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The default `gates_for_release` order is fixed: **security → tests → cruft
|
|
160
|
+
→ docs → patterns**. Override only if the project has a justified reason.
|
|
161
|
+
|
|
162
|
+
**`gate-refactor` is an opt-in gate** — not in the default list. Add it when your project has
|
|
163
|
+
scan-rule libraries installed under `gate_refactor_scan_library_roots` (defaults:
|
|
164
|
+
`{project}/.agents/skills/scan-*/SKILL.md`, then
|
|
165
|
+
`{project}/.claude/skills/scan-*/SKILL.md`). The gate discovers and loads all libraries it finds,
|
|
166
|
+
then checks the release bundle's changed files against every rule. With no libraries installed it
|
|
167
|
+
logs a graceful skip and continues — not an error. Example opt-in:
|
|
168
|
+
|
|
169
|
+
```yaml
|
|
170
|
+
gates_for_release: [security, tests, cruft, docs, patterns, refactor]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**`gate_finding_routing`** controls how item-producing gates place findings after
|
|
174
|
+
each gate normalizes its local vocabulary. Defaults preserve the built-in routing:
|
|
175
|
+
`critical` and `high` create active stories at `stage: implementing`, `medium`
|
|
176
|
+
creates active stories at `stage: drafting`, `low` writes a backlog file, and
|
|
177
|
+
`info` is skipped. Valid target values are `implementing`, `drafting`, `backlog`,
|
|
178
|
+
and `skip`; missing keys fall back to defaults. `skip` means no work item is
|
|
179
|
+
emitted, but the gate still reports skipped counts in its conversational output
|
|
180
|
+
and in any durable gate-run record it already writes. Gate vocabularies stay
|
|
181
|
+
gate-local: security and tests normalize `Critical|High|Medium|Low`, docs
|
|
182
|
+
normalizes `High|Medium`, and cruft/refactor normalize `High|Medium|Low`.
|
|
183
|
+
|
|
184
|
+
**`gate_refactor_scan_library_roots`** controls the parent directories
|
|
185
|
+
`gate-refactor` searches for scan-rule libraries. Defaults preserve current
|
|
186
|
+
behavior: `.agents/skills` first, `.claude/skills` second. Relative paths resolve
|
|
187
|
+
from the project/substrate root; absolute paths are allowed. The gate still only
|
|
188
|
+
loads libraries matching `scan-*/SKILL.md` below each configured root. Duplicate
|
|
189
|
+
libraries are deduped by derived library tag in configured root order, so the
|
|
190
|
+
first discovered library wins. Roots outside the project tree expand the trust
|
|
191
|
+
boundary because the gate loads instructions and reference files from those
|
|
192
|
+
locations.
|
|
193
|
+
|
|
194
|
+
**`binding_guard`** (default **`warn`** when absent) controls the Phase 3.5 binding-consistency check
|
|
195
|
+
in `release-deploy`. Values: `warn` | `halt` | `off`. `warn` runs all three checks and records any
|
|
196
|
+
finding as a durable warning in the release body (replace-or-skip, not appended), then continues.
|
|
197
|
+
`halt` stops the release on any acted-on finding (for projects that hold the no-cross-version-drift
|
|
198
|
+
invariant). `off` skips the checks entirely (short-circuits before any walk).
|
|
199
|
+
|
|
200
|
+
**`epic_cohesion`** (default **`phased`** when absent) governs the severity of an *unbound child of
|
|
201
|
+
a bound parent* (an INCOMPLETE finding). `phased` treats INCOMPLETE entries as informational —
|
|
202
|
+
listed in the warn report, never counting toward a halt (an epic may ship across releases). `total`
|
|
203
|
+
treats them as mismatches acted on per `binding_guard`, like CONFLICTs (the project holds "epics
|
|
204
|
+
ship whole"). CONFLICTs (a child bound to a *different* version than its bound parent, or a done
|
|
205
|
+
parent unbound while its children are bound) always follow `binding_guard` regardless of this dial.
|
|
206
|
+
|
|
207
|
+
**`backlog_staleness_days`** (integer; **absent ⇒ feature inert**) is the age threshold for the
|
|
208
|
+
opt-in backlog staleness query `work-view --stale`. When set, `--stale` lists `.work/backlog/`
|
|
209
|
+
items whose last-touched date — `updated` if present, else `created` — is more than this many days
|
|
210
|
+
before today (local time). When the key is absent, `--stale` surfaces nothing and prints a
|
|
211
|
+
one-line "no `backlog_staleness_days` configured" notice (exit 0) — a project that does not opt in
|
|
212
|
+
sees no behavior change. This is the query surface a backlog grooming capability consumes; it does
|
|
213
|
+
not auto-prune anything.
|
|
214
|
+
|
|
215
|
+
`terminal-tier retention` (default **`delete-refs`**) is **one merged convention** covering the
|
|
216
|
+
whole terminal lifecycle — archival, late-binding, and release collapse — not just on-disk byte
|
|
217
|
+
retention. With `delete-refs`:
|
|
218
|
+
|
|
219
|
+
1. **Archive (decoupled from release).** A `done` item with no `release_binding` becomes a
|
|
220
|
+
**bodyless stub** (frontmatter + `# Title` + `git_ref:` + `archived_atop:`). Its body is pruned to
|
|
221
|
+
git, so terminal prose (which carries zero design authority) cannot leak to future agents.
|
|
222
|
+
`archived_atop` records the release baseline the item was done atop — stamped once, immutable.
|
|
223
|
+
2. **Late-bind unbound archived stubs.** A release pulls in **all unbound archived stubs**
|
|
224
|
+
(`release_binding: null`), confirms the set with the user, and sets their `release_binding`. Each
|
|
225
|
+
stub's `archived_atop` records the baseline it was done atop and is kept as provenance (it surfaces
|
|
226
|
+
in the release summary), NOT used as the gather filter — filtering by strict `archived_atop ==
|
|
227
|
+
prior tag` would strand a stub forever whenever a release is skipped. Late-bound archived stubs
|
|
228
|
+
are re-gated during the release. Gates that need the item body must hydrate it from the stub's
|
|
229
|
+
`git_ref`; a pruned stub body is a lookup requirement, not a reason to skip the item.
|
|
230
|
+
3. **One-summary release.** All bound items (active done + late-bound stubs) collapse into a single
|
|
231
|
+
`.work/releases/<version>/release-<version>.md` table (id, title, kind, `archived_atop`, git ref).
|
|
232
|
+
No per-item placement; full bodies live only in git history.
|
|
233
|
+
|
|
234
|
+
`retain-bodies` is the legacy opt-out (full bodies kept under `.work/archive/` and
|
|
235
|
+
`.work/releases/<version>/`); it keeps the same `archived_atop`/late-binding semantics, just without
|
|
236
|
+
pruning bodies. A repo that already carries a bespoke "Done-item archival" convention describing this
|
|
237
|
+
model should be **converged** into this one merged convention, not left as a duplicate (see
|
|
238
|
+
`convert`).
|
|
239
|
+
|
|
240
|
+
#### Archive stub shape
|
|
241
|
+
|
|
242
|
+
A `done` item with no `release_binding` and no active parent is archived as a bodyless stub. The
|
|
243
|
+
stub is frontmatter + the first `# <Title>` line only; the body is pruned to git history. Its
|
|
244
|
+
frontmatter carries two extra fields beyond the standard contract:
|
|
245
|
+
|
|
246
|
+
- `archived_atop: <release | pre-release>` — the release baseline the item was done atop (see
|
|
247
|
+
computation below). Stamped **once** at archival; immutable thereafter.
|
|
248
|
+
- `git_ref: <sha>` — the commit where the full body lives. Recover it with
|
|
249
|
+
`git show <git_ref>:<path>`.
|
|
250
|
+
|
|
251
|
+
```yaml
|
|
252
|
+
---
|
|
253
|
+
id: <id>
|
|
254
|
+
kind: <kind>
|
|
255
|
+
stage: done
|
|
256
|
+
tags: [...]
|
|
257
|
+
parent: null
|
|
258
|
+
depends_on: []
|
|
259
|
+
release_binding: null # null until a release late-binds it
|
|
260
|
+
archived_atop: <release | pre-release>
|
|
261
|
+
git_ref: <sha>
|
|
262
|
+
created: <orig>
|
|
263
|
+
updated: <today>
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
# <Title>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
#### `archived_atop` computation
|
|
270
|
+
|
|
271
|
+
`archived_atop` is the **latest released version at archival time**, computed deterministically:
|
|
272
|
+
|
|
273
|
+
1. The newest git tag matching the project's release tag shape (e.g. `git describe --tags
|
|
274
|
+
--abbrev=0`), OR
|
|
275
|
+
2. the newest `.work/releases/<version>/` summary, when the project does not tag releases.
|
|
276
|
+
3. If neither exists yet — no release has ever shipped — use the `pre-release` sentinel.
|
|
277
|
+
|
|
278
|
+
Stamp it once when the stub is written and never rewrite it (it is the immutable baseline recorded as
|
|
279
|
+
provenance). Idempotent re-archival preserves the existing `archived_atop`. The
|
|
280
|
+
`/agile-workflow:release-deploy` bind phase gathers **all unbound archived stubs** (not only those
|
|
281
|
+
whose `archived_atop` matches the prior tag) and records each stub's `archived_atop` in the release
|
|
282
|
+
summary as provenance.
|
|
283
|
+
|
|
284
|
+
### AGENTS.md section
|
|
285
|
+
|
|
286
|
+
`convert` appends or replaces, idempotently, a section in the project's
|
|
287
|
+
canonical AGENTS target delimited by HTML comment markers. It detects
|
|
288
|
+
`AGENTS.md`, `.agents/AGENTS.md`, and `.claude/AGENTS.md`, preferring root
|
|
289
|
+
`AGENTS.md` when present and otherwise creating a root symlink/shim so Codex has
|
|
290
|
+
a root-readable entrypoint.
|
|
291
|
+
|
|
292
|
+
```markdown
|
|
293
|
+
<!-- agile-workflow:start -->
|
|
294
|
+
## Agile-Workflow Substrate
|
|
295
|
+
|
|
296
|
+
Work tracked in `.work/` as markdown items with YAML frontmatter
|
|
297
|
+
(`kind, stage, tags, parent, depends_on, release_binding, research_refs, research_origin`).
|
|
298
|
+
Layout: `.work/active/{epics,features,stories}/`, `.work/backlog/`,
|
|
299
|
+
`.work/releases/<version>/`, `.work/archive/`.
|
|
300
|
+
|
|
301
|
+
[slim dense pointers + work-view query patterns + a MANDATORY
|
|
302
|
+
"read `.agents/rules/*.md` before designing/implementing/reviewing"
|
|
303
|
+
read-directive — see ARCHITECTURE.md]
|
|
304
|
+
<!-- agile-workflow:end -->
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
The managed section is **slim**: substrate orientation, `work-view` query
|
|
308
|
+
patterns, and grep-able pointers to the canonical rules file
|
|
309
|
+
`.agents/rules/agile-workflow.md` and the `patterns` skill, plus a mandatory
|
|
310
|
+
read-directive. `convert --update` replaces everything between the markers
|
|
311
|
+
without touching the rest of the selected AGENTS target.
|
|
312
|
+
|
|
313
|
+
### `.agents/rules/` agent rules
|
|
314
|
+
|
|
315
|
+
Dense behavioral rules (tag semantics, test integrity, advisory review, entry
|
|
316
|
+
points) live in the plugin-managed `.agents/rules/agile-workflow.md`, delimited
|
|
317
|
+
by `<!-- agile-workflow:rules:start/end -->` markers. The agile-workflow hook
|
|
318
|
+
force-loads every `.agents/rules/*.md` into agent context (see Hook contracts).
|
|
319
|
+
`convert` writes and verifies `.agents/rules/agile-workflow.md` BEFORE slimming
|
|
320
|
+
the AGENTS section, so the managed-section overwrite can never drop dense rule
|
|
321
|
+
content.
|
|
322
|
+
|
|
323
|
+
User-owned and migrated legacy rule prose lives in separate user-owned
|
|
324
|
+
`.agents/rules/<name>.md` files (e.g. `project.md`), never inside the plugin
|
|
325
|
+
`agile-workflow:rules` markers. When an older repo has `.claude/rules/*.md`,
|
|
326
|
+
`convert`'s content-integrity gate parses each file into Markdown-aware blocks,
|
|
327
|
+
routes structural patterns to `.agents/skills/patterns/` and rule prose to
|
|
328
|
+
`.agents/rules/<name>.md`, verifies every block landed at its canonical home,
|
|
329
|
+
and only then replaces the legacy path with a shim. `.claude/rules/patterns.md`
|
|
330
|
+
is not a supported canonical rules file; its content migrates the same way.
|
|
331
|
+
|
|
332
|
+
### CLAUDE.md compatibility
|
|
333
|
+
|
|
334
|
+
Claude instruction files are not canonical. `convert` detects `CLAUDE.md`,
|
|
335
|
+
`.claude/CLAUDE.md`, and `.agents/CLAUDE.md`, then preserves Claude Code
|
|
336
|
+
compatibility by making each one a symlink to the selected AGENTS target where
|
|
337
|
+
possible. If symlinks are not available, it writes a short shim telling Claude
|
|
338
|
+
Code to read `AGENTS.md`.
|
|
339
|
+
|
|
340
|
+
When migrating an existing regular `CLAUDE.md`, `convert` imports non-duplicate
|
|
341
|
+
content into `AGENTS.md` before replacing it with the symlink or shim.
|
|
342
|
+
|
|
343
|
+
When migrating an older `.claude/rules/*.md`, `convert` follows the same
|
|
344
|
+
preservation rule via the content-integrity gate: route each block to its
|
|
345
|
+
canonical home (`.agents/skills/patterns/` for structural patterns,
|
|
346
|
+
`.agents/rules/<name>.md` for rule prose), verify every block landed, then leave
|
|
347
|
+
only a compatibility shim at the legacy path.
|
|
348
|
+
|
|
349
|
+
## File and directory layout
|
|
350
|
+
|
|
351
|
+
### Plugin source layout
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
plugins/agile-workflow/
|
|
355
|
+
├── .claude-plugin/
|
|
356
|
+
│ └── plugin.json
|
|
357
|
+
├── .codex-plugin/
|
|
358
|
+
│ └── plugin.json
|
|
359
|
+
├── docs/
|
|
360
|
+
│ ├── VISION.md
|
|
361
|
+
│ ├── SPEC.md
|
|
362
|
+
│ ├── ARCHITECTURE.md
|
|
363
|
+
│ ├── PRINCIPLES.md
|
|
364
|
+
│ └── MIGRATION.md
|
|
365
|
+
├── skills/<skill-name>/
|
|
366
|
+
│ ├── SKILL.md
|
|
367
|
+
│ └── references/<topic>.md
|
|
368
|
+
├── hooks/
|
|
369
|
+
│ ├── hooks.json
|
|
370
|
+
│ └── scripts/
|
|
371
|
+
│ ├── prompt-context.py
|
|
372
|
+
│ └── substrate-maintainer.py
|
|
373
|
+
├── scripts/
|
|
374
|
+
│ ├── install-work-view.sh
|
|
375
|
+
│ ├── work-view.sh
|
|
376
|
+
│ └── work-board.sh
|
|
377
|
+
├── work-view/ # Rust workspace: compiled work-view binary + board host
|
|
378
|
+
│ ├── crates/
|
|
379
|
+
│ │ ├── core/ # work-view-core: parse, model, index, graph, filter
|
|
380
|
+
│ │ └── cli/ # work-view binary (CLI + board host)
|
|
381
|
+
│ │ ├── src/board/ # board subcommand: server, feed, assets + embedded assets/
|
|
382
|
+
│ │ └── .work-view-version # plugin-version stamp (lockstep with plugin.json)
|
|
383
|
+
│ └── dist/<target-triple>/work-view # prebuilt per-platform binaries
|
|
384
|
+
├── CHANGELOG.md
|
|
385
|
+
└── README.md
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Bootstrapped project layout
|
|
389
|
+
|
|
390
|
+
After `convert` runs in a project repo:
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
<project-root>/
|
|
394
|
+
├── .work/
|
|
395
|
+
│ ├── active/{epics,features,stories}/<id>.md
|
|
396
|
+
│ ├── backlog/<id>.md
|
|
397
|
+
│ ├── releases/<version>/release-<version>.md # one summary doc (delete-refs)
|
|
398
|
+
│ ├── archive/<id>.md # bodyless ref stubs w/ archived_atop + git_ref (delete-refs)
|
|
399
|
+
│ ├── bin/work-view
|
|
400
|
+
│ └── CONVENTIONS.md
|
|
401
|
+
├── AGENTS.md
|
|
402
|
+
├── CLAUDE.md -> AGENTS.md
|
|
403
|
+
├── docs/
|
|
404
|
+
│ ├── VISION.md
|
|
405
|
+
│ ├── SPEC.md
|
|
406
|
+
│ └── ARCHITECTURE.md
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Distribution
|
|
410
|
+
|
|
411
|
+
The plugin distributes through three equal channels:
|
|
412
|
+
|
|
413
|
+
- Claude Code via the repo-root `.claude-plugin/marketplace.json` and
|
|
414
|
+
`plugins/agile-workflow/.claude-plugin/plugin.json`.
|
|
415
|
+
- OpenAI Codex via the same marketplace index and
|
|
416
|
+
`plugins/agile-workflow/.codex-plugin/plugin.json`.
|
|
417
|
+
- Pi via package metadata in the plugin root, with the same `skills/` directory
|
|
418
|
+
plus Pi-native extensions or prompt templates where they improve substrate
|
|
419
|
+
ergonomics.
|
|
420
|
+
|
|
421
|
+
The three channel metadata files stay in lockstep on name, version,
|
|
422
|
+
description, repository, and license. Pi-specific runtime surfaces wrap the same
|
|
423
|
+
`.work/` substrate; they do not fork the workflow model.
|
|
424
|
+
|
|
425
|
+
**Channel parity posture:** when agile-workflow adds or changes Claude/Codex hook
|
|
426
|
+
behavior, Pi must receive a native extension adapter in the same change unless a
|
|
427
|
+
host capability is explicitly impossible. The adapter should call the shared
|
|
428
|
+
hook scripts or read the same generated sources rather than reimplementing rules
|
|
429
|
+
in a parallel language. Drift is guarded by
|
|
430
|
+
`plugins/agile-workflow/scripts/tests/channel-parity.test.sh`.
|
|
431
|
+
|
|
432
|
+
## Version strategy
|
|
433
|
+
|
|
434
|
+
- Plugin version lives in `plugins/agile-workflow/.claude-plugin/plugin.json`
|
|
435
|
+
- Bumped via existing `./scripts/bump-version.sh agile-workflow <major|minor|patch>`
|
|
436
|
+
- Bump rules:
|
|
437
|
+
- **patch** — new skill, bug fix, or minor update to an existing skill
|
|
438
|
+
- **minor** — significant new capability or breaking change to a skill's workflow
|
|
439
|
+
- **major** — plugin restructure, frontmatter contract change, or
|
|
440
|
+
backwards-incompatible substrate evolution
|
|
441
|
+
- v0.1.0 is the initial release. Pre-1.0 signals that frontmatter and stage
|
|
442
|
+
shapes may shift during the first real-project shakedown.
|
|
443
|
+
- Promote to v1.0.0 when the substrate has carried 2+ projects through a
|
|
444
|
+
complete release cycle without contract changes.
|
|
445
|
+
|
|
446
|
+
### work-view `--version` lockstep
|
|
447
|
+
|
|
448
|
+
Both work-view implementations report the plugin semver so a deployed copy can
|
|
449
|
+
be checked against the plugin with a single string compare:
|
|
450
|
+
|
|
451
|
+
- The Rust CLI and the bash fallback (`scripts/work-view.sh`) each accept
|
|
452
|
+
`--version` / `-V` and print `work-view <semver>\n` (exit 0). The reported
|
|
453
|
+
`<semver>` is the agile-workflow **plugin** version from `plugin.json`, not the
|
|
454
|
+
crate version. Output is byte-identical across both implementations (a parity
|
|
455
|
+
test enforces this). The bash `--version` answer is emitted by a POSIX-safe
|
|
456
|
+
prelude that runs before the Bash-4 guard, so it works even on macOS system
|
|
457
|
+
bash 3.2.
|
|
458
|
+
- `plugin.json` is the single source of truth for the version.
|
|
459
|
+
`bump-version.sh` projects it, in lockstep, into the Rust stamp file
|
|
460
|
+
`work-view/crates/cli/.work-view-version` (compiled in via `include_str!`, no
|
|
461
|
+
trailing newline) and the `WORK_VIEW_VERSION` literal in
|
|
462
|
+
`scripts/work-view.sh`. A `cargo test` assertion fails loudly if the stamp
|
|
463
|
+
drifts from `plugin.json`.
|
|
464
|
+
- The four prebuilt `dist/<triple>/work-view` binaries are compiled by CI **from
|
|
465
|
+
the stamped source**, so they must be rebuilt on the **post-bump** commit:
|
|
466
|
+
after `bump-version.sh` commits and pushes the bump, trigger the "Build
|
|
467
|
+
work-view binaries" workflow (`workflow_dispatch`, `commit_binaries=true`)
|
|
468
|
+
against the bumped commit so the shipped binaries self-report the new semver.
|
|
469
|
+
Rebuilding before the bump would compile the old stamp and ship
|
|
470
|
+
version-mismatched binaries. The installer rejects supported-platform
|
|
471
|
+
prebuilts whose `--version` mismatches the plugin instead of silently
|
|
472
|
+
downgrading to the Bash fallback, so the CI binary refresh must land before a
|
|
473
|
+
bumped plugin is considered publishable.
|
|
474
|
+
|
|
475
|
+
## work-view binary
|
|
476
|
+
|
|
477
|
+
`convert` installs `work-view` into `.work/bin/work-view` via
|
|
478
|
+
`plugins/agile-workflow/scripts/install-work-view.sh`. The project-side tracked
|
|
479
|
+
entrypoint is the installed `work-view` artifact: a version-verified prebuilt
|
|
480
|
+
Rust binary on supported platforms, or the version-stamped Bash fallback only on
|
|
481
|
+
unsupported platforms. The entrypoint is kept fresh by the session hook
|
|
482
|
+
self-heal step, with convert using the same installer as a backstop. It is
|
|
483
|
+
git-tracked, not gitignored, and its `--version` stamp is compared to the plugin
|
|
484
|
+
version when hook or convert freshness checks run.
|
|
485
|
+
|
|
486
|
+
Prebuilt Rust binaries live under
|
|
487
|
+
`plugins/agile-workflow/work-view/dist/<target-triple>/work-view` and are the
|
|
488
|
+
standard install path. The compiled binary provides both the query filters and
|
|
489
|
+
`work-view board`. The Bash fallback (`scripts/work-view.sh`) is a degraded CLI
|
|
490
|
+
fallback for unsupported platforms only; it does not support the interactive
|
|
491
|
+
board. Supported prebuilt target triples:
|
|
492
|
+
|
|
493
|
+
| Triple | Platform |
|
|
494
|
+
|---|---|
|
|
495
|
+
| `x86_64-unknown-linux-musl` | Linux x86_64 (static) |
|
|
496
|
+
| `aarch64-unknown-linux-musl` | Linux aarch64 / ARM64 (static) |
|
|
497
|
+
| `x86_64-apple-darwin` | macOS Intel |
|
|
498
|
+
| `aarch64-apple-darwin` | macOS Apple Silicon (M1/M2/M3) |
|
|
499
|
+
|
|
500
|
+
Prebuilt binaries are produced by `.github/workflows/build-work-view.yml` and
|
|
501
|
+
committed to `dist/` via the manual refresh job after `bump-version.sh` commits
|
|
502
|
+
and pushes the version bump, so CI builds from the bumped source stamp. Users
|
|
503
|
+
need no Rust toolchain — only CI does.
|
|
504
|
+
|
|
505
|
+
The Bash fallback (`work-view.sh`) is pure bash, optional enhancement via `yq`
|
|
506
|
+
if installed, falls back to `grep`+`sed` otherwise. It is a **frozen, degraded
|
|
507
|
+
fallback** for platforms without a shipped prebuilt binary: it preserves the
|
|
508
|
+
core filter surface but intentionally does **not** implement newer Rust-only
|
|
509
|
+
features — no `--scope` (it always queries all tiers, the pre-scope default) and
|
|
510
|
+
no `work-view board`. bash<->Rust byte-parity is no longer enforced. Full
|
|
511
|
+
retirement of the Bash fallback (Rust-only) is tracked as a parked epic.
|
|
512
|
+
|
|
513
|
+
### Flag set
|
|
514
|
+
|
|
515
|
+
| Flag | Argument | Effect |
|
|
516
|
+
|---|---|---|
|
|
517
|
+
| `--stage` | `<stage>` | Filter to items at the given stage |
|
|
518
|
+
| `--tag` | `<tag>` | Filter to items with the given tag (repeatable, AND semantics) |
|
|
519
|
+
| `--kind` | `<kind>` | Filter to items of the given kind |
|
|
520
|
+
| `--parent` | `<id>` | Filter to direct children of the given item |
|
|
521
|
+
| `--release` | `<version>` | Filter by `release_binding` |
|
|
522
|
+
| `--gate` | `<gate>` | Filter by `gate_origin` |
|
|
523
|
+
| `--ready` | (none) | Active-tier items at `stage: drafting`, `implementing`, or `review` with all `depends_on` terminal (`done`/`released`, or resident in `releases/`/`archive/`). **Excludes `[scan]`-tagged items** — they are engagement-owned by `deep-code-scan` and must not be drained by autopilot. |
|
|
524
|
+
| `--blocked` | (none) | Active-tier items at `stage: drafting`, `implementing`, or `review` with at least one non-terminal dependency. Also excludes `[scan]`-tagged items. |
|
|
525
|
+
| `--blocking` | `<id>` | Reverse lookup: items that depend on `<id>` |
|
|
526
|
+
| `--scope` | `<active\|backlog\|releases\|archive\|all>` | Tiers to surface. Default (flag absent) = **active + backlog** (non-terminal); terminal tiers (`releases`/`archive`) are hidden unless requested. `--release`/`--gate` auto-widen to `all` unless `--scope` is set explicitly |
|
|
527
|
+
| `--research-origin` | `<slug>` | Filter by `research_origin` (use `null` to select items with no origin) |
|
|
528
|
+
| `--research-refs` | `<slug>` | Items whose `research_refs` list contains `<slug>` |
|
|
529
|
+
| `--scan-origin` | `<slug>` | Filter by `scan_origin` (use `null` to select items with no scan origin) |
|
|
530
|
+
| `--paths` | (none) | Output only file paths (grep-pipe-friendly) |
|
|
531
|
+
| `--cat` | (none) | Output full bodies of matching items |
|
|
532
|
+
| `--count` | (none) | Output only the match count |
|
|
533
|
+
| `--help` | (none) | Show usage and exit |
|
|
534
|
+
|
|
535
|
+
Multiple filters compose with AND semantics. By default `work-view` surfaces only
|
|
536
|
+
the non-terminal tiers (active + backlog); the unbounded `releases/`/`archive/`
|
|
537
|
+
history is opt-in via `--scope`. Because release-bound and gate-origin items
|
|
538
|
+
migrate into the terminal `releases/` tier when a release ships, `--release` and
|
|
539
|
+
`--gate` are treated as lifecycle queries and auto-widen to all tiers unless an
|
|
540
|
+
explicit `--scope` overrides them. `--scope` is a Rust-binary feature; the frozen
|
|
541
|
+
Bash fallback does not implement it (see below).
|
|
542
|
+
|
|
543
|
+
### Output modes
|
|
544
|
+
|
|
545
|
+
- **Default (tabular):** `id | kind | stage | tags | parent` — padded rows
|
|
546
|
+
- **`--paths`:** one path per line
|
|
547
|
+
- **`--cat`:** full file bodies separated by `---` lines
|
|
548
|
+
- **`--count`:** integer
|
|
549
|
+
|
|
550
|
+
### Exit codes
|
|
551
|
+
|
|
552
|
+
| Code | Meaning |
|
|
553
|
+
|---|---|
|
|
554
|
+
| `0` | Success |
|
|
555
|
+
| `1` | Usage error (bad flag, conflicting flags) |
|
|
556
|
+
| `2` | Substrate not found (no `.work/CONVENTIONS.md` in CWD or ancestor) |
|
|
557
|
+
| `3` | Internal error (corrupted item file, etc.) |
|
|
558
|
+
|
|
559
|
+
## Interactive board
|
|
560
|
+
|
|
561
|
+
The human board surface is `plugins/agile-workflow/skills/board/SKILL.md` and
|
|
562
|
+
the compiled `work-view board` subcommand. It serves a live localhost view of
|
|
563
|
+
the `.work/` substrate, backed by the Rust query core and embedded assets. The
|
|
564
|
+
server binds `127.0.0.1`, scans upward from the requested port when that port is
|
|
565
|
+
busy, and never exposes the user's absolute paths or raw item frontmatter in the
|
|
566
|
+
browser API. Requests must carry a loopback `Host` authority (`127.0.0.1`,
|
|
567
|
+
`localhost`, or `[::1]`) so a page on a non-local origin cannot use DNS
|
|
568
|
+
rebinding to read the board feed.
|
|
569
|
+
|
|
570
|
+
`plugins/agile-workflow/scripts/work-board.sh` remains only as a compatibility
|
|
571
|
+
shim for older invocations. It does not render HTML. It checks for a
|
|
572
|
+
board-capable `.work/bin/work-view`, execs `.work/bin/work-view board "$@"` when
|
|
573
|
+
available, and otherwise prints an actionable compiled-binary requirement.
|
|
574
|
+
|
|
575
|
+
### Flag set
|
|
576
|
+
|
|
577
|
+
| Flag | Argument | Effect |
|
|
578
|
+
|---|---|---|
|
|
579
|
+
| `--port` | `<port>` | Bind localhost starting at this port, default `8181` |
|
|
580
|
+
| `--no-open` | (none) | Do not launch a browser after binding |
|
|
581
|
+
| `--print` | (none) | Alias for `--no-open` |
|
|
582
|
+
| `--help` | (none) | Show usage and exit |
|
|
583
|
+
|
|
584
|
+
### Swimlanes and stage columns
|
|
585
|
+
|
|
586
|
+
The kanban view groups items into **swimlanes by parent** — the item's `parent`
|
|
587
|
+
id, else its owning epic id, else a `(no parent)` lane. Within each lane it
|
|
588
|
+
renders one **column per distinct stage value**, in preferred order:
|
|
589
|
+
|
|
590
|
+
```
|
|
591
|
+
drafting → implementing → review → done → released
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Any other stage values present in the items (e.g. `planned`, `quality-gate`)
|
|
595
|
+
follow as their own columns after the preferred order, with a trailing column
|
|
596
|
+
for items that have no stage. Stages are shown **verbatim** — the board does not
|
|
597
|
+
collapse or rename them. Backlog items are surfaced through the kind filter
|
|
598
|
+
(`backlog` is a selectable kind), not a dedicated column.
|
|
599
|
+
|
|
600
|
+
### Browser API shape
|
|
601
|
+
|
|
602
|
+
`GET /api/substrate` returns JSON with project metadata, diagnostics, and an
|
|
603
|
+
array of item objects:
|
|
604
|
+
|
|
605
|
+
```ts
|
|
606
|
+
{
|
|
607
|
+
work_view_version: string;
|
|
608
|
+
project: string;
|
|
609
|
+
root_rel: string;
|
|
610
|
+
diagnostics: {
|
|
611
|
+
parse_errors: Array<{ rel_path: string; reason: string }>;
|
|
612
|
+
validation_warnings: Array<ItemDiagnostic>;
|
|
613
|
+
duplicate_ids: Array<ItemDiagnostic>;
|
|
614
|
+
};
|
|
615
|
+
items: Array<{
|
|
616
|
+
id: string;
|
|
617
|
+
kind: 'epic' | 'feature' | 'story' | 'release' | null;
|
|
618
|
+
tier: 'active' | 'backlog' | 'releases' | 'archive';
|
|
619
|
+
stage: string | null;
|
|
620
|
+
parent: string | null;
|
|
621
|
+
release_binding: string | null;
|
|
622
|
+
gate_origin: string | null;
|
|
623
|
+
research_origin: string | null;
|
|
624
|
+
research_refs: string[];
|
|
625
|
+
scan_origin: string | null;
|
|
626
|
+
created: string | null;
|
|
627
|
+
updated: string | null;
|
|
628
|
+
tags: string[];
|
|
629
|
+
depends_on: string[];
|
|
630
|
+
unmet_deps: string[];
|
|
631
|
+
dependents: string[];
|
|
632
|
+
children: string[];
|
|
633
|
+
ready: boolean;
|
|
634
|
+
blocked: boolean;
|
|
635
|
+
is_terminal: boolean;
|
|
636
|
+
body: string;
|
|
637
|
+
rel_path: string;
|
|
638
|
+
}>;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
type ItemDiagnostic = {
|
|
642
|
+
rel_path: string;
|
|
643
|
+
tier: 'active' | 'backlog' | 'releases' | 'archive';
|
|
644
|
+
id: string | null;
|
|
645
|
+
field: string | null;
|
|
646
|
+
reason: string;
|
|
647
|
+
};
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
The API intentionally omits absolute filesystem paths and the raw item text
|
|
651
|
+
envelope. Markdown body content is returned for display, while frontmatter is
|
|
652
|
+
represented by parsed fields.
|
|
653
|
+
|
|
654
|
+
### Exit codes
|
|
655
|
+
|
|
656
|
+
| Code | Meaning |
|
|
657
|
+
|---|---|
|
|
658
|
+
| `0` | Success |
|
|
659
|
+
| `1` | Usage error (bad flag) |
|
|
660
|
+
| `2` | Substrate not found |
|
|
661
|
+
|
|
662
|
+
## Hook contracts
|
|
663
|
+
|
|
664
|
+
Hooks live in `plugins/agile-workflow/hooks/hooks.json`.
|
|
665
|
+
|
|
666
|
+
### SessionStart / PostCompact hooks
|
|
667
|
+
|
|
668
|
+
```json
|
|
669
|
+
{
|
|
670
|
+
"SessionStart": [
|
|
671
|
+
{
|
|
672
|
+
"matcher": "startup|resume|clear|compact",
|
|
673
|
+
"hooks": [
|
|
674
|
+
{
|
|
675
|
+
"type": "command",
|
|
676
|
+
"command": "PYTHONDONTWRITEBYTECODE=1 python3 ${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/hooks/scripts/prompt-context.py",
|
|
677
|
+
"timeout": 5
|
|
678
|
+
}
|
|
679
|
+
]
|
|
680
|
+
}
|
|
681
|
+
],
|
|
682
|
+
"PostCompact": [
|
|
683
|
+
{
|
|
684
|
+
"matcher": "manual|auto",
|
|
685
|
+
"hooks": [
|
|
686
|
+
{
|
|
687
|
+
"type": "command",
|
|
688
|
+
"command": "PYTHONDONTWRITEBYTECODE=1 python3 ${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/hooks/scripts/prompt-context.py",
|
|
689
|
+
"timeout": 5
|
|
690
|
+
}
|
|
691
|
+
]
|
|
692
|
+
}
|
|
693
|
+
]
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
**Activation:** resolves the substrate root by walking up from the hook payload's
|
|
698
|
+
`cwd` (then `CLAUDE_PROJECT_DIR`, then the process working directory) until a
|
|
699
|
+
`.work/CONVENTIONS.md` is found; runs only if one exists, otherwise exits 0 with
|
|
700
|
+
no output.
|
|
701
|
+
|
|
702
|
+
**Effect:** updates prompt-context state under the host-provided plugin data
|
|
703
|
+
directory (`PLUGIN_DATA` / `CLAUDE_PLUGIN_DATA`), falling back to
|
|
704
|
+
`XDG_STATE_HOME`, `~/.local/state`, or the system temp directory only when no
|
|
705
|
+
plugin data directory is available. `SessionStart` resets the per-session epoch
|
|
706
|
+
and seen-set; `PostCompact` bumps the epoch so context re-injects after
|
|
707
|
+
compaction. This lets principles capsules fire once per session, and once again
|
|
708
|
+
after resume/compaction, without dirtying normal project worktrees. It does not
|
|
709
|
+
inject queue context at session start.
|
|
710
|
+
|
|
711
|
+
These events are also the **primary firing** of the `.agents/rules/`
|
|
712
|
+
rules-injection contract where the host accepts hook-specific context. They emit
|
|
713
|
+
the concatenated `.agents/rules/*.md` content as
|
|
714
|
+
`hookSpecificOutput.additionalContext` directly (after the epoch reset/bump),
|
|
715
|
+
unconditionally — no prompt to gate on. Codex is the exception for
|
|
716
|
+
`PostCompact`: Codex's `PostCompact` output schema does not allow
|
|
717
|
+
`hookSpecificOutput`, so that event only bumps the epoch and leaves context
|
|
718
|
+
reload to `SessionStart` with `source: compact`. This
|
|
719
|
+
keeps rules reloading at session start and after compaction, even during
|
|
720
|
+
auto-continuation with no user prompt, mirroring the legacy Claude-only
|
|
721
|
+
`.claude/rules/` force-load.
|
|
722
|
+
|
|
723
|
+
### `.agents/rules/` rules-injection contract
|
|
724
|
+
|
|
725
|
+
The hook force-loads every `.agents/rules/*.md` file into agent context so
|
|
726
|
+
producers (`convert`, `gate-patterns`, or the user) can drop content-agnostic
|
|
727
|
+
rule files there and have them reliably reach the agent in both Claude Code and
|
|
728
|
+
Codex. The contract:
|
|
729
|
+
|
|
730
|
+
- **Fires on:** `SessionStart` and host-supported `PostCompact` context output,
|
|
731
|
+
unconditionally. On Codex, `PostCompact` is side-effect-only because its
|
|
732
|
+
output schema does not allow `hookSpecificOutput`; `SessionStart` with
|
|
733
|
+
`source: compact` carries the context.
|
|
734
|
+
- **Content:** all `<root>/.agents/rules/*.md` files, sorted by name,
|
|
735
|
+
concatenated under a `## Project Rules (.agents/rules/)` heading.
|
|
736
|
+
- **Dedup:** per-session epoch + SHA-256 content hash. Rules inject exactly once
|
|
737
|
+
per `(epoch, content-hash)` — re-injecting after a `PostCompact` epoch bump or
|
|
738
|
+
when any `.agents/rules/*.md` file changes, but not otherwise.
|
|
739
|
+
- **Substrate gate:** only fires when `${CLAUDE_PROJECT_DIR}/.work/CONVENTIONS.md`
|
|
740
|
+
exists, like all the prompt-context hooks.
|
|
741
|
+
- **CONVENTIONS flag + byte cap:** `.work/CONVENTIONS.md` may set
|
|
742
|
+
`rules_context: on|off` (default `on`) to disable injection, and
|
|
743
|
+
`rules_context_max_bytes: <int>` (default 12000) to cap the emitted size. A
|
|
744
|
+
malformed CONVENTIONS keeps the enabled defaults so rules are never silently
|
|
745
|
+
dropped; oversized content is truncated with a "read the files for full
|
|
746
|
+
content" notice (the hash is computed over the untruncated content so any edit
|
|
747
|
+
re-injects).
|
|
748
|
+
|
|
749
|
+
### UserPromptSubmit hook
|
|
750
|
+
|
|
751
|
+
```json
|
|
752
|
+
{
|
|
753
|
+
"UserPromptSubmit": [
|
|
754
|
+
{
|
|
755
|
+
"hooks": [
|
|
756
|
+
{
|
|
757
|
+
"type": "command",
|
|
758
|
+
"command": "PYTHONDONTWRITEBYTECODE=1 python3 ${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/hooks/scripts/prompt-context.py",
|
|
759
|
+
"timeout": 10
|
|
760
|
+
}
|
|
761
|
+
]
|
|
762
|
+
}
|
|
763
|
+
]
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
**Activation:** runs only if a substrate exists. Principles capsules additionally
|
|
768
|
+
require an actionable agile-workflow move: queue operations, stage movement,
|
|
769
|
+
explicit workflow verbs, or a known item id.
|
|
770
|
+
|
|
771
|
+
**Effect:** returns `hookSpecificOutput.additionalContext` with:
|
|
772
|
+
- The smallest relevant principles capsule, at most once per session per
|
|
773
|
+
capsule: code design, dispatch economy, or advisory review.
|
|
774
|
+
|
|
775
|
+
It does not inject `.agents/rules/*.md` or queue snapshots at prompt time. Queue
|
|
776
|
+
state remains available through explicit `work-view`, `/aw`, or board commands.
|
|
777
|
+
|
|
778
|
+
### Pi hook parity adapter
|
|
779
|
+
|
|
780
|
+
Pi packages do not consume `hooks/hooks.json`. The Pi package therefore exposes
|
|
781
|
+
`plugins/agile-workflow/extensions/agile-workflow.ts` as a **Pi hook parity
|
|
782
|
+
adapter**. It maps Pi-native events onto the same deterministic hook scripts:
|
|
783
|
+
|
|
784
|
+
- `session_start` → `prompt-context.py` with `hook_event_name: SessionStart` for
|
|
785
|
+
epoch reset and work-view self-heal side effects.
|
|
786
|
+
- `session_compact` → `prompt-context.py` with `hook_event_name: PostCompact` for
|
|
787
|
+
epoch bump side effects.
|
|
788
|
+
- `before_agent_start` → `prompt-context.py` twice: synthetic
|
|
789
|
+
`hook_event_name: PiBeforeAgentStart` with `force_rules_context: true` to
|
|
790
|
+
append `.agents/rules/*.md` into Pi's rebuilt-per-turn system prompt, then
|
|
791
|
+
`hook_event_name: UserPromptSubmit` for the same prompt-gated principles
|
|
792
|
+
capsules Claude/Codex receive. Principles are returned as an injected Pi
|
|
793
|
+
message (`customType: agile-workflow-principles`) rather than hidden permanent
|
|
794
|
+
instructions, matching hook-specific context visibility.
|
|
795
|
+
- `tool_result` for mutating tools (`write`, `edit`, `apply_patch`) →
|
|
796
|
+
`substrate-maintainer.py` with `hook_event_name: PostToolUse`; validation
|
|
797
|
+
output is appended to the tool result so the next model step sees the same
|
|
798
|
+
substrate warnings.
|
|
799
|
+
|
|
800
|
+
This adapter is intentionally thin: `.agents/rules/`, `prompt-context.py`, and
|
|
801
|
+
`substrate-maintainer.py` remain the source of truth across Claude Code, Codex,
|
|
802
|
+
and Pi. Any change to hook behavior must update the adapter and the parity check
|
|
803
|
+
script in the same patch.
|
|
804
|
+
|
|
805
|
+
### PostToolUse hook
|
|
806
|
+
|
|
807
|
+
```json
|
|
808
|
+
{
|
|
809
|
+
"PostToolUse": [
|
|
810
|
+
{
|
|
811
|
+
"matcher": "Write|Edit|apply_patch",
|
|
812
|
+
"hooks": [
|
|
813
|
+
{
|
|
814
|
+
"type": "command",
|
|
815
|
+
"command": "PYTHONDONTWRITEBYTECODE=1 python3 ${PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}/hooks/scripts/substrate-maintainer.py",
|
|
816
|
+
"timeout": 5
|
|
817
|
+
}
|
|
818
|
+
]
|
|
819
|
+
}
|
|
820
|
+
]
|
|
821
|
+
}
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
**Activation:** runs only if the modified file path is under `.work/active/`,
|
|
825
|
+
`.work/backlog/`, `.work/releases/`, or `.work/archive/`. Otherwise exits 0.
|
|
826
|
+
|
|
827
|
+
**Effect:** auto-bumps the `updated:` frontmatter field of modified active or
|
|
828
|
+
backlog item files to today's date in **local time**. It then validates cheap
|
|
829
|
+
structural invariants for the touched item(s): required frontmatter, valid
|
|
830
|
+
kind/stage, filename/id match, duplicate id conflicts involving the touched
|
|
831
|
+
item, existing parents and dependencies, and `depends_on` cycles reachable from
|
|
832
|
+
the touched item. Validation issues are returned as
|
|
833
|
+
`hookSpecificOutput.additionalContext`; the hook does not invoke a model.
|
|
834
|
+
|
|
835
|
+
## Tooling requirements
|
|
836
|
+
|
|
837
|
+
### Required
|
|
838
|
+
|
|
839
|
+
- **bash** ≥ 4.0 — for the `work-view` bash fallback (`work-view.sh`) and the install helper (`install-work-view.sh`)
|
|
840
|
+
- **python3** — for plugin hook scripts
|
|
841
|
+
- **grep** — POSIX-compatible
|
|
842
|
+
- **git** — substrate's audit trail; `work-view`'s history queries call `git log`
|
|
843
|
+
|
|
844
|
+
### Optional (auto-detected, falls back gracefully)
|
|
845
|
+
|
|
846
|
+
- **yq** — cleaner YAML parsing in `work-view` (faster on > 100 items)
|
|
847
|
+
- **jq** — JSON manipulation in some hook scripts
|
|
848
|
+
- **gh** — required only if the project's release mapping is `branch-held`
|
|
849
|
+
(used by `release-deploy` to merge bound PRs)
|
|
850
|
+
|
|
851
|
+
### Not required
|
|
852
|
+
|
|
853
|
+
- No Node, Python, Rust, or other language toolchains
|
|
854
|
+
- No MCP server
|
|
855
|
+
- No external services or auth
|