acstack 0.0.0-stage → 0.47.1
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 +19 -0
- package/LICENSE +21 -0
- package/README.md +389 -2
- package/THIRD_PARTY_NOTICES +14 -0
- package/TROUBLESHOOTING.md +225 -0
- package/agents/codex/frontend-verifier.toml +352 -0
- package/agents/codex/task-checker.toml +345 -0
- package/agents/codex/task-executor.toml +157 -0
- package/agents/codex/test-writer.toml +149 -0
- package/agents/frontend-verifier.md +351 -0
- package/agents/task-checker.md +344 -0
- package/agents/task-executor.md +156 -0
- package/agents/test-writer.md +148 -0
- package/assets/playwriter-bridge/build-launcher.ps1 +32 -0
- package/assets/playwriter-bridge/doctor.ps1 +450 -0
- package/assets/playwriter-bridge/launcher-src.cs +131 -0
- package/assets/playwriter-bridge/opener.js +330 -0
- package/assets/playwriter-bridge/opener.ps1 +63 -0
- package/assets/playwriter-bridge/register-tasks.ps1 +328 -0
- package/assets/playwriter-bridge/relay.ps1 +50 -0
- package/assets/playwriter-bridge/stop.ps1 +125 -0
- package/assets/playwriter-bridge/sync.ps1 +271 -0
- package/assets/playwriter-bridge/tunnel.ps1 +325 -0
- package/assets/playwriter-bridge/vm-free-port.sh +166 -0
- package/assets/terminal-workspace/client-keybindings.md +87 -0
- package/assets/terminal-workspace/config.example.yaml +334 -0
- package/assets/terminal-workspace/setup.sh +4404 -0
- package/cli/README.md +47 -0
- package/cli/bin/acstack.js +3 -0
- package/cli/dist/index.js +25984 -0
- package/cli/dist/index.js.map +7 -0
- package/cli/package.json +59 -0
- package/docs/adr/0001-ste-writing-standard.md +16 -0
- package/docs/adr/0002-version-gate-not-auto-bump.md +35 -0
- package/docs/adr/0003-handoff-ack-command.md +19 -0
- package/docs/adr/0004-dev-setup-per-host.md +13 -0
- package/docs/adr/0005-two-orchestrators-per-host.md +25 -0
- package/docs/adr/0006-document-opener-service.md +89 -0
- package/docs/adr/0007-lead-check-reads-the-transcript.md +87 -0
- package/docs/adr/0008-cli-audits-skill-interviews.md +37 -0
- package/docs/adr/0009-verify-the-write-not-the-writer.md +51 -0
- package/docs/adr/0010-promote-dev-to-main-by-fast-forward.md +115 -0
- package/docs/adr/0011-node-header-is-the-edge-encoding.md +20 -0
- package/docs/adr/0012-node-kind-is-a-closed-set-of-five.md +31 -0
- package/docs/adr/0013-the-diagram-renderer-is-pure.md +23 -0
- package/docs/adr/0014-reading-a-node-hides-its-generated-diagram.md +29 -0
- package/docs/adr/0015-a-node-id-links-to-its-issue-through-an-anchor.md +37 -0
- package/docs/adr/0016-the-map-root-carries-no-status-of-its-own.md +21 -0
- package/docs/adr/0017-call-impeccable-copy-only-its-questions.md +13 -0
- package/docs/adr/index.md +17 -0
- package/docs/config-reference.md +572 -0
- package/docs/dev-setups.md +164 -0
- package/docs/migrate-0.8.md +28 -0
- package/docs/playwriter-bridge-windows.md +15 -0
- package/docs/terminal-workspace-keys.md +137 -0
- package/docs/terminal-workspace.md +1780 -0
- package/docs/workflows.md +309 -0
- package/hooks/ac-writing-style-reminder.sh +86 -0
- package/hooks/context-pressure.sh +583 -0
- package/hooks/hooks.json +50 -0
- package/hooks/session-start-handoff.sh +165 -0
- package/hooks/session-start.sh +214 -0
- package/orchestrator/AGENTS.md +532 -0
- package/output-styles/ac-writing-style.md +286 -0
- package/package.json +50 -4
- package/pi/agents/frontend-verifier.md +357 -0
- package/pi/agents/task-checker.md +348 -0
- package/pi/agents/task-executor.md +160 -0
- package/pi/agents/test-writer.md +154 -0
- package/pi/extension.ts +723 -0
- package/profiles/fullstack-python.yaml +29 -0
- package/profiles/node-typescript.yaml +23 -0
- package/profiles/python.yaml +24 -0
- package/skills/archive/SKILL.md +160 -0
- package/skills/bootstrap/SKILL.md +109 -0
- package/skills/bridge/HANDOFF.md +93 -0
- package/skills/bridge/SKILL-VM.md +292 -0
- package/skills/bridge/SKILL-WINDOWS.md +526 -0
- package/skills/bridge/SKILL.md +121 -0
- package/skills/browser-verify/SKILL.md +229 -0
- package/skills/code-review/SKILL.md +44 -0
- package/skills/commit/SKILL.md +106 -0
- package/skills/compact-and-continue/SKILL.md +241 -0
- package/skills/explore/SKILL.md +149 -0
- package/skills/grilling/SKILL.md +134 -0
- package/skills/handoff/SKILL.md +250 -0
- package/skills/handoff/launch-herdr.md +197 -0
- package/skills/handoff/launch-without-herdr.md +30 -0
- package/skills/handoff/lead-check.md +59 -0
- package/skills/handoff/outcomes.md +162 -0
- package/skills/handoff/running-agent.md +50 -0
- package/skills/handoff/watch.md +115 -0
- package/skills/host/SKILL.md +247 -0
- package/skills/host/detect-host.sh +297 -0
- package/skills/host/herdr.md +79 -0
- package/skills/host/install-herdr-block.sh +467 -0
- package/skills/host/install-orca.sh +512 -0
- package/skills/host/notes.md +97 -0
- package/skills/host/orca.md +160 -0
- package/skills/host/questions.md +163 -0
- package/skills/host/report.md +42 -0
- package/skills/implement/SKILL.md +230 -0
- package/skills/implement/decision-log.md +62 -0
- package/skills/implement/design-pass.md +32 -0
- package/skills/implement/relaxed-tdd.md +28 -0
- package/skills/map/SKILL.md +250 -0
- package/skills/map/frontend.md +227 -0
- package/skills/map/trackers/files.md +74 -0
- package/skills/map/trackers/github.md +180 -0
- package/skills/map/visuals.md +387 -0
- package/skills/new-worktree/SKILL.md +155 -0
- package/skills/new-worktree/detect-orchestrator.sh +328 -0
- package/skills/new-worktree/detect-orchestrator.test.sh +894 -0
- package/skills/new-worktree/herdr.md +84 -0
- package/skills/new-worktree/orca.md +101 -0
- package/skills/pre-commit-review/SKILL.md +242 -0
- package/skills/pre-commit-review/auto-fix.md +19 -0
- package/skills/pre-commit-review/interactive.md +35 -0
- package/skills/quick-fix/SKILL.md +125 -0
- package/skills/record-context/SKILL.md +106 -0
- package/skills/setup/SKILL.md +250 -0
- package/skills/setup/browser.md +123 -0
- package/skills/setup/design-review.md +97 -0
- package/skills/setup/first-run.md +114 -0
- package/skills/setup/report.md +68 -0
- package/skills/setup/row-fixes.md +196 -0
- package/skills/setup/terminal-workspace.md +153 -0
- package/skills/sync/SKILL.md +171 -0
- package/skills/teardown-worktree/SKILL.md +245 -0
- package/skills/teardown-worktree/detector.md +39 -0
- package/skills/teardown-worktree/herdr.md +113 -0
- package/skills/teardown-worktree/orca.md +61 -0
- package/skills/terminal-workspace/SKILL.md +249 -0
- package/skills/terminal-workspace/components.md +36 -0
- package/skills/terminal-workspace/config-choices.md +69 -0
- package/skills/terminal-workspace/emulator-keys.md +48 -0
- package/skills/terminal-workspace/headless-clipboard.md +175 -0
- package/skills/terminal-workspace/turn-off-and-update.md +104 -0
- package/skills/test-conventions/SKILL.md +59 -0
- package/skills/visual-docs/SKILL.md +246 -0
- package/skills/writing/SKILL.md +231 -0
- package/skills/writing/examples.md +153 -0
- package/skills/writing/vocabulary.md +96 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# ACStack workflows
|
|
2
|
+
|
|
3
|
+
*Every request ends the same way, with your specs updated from the diff. What changes is how many questions you settle first.*
|
|
4
|
+
|
|
5
|
+
ACStack routes a request down one of three paths. Every path ends at a commit that updates your specs.
|
|
6
|
+
|
|
7
|
+
- **The path depends on what is in your way**: nothing, a bug, or an unanswered question
|
|
8
|
+
- **A clear request goes straight to the four TDD agents** (see section 4)
|
|
9
|
+
- **A bug goes to root-cause analysis first** (see section 2)
|
|
10
|
+
- **A request with open questions becomes a to-do graph** you work through (see section 1)
|
|
11
|
+
- **The rest of this document** is the detail behind one box of the diagram below
|
|
12
|
+
|
|
13
|
+
```mermaid
|
|
14
|
+
flowchart TD
|
|
15
|
+
R["A request<br/>(feature, bug, refactor)"] --> Q{"What stands<br/>in the way?"}
|
|
16
|
+
Q -->|"nothing – the way is clear"| I["Implement<br/>(implement)"]
|
|
17
|
+
Q -->|"it is broken"| F["Root-cause fix<br/>(quick-fix)"]
|
|
18
|
+
Q -->|"open decisions"| M["Map<br/>(chart, then work the frontier)"]
|
|
19
|
+
M -->|"work nodes"| I
|
|
20
|
+
I --> T["Build under TDD<br/>(4-phase pipeline)"]
|
|
21
|
+
F --> C["Commit<br/>(acstack:commit)"]
|
|
22
|
+
T --> C
|
|
23
|
+
C --> Y["Sync specs from the diff<br/>(domain-map.yaml)"]
|
|
24
|
+
Y --> L[("Living specs<br/>acstack/specs/")]
|
|
25
|
+
M -->|"every question answered"| A["Archive<br/>(check the decisions landed,<br/>then delete the nodes)"]
|
|
26
|
+
A --> L
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Step in the diagram | Detail |
|
|
30
|
+
| --------------------- | --------- |
|
|
31
|
+
| Map, the to-do graph | section 1 |
|
|
32
|
+
| Implement | section 2 |
|
|
33
|
+
| Asking and recording | section 3 |
|
|
34
|
+
| Build under TDD | section 4 |
|
|
35
|
+
| Commit **and** sync | section 5 |
|
|
36
|
+
| Archive | section 6 |
|
|
37
|
+
| Living specs | section 7 |
|
|
38
|
+
|
|
39
|
+
The request box is a terminal, not a step. Section 5 covers two boxes because one command does both.
|
|
40
|
+
|
|
41
|
+
Section 8 describes this document. No box holds it.
|
|
42
|
+
|
|
43
|
+
## 1. The map, meaning the to-do graph
|
|
44
|
+
|
|
45
|
+
*One kind of record replaces the fixed proposal, design, and tasks pipeline earlier versions used. Nothing stores the map itself. It is queries over the nodes.*
|
|
46
|
+
|
|
47
|
+
- **A map** is a set of small records called nodes
|
|
48
|
+
- **A node** is one question to settle or one piece of work to do
|
|
49
|
+
- `/acstack:map` is the entry point for planned work
|
|
50
|
+
- It charts a map when none exists, opening with a grill, a round of questions that fixes the destination and surfaces the fog
|
|
51
|
+
- The destination is what finished looks like
|
|
52
|
+
- It works the frontier instead when a map exists
|
|
53
|
+
- ACStack never sorts requests into sizes
|
|
54
|
+
- Nothing picks a different process for a big one
|
|
55
|
+
- There is one path, and only the node count changes
|
|
56
|
+
|
|
57
|
+
A node carries one of five statuses.
|
|
58
|
+
|
|
59
|
+
| Status | What it means |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `fog` | nobody can state it precisely yet |
|
|
62
|
+
| `open` | ready to settle |
|
|
63
|
+
| `claimed` | someone is working it |
|
|
64
|
+
| `resolved` | settled |
|
|
65
|
+
| `out-of-scope` | deliberately dropped |
|
|
66
|
+
|
|
67
|
+
A node carries a `kind`, a `label`, and a `mode` too. Two link types connect the nodes.
|
|
68
|
+
|
|
69
|
+
- **`kind`** is one of five: `destination`, `notes`, `decision`, `research`, `work`
|
|
70
|
+
- It picks the node's shape in a diagram, never how the map routes it
|
|
71
|
+
- **`label`** is the node's short name for a diagram, at most four words
|
|
72
|
+
- **`mode`** says who settles the node: `hitl` for a human, `afk` for an agent alone
|
|
73
|
+
- **`answers`** names the one node whose answer raised this one
|
|
74
|
+
- The parent links form a tree, which gives you a reading order
|
|
75
|
+
- An agent packages a handoff by walking that tree
|
|
76
|
+
- **`blocked-by`** names any number of nodes that must resolve before this one starts
|
|
77
|
+
- The blocking edges form a directed acyclic graph, meaning the edges never loop back
|
|
78
|
+
- These edges tell you what you can work right now
|
|
79
|
+
|
|
80
|
+
Every node body carries a diagram, two at most. A childless `notes` node is the one exception.
|
|
81
|
+
|
|
82
|
+
- A node with children draws its own subtree, rendered by `acstack node diagram`
|
|
83
|
+
- Every other node draws what its question or its change touches, drawn by the agent
|
|
84
|
+
- A second mermaid fence under each diagram is its legend, showing only the cues that diagram uses
|
|
85
|
+
- On GitHub every node id in a diagram links to its issue
|
|
86
|
+
- `skills/map/visuals.md` holds the rules
|
|
87
|
+
|
|
88
|
+
ACStack works depth out from `answers`. Nobody declares it. The map itself is five queries.
|
|
89
|
+
|
|
90
|
+
| The question | The query |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| Where are we going? | the root node |
|
|
93
|
+
| What have we decided? | the `resolved` nodes, in the order the decisions happened |
|
|
94
|
+
| What can we work now? | the `open` nodes with no unresolved blockers |
|
|
95
|
+
| What is not yet specified? | the `fog` nodes |
|
|
96
|
+
| What did we drop? | the `out-of-scope` nodes |
|
|
97
|
+
|
|
98
|
+
Nodes live in a tracker. That is the storage layer, and you can swap it.
|
|
99
|
+
|
|
100
|
+
- A tracker provides four operations and nothing more: create, read, update, list
|
|
101
|
+
- GitHub issues are the default
|
|
102
|
+
- The first line of every issue body carries all of that node's edges
|
|
103
|
+
- One list call therefore returns the whole graph
|
|
104
|
+
- A sub-issue and a dependency mirror those edges, so GitHub's own interface draws the map
|
|
105
|
+
- Files under `acstack/maps/<name>/` are the fallback
|
|
106
|
+
- Frontmatter holds the edges, so those files carry no header line
|
|
107
|
+
- Frontier, claim, and resolve build on those four operations
|
|
108
|
+
- No tracker implements them itself
|
|
109
|
+
|
|
110
|
+
**Build no more process than the job needs.**
|
|
111
|
+
|
|
112
|
+
- You create a map only when the fog will outlive the session
|
|
113
|
+
- You settle one question in conversation
|
|
114
|
+
- That leaves an architecture decision record (ADR), not a map
|
|
115
|
+
|
|
116
|
+
## 2. Implement
|
|
117
|
+
|
|
118
|
+
*A unit of work carries its own size. One node is a quick change.*
|
|
119
|
+
|
|
120
|
+
*Forty is a long effort. Nothing declares which.*
|
|
121
|
+
|
|
122
|
+
- `/acstack:implement` claims `afk` work nodes from the frontier when a map exists
|
|
123
|
+
- It treats the request itself as the work item when none does
|
|
124
|
+
- Either way, parallel explorer subagents run over the relevant code before anyone writes anything
|
|
125
|
+
- The command resolves paths at claim time
|
|
126
|
+
- A node describes behaviour
|
|
127
|
+
- It can sit unstarted for weeks
|
|
128
|
+
- The test-driven development (TDD) pipeline of section 4 runs to completion inside each claim
|
|
129
|
+
- A node only ever moves `open -> claimed -> resolved`
|
|
130
|
+
- The agent releases the claim when work stalls
|
|
131
|
+
- The node is plainly open again
|
|
132
|
+
- Progress is a query, not a checkbox file
|
|
133
|
+
- Resuming never means re-reading an effort end to end
|
|
134
|
+
|
|
135
|
+
`/acstack:quick-fix` stays separate. A broken thing is a different problem from an unanswered question.
|
|
136
|
+
|
|
137
|
+
- A bug has a root cause to find, not a decision to settle
|
|
138
|
+
- `/acstack:quick-fix` therefore never creates a node
|
|
139
|
+
|
|
140
|
+
## 3. Asking the questions, and writing the answers down
|
|
141
|
+
|
|
142
|
+
*Three skills the agent reaches for itself, without you typing a command, carry the interviewing, the recording, and the writing.*
|
|
143
|
+
|
|
144
|
+
- **`grilling`** is the interview
|
|
145
|
+
- It works through your decisions one round at a time
|
|
146
|
+
- A round asks the whole frontier, every question whose prerequisites have resolved, numbered, each with a recommended answer
|
|
147
|
+
- It then recomputes the frontier and repeats
|
|
148
|
+
- Facts are the agent's job, never yours
|
|
149
|
+
- It sends any question a look at the environment would answer to a subagent instead
|
|
150
|
+
- Presentation follows `workflow.grilling.questions`, the host's question tool by default
|
|
151
|
+
- It falls back to inline prose past 4 questions, or for a question with no discrete options
|
|
152
|
+
- There is no question cap
|
|
153
|
+
- The set of answerable questions bounds itself
|
|
154
|
+
- **`record-context`** fires when a decision lands
|
|
155
|
+
- It writes an ADR under `docs/adr/` only when the decision is hard to reverse *and* surprising *and* a real trade-off
|
|
156
|
+
- It writes a glossary term when a term got settled, in root `CONTEXT.md` for cross-domain vocabulary
|
|
157
|
+
- It writes a domain term in `acstack/specs/<domain>/CONTEXT.md` instead
|
|
158
|
+
- It can write both, or neither
|
|
159
|
+
- ACStack generates the ADR index from the files
|
|
160
|
+
- Nobody hand-edits it
|
|
161
|
+
- **`writing`** holds the standard every durable artifact follows: node answers, ADRs, glossary entries, specs and handoffs
|
|
162
|
+
- The words to avoid live in `skills/writing/vocabulary.md`
|
|
163
|
+
|
|
164
|
+
## 4. Build under TDD
|
|
165
|
+
|
|
166
|
+
*Four agents run in order. The rule that does the work: the test-writer never sees the implementation.*
|
|
167
|
+
|
|
168
|
+
```mermaid
|
|
169
|
+
flowchart LR
|
|
170
|
+
subgraph P["Order set by workflow.tdd.strict"]
|
|
171
|
+
direction LR
|
|
172
|
+
W["test-writer<br/>(requirements only)"]
|
|
173
|
+
E["task-executor<br/>(cannot edit tests)"]
|
|
174
|
+
W -.->|"strict: tests first"| E
|
|
175
|
+
E -.->|"relaxed: code first"| W
|
|
176
|
+
end
|
|
177
|
+
P --> Fm["format<br/>(commands.format)"]
|
|
178
|
+
Fm --> K["task-checker<br/>(PASS / FAIL)"]
|
|
179
|
+
K -->|FAIL| E
|
|
180
|
+
K -->|PASS| V["frontend-verifier<br/>(real browser)"]
|
|
181
|
+
V -->|FAIL| E
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The separation is the mechanism, not a formality.
|
|
185
|
+
|
|
186
|
+
- **test-writer** sees requirements and acceptance criteria, never the implementation plan
|
|
187
|
+
- Tests then encode what should happen
|
|
188
|
+
- The implementation cannot shape them
|
|
189
|
+
- **task-executor** receives the failing tests and cannot modify anything in the test directory
|
|
190
|
+
- It has to make the specification pass instead of editing it
|
|
191
|
+
- **task-checker** is a binary gate
|
|
192
|
+
- It runs the task's tests, then the full suite for regressions
|
|
193
|
+
- It checks the test count against `.test-baseline` and audits mocks for circular assertions
|
|
194
|
+
- It confirms the executor left the tests alone
|
|
195
|
+
- **frontend-verifier** drives a real browser over the Chrome DevTools Protocol (CDP)
|
|
196
|
+
- It takes before and after screenshots
|
|
197
|
+
- It reports on that evidence
|
|
198
|
+
|
|
199
|
+
Which phases run, and in what order:
|
|
200
|
+
|
|
201
|
+
- A FAIL routes back to the executor with the reason
|
|
202
|
+
- Phases 1 and 4 are conditional
|
|
203
|
+
- You can skip test-writer for a config or docs change with no testable behaviour
|
|
204
|
+
- The frontend-verifier runs under three conditions: `acstack/project.yaml` configures a frontend, frontend files changed, and verification is on
|
|
205
|
+
- `workflow.tdd.strict: false` reverses phase 1 and phase 2
|
|
206
|
+
- The order becomes task-executor, then test-writer, then task-checker
|
|
207
|
+
- It drops no phase
|
|
208
|
+
- All three agents run
|
|
209
|
+
- Relaxed TDD means nobody writes the tests first, never that the work goes unverified
|
|
210
|
+
|
|
211
|
+
Relaxed weakens one wall, the one this section calls the important one.
|
|
212
|
+
|
|
213
|
+
- Under `false` the test-writer works beside an implementation it must not read, instead of one that does not exist yet
|
|
214
|
+
- Its independence then rests on its instructions rather than on context isolation
|
|
215
|
+
- That is the cost of relaxed TDD
|
|
216
|
+
- The checker pays for it too
|
|
217
|
+
- No run can show the new tests failing without the implementation
|
|
218
|
+
- It holds them to existing and passing instead
|
|
219
|
+
|
|
220
|
+
The format step sits immediately before phase 3.
|
|
221
|
+
|
|
222
|
+
- The pipeline runs `commands.format` over the files the work touched
|
|
223
|
+
- Under relaxed that puts the format step after the test-writer
|
|
224
|
+
- The new tests get formatted too
|
|
225
|
+
- A project whose `commands.format` is `null` gets no format step
|
|
226
|
+
- A non-zero exit gets reported
|
|
227
|
+
- It never counts as a failed implementation
|
|
228
|
+
|
|
229
|
+
## 5. Commit and sync specs
|
|
230
|
+
|
|
231
|
+
*Spec sync runs on every commit on every path. It reads the diff. Your specs therefore describe what you built, not what you planned.*
|
|
232
|
+
|
|
233
|
+
`/acstack:commit` groups changes into MECE commits. MECE means mutually exclusive and collectively exhaustive: no change appears twice, and no change goes missing. Before writing them it does five things.
|
|
234
|
+
|
|
235
|
+
1. Reads `acstack/domain-map.yaml` to map each changed file to a domain.
|
|
236
|
+
2. Works out what the diff adds, modifies or removes, for each affected domain with a `spec.md`.
|
|
237
|
+
3. Writes those entries into the domain's spec and stages them in the same commit.
|
|
238
|
+
4. Flags source files that match no domain.
|
|
239
|
+
5. Checks the glossaries.
|
|
240
|
+
|
|
241
|
+
On the glossary check:
|
|
242
|
+
|
|
243
|
+
- It says so when the diff renames or deletes an identifier matching a glossary term
|
|
244
|
+
- It never edits the glossary
|
|
245
|
+
- For specs the code wins
|
|
246
|
+
- For the glossary the human wins
|
|
247
|
+
|
|
248
|
+
Four cases stop sync.
|
|
249
|
+
|
|
250
|
+
- `workflow.spec_sync` set to `false`
|
|
251
|
+
- no domain map
|
|
252
|
+
- no file matching a domain
|
|
253
|
+
- a change that touches only docs and config
|
|
254
|
+
|
|
255
|
+
**Without `acstack/domain-map.yaml` this step does nothing, silently.**
|
|
256
|
+
|
|
257
|
+
- `/acstack:setup` generates that file
|
|
258
|
+
- `acstack config check` reports it as missing on a project set up before that existed
|
|
259
|
+
|
|
260
|
+
## 6. Archive
|
|
261
|
+
|
|
262
|
+
*A map is working state, not a record you keep. Archive checks the decisions reached your specs, your decision notes, and your glossary, then deletes the nodes.*
|
|
263
|
+
|
|
264
|
+
- `/acstack:archive` checks for a cleared map: empty frontier, no fog, no claims
|
|
265
|
+
- It spot-checks that the specs, the decision notes and the glossary captured what the effort settled
|
|
266
|
+
- It then disposes of the nodes
|
|
267
|
+
- It deletes them by default
|
|
268
|
+
- It moves them to `acstack/archive/<date>-<name>/nodes/` when `workflow.maps.persist` is `true`
|
|
269
|
+
- Keeping nodes is off by default
|
|
270
|
+
- A kept map is a second copy of every decision
|
|
271
|
+
- The two drift apart
|
|
272
|
+
- On the GitHub tracker there is nothing to dispose
|
|
273
|
+
- A closed issue is already the archive
|
|
274
|
+
- Archive runs either way
|
|
275
|
+
- The user types `/acstack:archive`
|
|
276
|
+
- `/acstack:map` hands off to it once every node resolves
|
|
277
|
+
- The disposal step then asks you first
|
|
278
|
+
- Legacy `acstack/changes/` directories from the pre-map workflow still archive the old way
|
|
279
|
+
- An upgrade therefore never strands work
|
|
280
|
+
|
|
281
|
+
## 7. Living specs
|
|
282
|
+
|
|
283
|
+
*What the project keeps. ACStack deletes a map once every question resolves. `acstack/specs/` outlives it.*
|
|
284
|
+
|
|
285
|
+
- Specs live at `acstack/specs/<domain>/spec.md`, organised by the domains in `domain-map.yaml`
|
|
286
|
+
- Each spec states numbered functional requirements (`FR-NNN`) in Given, When, Then form
|
|
287
|
+
- They are cumulative
|
|
288
|
+
- They describe only what the code already does
|
|
289
|
+
- A roadmap item in a living spec is a bug in the spec
|
|
290
|
+
|
|
291
|
+
Two rules keep them honest.
|
|
292
|
+
|
|
293
|
+
- **Two writers, one target**
|
|
294
|
+
- Commit-time sync handles incremental change
|
|
295
|
+
- Archive verifies a completed map left nothing behind
|
|
296
|
+
- Both converge on the same files
|
|
297
|
+
- **Fix it when you see it**
|
|
298
|
+
- Any agent that finds a spec contradicting the code corrects the spec immediately
|
|
299
|
+
- It rewrites wrong behaviour, appends missing requirements, and deletes stale references
|
|
300
|
+
|
|
301
|
+
`/acstack:bootstrap` generates the first set from an existing codebase. A project never starts from an empty directory.
|
|
302
|
+
|
|
303
|
+
## 8. Where the design record lives
|
|
304
|
+
|
|
305
|
+
*This section describes the document, not the system. No diagram box holds it.*
|
|
306
|
+
|
|
307
|
+
- The reasoning behind this design lives in the issues labelled `wayfinder` on this repository
|
|
308
|
+
- That covers why one node type, why four tracker operations, and why no tiers
|
|
309
|
+
- Each issue is one decision with the reasoning that produced it
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Per-turn reminder for the ac-writing-style output style.
|
|
3
|
+
#
|
|
4
|
+
# Built-in styles (Concise, Proactive) carry a `turnReminder` field that the CLI
|
|
5
|
+
# re-injects every turn. A file-based output style cannot set one: the
|
|
6
|
+
# frontmatter schema accepts only name, description, keep-coding-instructions
|
|
7
|
+
# and force-for-plugin. This hook supplies the equivalent.
|
|
8
|
+
#
|
|
9
|
+
# The reminder text is EXTRACTED from output-styles/ac-writing-style.md on every
|
|
10
|
+
# turn, never stored. A hand-typed copy drifts from the style the moment either
|
|
11
|
+
# one changes, and that is exactly what happened to the first version of this
|
|
12
|
+
# hook. Two parts come out of the file:
|
|
13
|
+
#
|
|
14
|
+
# 1. "## Who you are", top-level lines only, which is the persona
|
|
15
|
+
# 2. "## Before you send", in full, which is the checklist
|
|
16
|
+
#
|
|
17
|
+
# Output is JSON only, with suppressOutput true, so nothing reaches the user's
|
|
18
|
+
# transcript. The hook stays silent unless the active output style is this one.
|
|
19
|
+
|
|
20
|
+
set -u
|
|
21
|
+
|
|
22
|
+
# Drain stdin so the CLI never sees a broken pipe.
|
|
23
|
+
{ command -p cat 2>/dev/null || cat; } >/dev/null 2>&1 || :
|
|
24
|
+
|
|
25
|
+
silent() { printf '{}\n'; exit 0; }
|
|
26
|
+
|
|
27
|
+
# --------------------------------------------------------------------------
|
|
28
|
+
# Gate: only speak when ac-writing-style is the active output style.
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
read_style() {
|
|
32
|
+
[ -f "$1" ] || return 1
|
|
33
|
+
sed -n 's/.*"outputStyle"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$1" 2>/dev/null | head -1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Project settings win over user settings, the same order the CLI resolves them.
|
|
37
|
+
style=$(read_style ".claude/settings.local.json" || true)
|
|
38
|
+
[ -n "${style:-}" ] || style=$(read_style ".claude/settings.json" || true)
|
|
39
|
+
[ -n "${style:-}" ] || style=$(read_style "${HOME}/.claude/settings.json" || true)
|
|
40
|
+
|
|
41
|
+
case "${style:-}" in
|
|
42
|
+
*ac-writing-style|*ac-agentic-coding-writing) ;;
|
|
43
|
+
*) silent ;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
46
|
+
# --------------------------------------------------------------------------
|
|
47
|
+
# Locate the output style the reminder derives from.
|
|
48
|
+
# --------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
root="${CLAUDE_PLUGIN_ROOT:-}"
|
|
51
|
+
[ -n "$root" ] || root="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
|
|
52
|
+
style_file="${root}/output-styles/ac-writing-style.md"
|
|
53
|
+
|
|
54
|
+
[ -r "$style_file" ] || silent
|
|
55
|
+
|
|
56
|
+
# --------------------------------------------------------------------------
|
|
57
|
+
# Extract, escape, and emit.
|
|
58
|
+
# --------------------------------------------------------------------------
|
|
59
|
+
|
|
60
|
+
awk '
|
|
61
|
+
function esc(s) {
|
|
62
|
+
gsub(/\\/, "\\\\", s)
|
|
63
|
+
gsub(/"/, "\\\"", s)
|
|
64
|
+
gsub(/\t/, "\\t", s)
|
|
65
|
+
return s
|
|
66
|
+
}
|
|
67
|
+
function emit(s) { out = out esc(s) "\\n" }
|
|
68
|
+
|
|
69
|
+
# "## Who you are" holds the persona. Keep its top-level lines: the italic
|
|
70
|
+
# opener, the bold rules, and the unindented bullets. Drop the sub-bullets,
|
|
71
|
+
# because the reminder names each rule and the file itself argues for it.
|
|
72
|
+
/^## Who you are$/ { persona = 1; next }
|
|
73
|
+
/^## Shape: Minto pyramid$/ { persona = 0 }
|
|
74
|
+
persona && /^### / { emit(""); emit($0); next }
|
|
75
|
+
persona && /^[*-]/ { emit($0); next }
|
|
76
|
+
persona && /^\*\*/ { emit($0); next }
|
|
77
|
+
|
|
78
|
+
# "## Before you send" is the checklist, and it runs to the end of the file.
|
|
79
|
+
/^## Before you send$/ { checklist = 1; emit(""); emit($0); next }
|
|
80
|
+
checklist { emit($0); next }
|
|
81
|
+
|
|
82
|
+
END {
|
|
83
|
+
if (out == "") exit 1
|
|
84
|
+
printf "{\"suppressOutput\": true, \"hookSpecificOutput\": {\"hookEventName\": \"UserPromptSubmit\", \"additionalContext\": \"ac-writing-style reminder\\n\\n%s\"}}\n", out
|
|
85
|
+
}
|
|
86
|
+
' "$style_file" || silent
|