acstack 0.50.4 → 0.51.0

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.
Files changed (111) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +14 -7
  3. package/agents/codex/frontend-verifier.toml +89 -6
  4. package/agents/codex/task-checker.toml +83 -2
  5. package/agents/codex/task-executor.toml +83 -1
  6. package/agents/codex/test-writer.toml +77 -1
  7. package/agents/frontend-verifier.md +13 -6
  8. package/agents/task-checker.md +7 -2
  9. package/agents/task-executor.md +7 -1
  10. package/agents/test-writer.md +1 -1
  11. package/assets/terminal-workspace/config.example.yaml +1 -1
  12. package/assets/terminal-workspace/helpers/acstack-md +12 -4
  13. package/assets/terminal-workspace/helpers/acstack-open +10 -2
  14. package/cli/dist/index.js +10142 -9369
  15. package/cli/dist/index.js.map +4 -4
  16. package/cli/package.json +1 -1
  17. package/docs/config-reference.md +113 -14
  18. package/docs/dev-setups.md +4 -4
  19. package/docs/terminal-workspace.md +1 -1
  20. package/docs/workflows.md +22 -16
  21. package/examples/design-doc/acstack/README.md +273 -0
  22. package/examples/design-doc/acstack/acstack.yaml +4 -0
  23. package/examples/design-doc/acstack/cli.yaml +5 -0
  24. package/examples/design-doc/acstack/design.yaml +39 -0
  25. package/examples/design-doc/acstack/github.yaml +12 -0
  26. package/examples/design-doc/acstack/host.yaml +14 -0
  27. package/examples/design-doc/acstack/journey.md +85 -0
  28. package/examples/design-doc/acstack/publication.md +16 -0
  29. package/examples/design-doc/acstack/review-runtime.yaml +24 -0
  30. package/examples/design-doc/acstack/skills.yaml +22 -0
  31. package/examples/design-doc/acstack/store.yaml +11 -0
  32. package/examples/design-doc/acstack/user.yaml +15 -0
  33. package/examples/design-doc/acstack/viewer.yaml +13 -0
  34. package/hooks/ac-writing-style-reminder.sh +7 -18
  35. package/hooks/communication-standard.mjs +17 -0
  36. package/hooks/communication-standard.sh +6 -0
  37. package/hooks/context-pressure.sh +2 -2
  38. package/hooks/hooks.json +18 -0
  39. package/hooks/lib/communication-standard.mjs +16 -0
  40. package/hooks/project-data.sh +38 -0
  41. package/hooks/session-start-handoff.sh +21 -7
  42. package/hooks/session-start.sh +9 -2
  43. package/orchestrator/AGENTS.md +25 -14
  44. package/output-styles/ac-writing-style.md +75 -276
  45. package/package.json +2 -1
  46. package/pi/agents/frontend-verifier.md +89 -6
  47. package/pi/agents/task-checker.md +83 -2
  48. package/pi/agents/task-executor.md +83 -1
  49. package/pi/agents/test-writer.md +77 -1
  50. package/pi/extension.ts +70 -12
  51. package/profiles/fullstack-python.yaml +1 -1
  52. package/profiles/node-typescript.yaml +1 -1
  53. package/profiles/python.yaml +1 -1
  54. package/skills/archive/SKILL.md +53 -36
  55. package/skills/bootstrap/SKILL.md +6 -6
  56. package/skills/bridge/SKILL-VM.md +11 -2
  57. package/skills/bridge/SKILL-WINDOWS.md +3 -3
  58. package/skills/browser-verify/SKILL.md +14 -5
  59. package/skills/code-review/SKILL.md +8 -2
  60. package/skills/commit/SKILL.md +7 -6
  61. package/skills/compact-and-continue/SKILL.md +9 -8
  62. package/skills/design-doc/SKILL.md +235 -0
  63. package/skills/explore/SKILL.md +1 -1
  64. package/skills/grilling/SKILL.md +4 -4
  65. package/skills/handoff/SKILL.md +4 -4
  66. package/skills/host/SKILL.md +1 -1
  67. package/skills/host/detect-host.sh +2 -2
  68. package/skills/host/notes.md +2 -2
  69. package/skills/host/questions.md +1 -1
  70. package/skills/implement/SKILL.md +20 -13
  71. package/skills/implement/decision-log.md +9 -8
  72. package/skills/implement/design-pass.md +16 -2
  73. package/skills/map/SKILL.md +15 -71
  74. package/skills/map/alignment.md +18 -27
  75. package/skills/map/frontend.md +1 -1
  76. package/skills/map/materialising.md +74 -0
  77. package/skills/map/trackers/files.md +4 -6
  78. package/skills/pre-commit-review/SKILL.md +15 -9
  79. package/skills/pre-commit-review/auto-fix.md +1 -1
  80. package/skills/quick-fix/SKILL.md +1 -1
  81. package/skills/record-context/SKILL.md +6 -6
  82. package/skills/setup/SKILL.md +15 -50
  83. package/skills/setup/browser.md +2 -2
  84. package/skills/setup/first-run.md +19 -8
  85. package/skills/setup/report.md +3 -2
  86. package/skills/setup/row-fixes.md +56 -9
  87. package/skills/sync/SKILL.md +12 -11
  88. package/skills/terminal-workspace/SKILL.md +1 -1
  89. package/skills/test-conventions/SKILL.md +2 -2
  90. package/skills/visual-docs/SKILL.md +69 -235
  91. package/skills/writing/SKILL.md +29 -217
  92. package/skills/writing/examples.md +62 -129
  93. package/docs/adr/0001-ste-writing-standard.md +0 -16
  94. package/docs/adr/0002-version-gate-not-auto-bump.md +0 -35
  95. package/docs/adr/0003-handoff-ack-command.md +0 -19
  96. package/docs/adr/0004-dev-setup-per-host.md +0 -13
  97. package/docs/adr/0005-two-orchestrators-per-host.md +0 -25
  98. package/docs/adr/0006-document-opener-service.md +0 -89
  99. package/docs/adr/0007-lead-check-reads-the-transcript.md +0 -87
  100. package/docs/adr/0008-cli-audits-skill-interviews.md +0 -37
  101. package/docs/adr/0009-verify-the-write-not-the-writer.md +0 -51
  102. package/docs/adr/0010-promote-dev-to-main-by-fast-forward.md +0 -115
  103. package/docs/adr/0011-node-header-is-the-edge-encoding.md +0 -20
  104. package/docs/adr/0012-node-kind-is-a-closed-set-of-five.md +0 -31
  105. package/docs/adr/0013-the-diagram-renderer-is-pure.md +0 -23
  106. package/docs/adr/0014-reading-a-node-hides-its-generated-diagram.md +0 -29
  107. package/docs/adr/0015-a-node-id-links-to-its-issue-through-an-anchor.md +0 -37
  108. package/docs/adr/0016-the-map-root-carries-no-status-of-its-own.md +0 -21
  109. package/docs/adr/0017-call-impeccable-copy-only-its-questions.md +0 -13
  110. package/docs/adr/0018-alignment-packs-use-local-viewers.md +0 -11
  111. package/docs/adr/index.md +0 -18
@@ -1,153 +1,86 @@
1
1
  # Writing examples
2
2
 
3
- The `Write:` and `Not:` pair for each rule in `SKILL.md`, except rules 3 and 11, which keep theirs inline.
3
+ These examples apply the shared communication standard in `../../output-styles/ac-writing-style.md` without prescribing one shape for every answer.
4
4
 
5
- ### 1. Cap a descriptive sentence at 25 words, and an instruction at 20 words (ASD-STE100)
5
+ ## A short reply needs only the answer
6
6
 
7
- - Write: The SessionStart hook creates the symlink at `~/.claude/acstack/bin/acstack`.
8
- - Not: The SessionStart hook, which runs whenever a session begins and which the plugin installs for you, is responsible for creating the symlink that points at the CLI inside the current plugin cache.
7
+ - Write: The build passes
8
+ - Avoid: `## Context`, `## Problem`, and `## Solution` sections to report a successful build
9
9
 
10
- ### 2. Give each sentence one instruction (ASD-STE100)
10
+ ## Preserve the reason when it changes the action
11
11
 
12
- - Write: Run the tests. Stage the spec files.
13
- - Not: Run the tests and stage the spec files, then check the baseline count.
12
+ - Write: Don't cache the token; it expires in five minutes
13
+ - Avoid: Don't cache the token
14
+ - The shorter version omits the constraint that explains the recommendation
15
+ - Write: The hook writes the symlink
16
+ - Avoid: The hook writes the symlink, which means the symlink gets created
17
+ - The second clause adds no information
14
18
 
15
- ### 4. Break a paragraph at three sentences
19
+ ## Give each level one question to answer
16
20
 
17
- - Write: Three sentences, then a new paragraph, even mid-argument.
18
- - Not: A sixth sentence of setup inside the same block.
21
+ - Write: The release is blocked by two failed checks
22
+ - The CLI build fails on a missing import
23
+ - The hook suite fails on malformed JSON
24
+ - Avoid: The release is blocked by these items
25
+ - The CLI build fails on a missing import
26
+ - Run `npm test`
27
+ - Yesterday we considered changing the hook
19
28
 
20
- ### 5. Open a paragraph with its point
29
+ The first list names blockers at the same level.
30
+ The second mixes a blocker, an action, and history.
21
31
 
22
- - Write: Spec sync runs at commit time. It maps changed files to domains, then rewrites each spec.
23
- - Not: Specs can drift. One option is to update them by hand. Spec sync runs at commit time.
32
+ ## Keep the overview connected to the detail
24
33
 
25
- ### 6. Use one term for one meaning across a document (ASD-STE100)
34
+ - Write: The SessionStart hook creates the CLI symlink
35
+ - `hooks/session-start.sh` links the bundled CLI to `~/.claude/acstack/bin/acstack`
36
+ - Avoid: The startup mechanism prepares the launcher
37
+ - `hooks/session-start.sh` creates a symlink
26
38
 
27
- - Write: The map holds nodes. Each node has a status.
28
- - Not: The map holds nodes. Each item has a status.
39
+ The first version ties the readable name to the file and its output.
40
+ The second makes the reader guess whether the names identify the same thing.
29
41
 
30
- ### 7. Define a term of art in plain words, before you first use it
42
+ ## Define unfamiliar terms before relying on them
31
43
 
32
- - Write: Work the frontier, the nodes ready to work now.
33
- - Not: Work the frontier, the unblocked open nodes the tracker returns.
44
+ - Write: Work the frontier, meaning the nodes ready to work now
45
+ - Avoid: Work the frontier returned by the tracker
46
+ - Write: The map holds nodes; each node has a status
47
+ - Avoid: The map holds nodes; each item has a status
34
48
 
35
- - Write: define `map` and `node`, then say what `/acstack:map` does
36
- - Not: say what `/acstack:map` does, then define `map` in the next subsection
49
+ ## Separate the current decision from its history
37
50
 
38
- ### 8. Spell out an abbreviation at first use
51
+ - Write: Use the files backend because it works offline
52
+ - Decision history: We rejected the issues backend because this deployment has no network access
53
+ - Avoid: We first considered issues, then investigated files, and eventually chose files
39
54
 
40
- - Write: an architecture decision record (ADR)
41
- - Not: an ADR
55
+ ## Keep necessary qualifications and evidence
42
56
 
43
- ### 9. Cap a noun string at three words (ASD-STE100)
57
+ - Write: The unit tests pass; browser verification is blocked because Chrome is unavailable
58
+ - Avoid: All checks pass
59
+ - Write: The parser rejects duplicate keys
60
+ - Avoid: The parser offers comprehensive validation
44
61
 
45
- - Write: the knowledge base for browser verification
46
- - Not: the browser verification knowledge base file
62
+ ## Choose clear words without enforcing word counts
47
63
 
48
- ### 10. Keep the articles (ASD-STE100)
64
+ - Write: Use the bundled CLI
65
+ - Avoid: Utilize the bundled CLI
66
+ - Write: The browser verification knowledge base records selectors that survived a page reload
67
+ - Avoid: Removing a necessary term to meet a three-word noun limit
68
+ - Write: The file was deleted before the hook ran
69
+ - Avoid: Inventing an actor to force active voice when the logs do not identify who deleted the file
49
70
 
50
- - Write: Update the spec in the domain directory.
51
- - Not: Update spec in domain directory.
71
+ ## Show relationships without inventing containment
52
72
 
53
- ### 12. Use the short form
73
+ - Write: The API and worker both use the authentication module
74
+ - Avoid: Nesting the worker under the API because both depend on authentication
75
+ - Write: The parser exposes `parse(text)` and keeps tokenization internal
76
+ - Avoid: Listing every tokenizer helper before explaining the parser's interface
54
77
 
55
- - Write: To stage the specs, run the commit skill. It warns because the cap is a heuristic.
56
- - Not: In order to stage the specs, run the commit skill. It warns due to the fact that the cap is a heuristic.
78
+ ## Use formatting to clarify the content
57
79
 
58
- ### 13. Name the actor and put it in front of the verb (ASD-STE100)
59
-
60
- - Write: The task-checker runs the full suite.
61
- - Not: The full suite is run.
62
-
63
- ### 14. Write descriptions in the present tense and procedures in the imperative (ASD-STE100)
64
-
65
- - Write: The hook writes the symlink. Run the hook after you install the plugin.
66
- - Not: The hook will have written the symlink. You should then probably run it.
67
-
68
- ### 15. Make a claim once, at the strength the evidence supports
69
-
70
- - Write: The cap misfires inside tables.
71
- - Not: It may possibly be the case that the cap could sometimes misfire inside tables.
72
-
73
- ### 16. Name the source of a claim
74
-
75
- - Write: ASD-STE100 caps a descriptive sentence at 25 words.
76
- - Not: Experts believe that shorter sentences read better.
77
-
78
- ### 17. Describe a thing by what it does
79
-
80
- - Write: The tunnel forwards port 19988 to Chrome on the laptop.
81
- - Not: The tunnel offers a seamless, robust bridge to your browser.
82
-
83
- ### 18. Name the file, the number, and the actor
84
-
85
- - Write: Three of the eleven skills restate these rules, `commit` among them.
86
- - Not: Several files restate these rules.
87
-
88
- ### 19. Recommend one option and give the reason
89
-
90
- - Write: Use the files backend. It needs no network.
91
- - Not: There is a files backend and an issues backend. Both carry trade-offs.
92
-
93
- ### 20. State what a thing is, then stop
94
-
95
- - Write: The skill holds the rules. The CLI checks them.
96
- - Not: The skill is not just a style guide but a contract.
97
- - Not: The hook writes the symlink rather than copying it.
98
-
99
- ### 21. List as many items as there are
100
-
101
- - Write: The lint warns and never blocks.
102
- - Not: The lint is fast, focused, and forgiving.
103
-
104
- ### 22. Name the thing a pronoun stands for
105
-
106
- - Write: Only `/acstack:map` creates a map.
107
- - Not: Only `/acstack:map` creates one.
108
-
109
- ### 23. Write for a developer who has never seen this repository
110
-
111
- - Write: Node 14 asks which tracker backend ships first.
112
- - Not: The node from this morning's grill.
113
-
114
- - Write: the frontier, meaning the nodes you can work right now
115
- - Not: work the frontier
116
-
117
- ### 24. State what you checked, and when
118
-
119
- - Write: `acstack lint-prose` does not exist yet, as of 2026-08-22.
120
- - Not: My knowledge has a cutoff, so this may have changed since.
121
-
122
- ### 25. Connect clauses with a period or a comma, and set an aside off with an en dash
123
-
124
- - Write: The lint warns. It never blocks. The rule – a heuristic – misfires inside tables.
125
- - Not: The same two sentences joined by an em dash, or by a colon in mid sentence.
126
-
127
- - Write: proposals, designs, and tasks
128
- - Not: proposals, designs and tasks
129
-
130
- ### 26. Write a heading in sentence case, and end a fragment with no period
131
-
132
- - Write: `## Before you finish`, and a table cell that reads `make sure`
133
- - Not: `## Before You Finish.`, and a table cell that reads `make sure.`
134
-
135
- ### 27. Give a heading content that its paragraph does not repeat
136
-
137
- - Write: `## Sentences`
138
- - Not: `## This section covers the rules that apply to sentences`
139
-
140
- ### 28. Bold a single term for emphasis
141
-
142
- - Write: **fog** names whatever nobody can state precisely yet.
143
- - Not: **ACStack** ships a **CLI** that **many** skills call.
144
-
145
- ### 29. Carry the meaning in words
146
-
147
- - Write: Done. 12 tests pass.
148
- - Not: The same line with a tick emoji in front and a rocket after.
149
-
150
- ### 30. End with the last fact
151
-
152
- - Write: The build passes. The baseline holds at 214 tests.
153
- - Not: Let me know if you would like me to help with anything else.
80
+ - Use bullets for distinct checks and numbered steps for actions that must happen in order
81
+ - Use a table when each option needs the same comparison fields
82
+ - Keep a connected explanation in prose when splitting it would hide the causal relationship
83
+ - Indent nested Markdown bullets four spaces and leave a blank line before a list
84
+ - Write `## Before you finish`, not `## Before You Finish.`
85
+ - Write `proposals, designs, and tasks`, with the Oxford comma
86
+ - Report `12 tests pass` in words rather than relying on an icon
@@ -1,16 +0,0 @@
1
- # One plain-language writing standard based on ASD-STE100
2
-
3
- Every durable artifact an agent writes follows one standard. The standard lives in the `writing` skill and follows ASD-STE100 – Simplified Technical English, an aerospace standard for controlled technical writing. We adopt its rules: short sentences with a numeric cap, active voice, one instruction per sentence, one term for one meaning.
4
-
5
- We reject the "add voice" advice common in anti-AI-writing guides. Someone with no context reads the artifacts weeks later. Uniformity serves that reader better than personality.
6
-
7
- ## Considered options
8
-
9
- - Adopt the Cursor `unslop` skill as is – a removal checklist plus "add soul" (first person, varied rhythm, deliberate imperfection). Rejected: removal framing tells an agent what not to do, and personality is noise in specs, ADRs and map nodes.
10
- - Keep the rules where they are today – restated in eight files in slightly different words. Rejected: they had already drifted, and no one could point at one file.
11
-
12
- ## Consequences
13
-
14
- - The standard lives in one skill; every other skill points at it. Plugin prose must itself comply, so a sweep follows.
15
- - A deterministic lint, `acstack lint-prose`, checks what a grep can check. It warns and never blocks, because sentence-length heuristics misfire in tables and code.
16
- - The ASD-STE100 dictionary requires a license, so the plugin does not reproduce it; it ships its own short vocabulary table instead.
@@ -1,35 +0,0 @@
1
- # A PR gate enforces the version bump; CI never bumps it
2
-
3
- The Claude Code plugin cache is keyed by the version in
4
- `.claude-plugin/plugin.json`, so a merge to `main` that does not change the
5
- version is invisible to every installed copy. A pull request gate
6
- (`scripts/version-gate.sh`, run by the `version-gate` workflow) fails the check
7
- when a shipped path changed without a higher version, rather than CI bumping
8
- the version itself. The author decides the semver level, because deriving it
9
- from commit message prefixes is brittle and gets the level wrong exactly when
10
- it matters.
11
-
12
- ## Considered options
13
-
14
- - **Auto-bump on push to `main`.** CI raises the patch version whenever shipped
15
- files land. Removes the failure, but a feature or a breaking change ships as
16
- a patch, and CI has to write to `main`.
17
-
18
- - **release-please.** Derives the level from Conventional Commit prefixes and
19
- opens a release pull request. Correct only when every commit is labelled
20
- correctly, which squashed merges and hand-written subjects do not guarantee.
21
-
22
- - **A pull request gate.** CI refuses the merge; a human sets the version.
23
- Chosen.
24
-
25
- ## Consequences
26
-
27
- - `main` needs branch protection with `version-gate` as a required status
28
- check. Without it the gate is advisory.
29
-
30
- - A shipped change that genuinely should not roll out needs the `no-bump` label
31
- on the pull request. A version that goes down fails even with the label.
32
-
33
- - Documentation-only paths are exempt, listed as `INERT_PATHS` in the script
34
- and duplicated in CONTRIBUTING.md. The two lists have to be kept in sync by
35
- hand.
@@ -1,19 +0,0 @@
1
- # Handoff acknowledgement is a CLI command, not a reply
2
-
3
- /acstack:handoff hands work to another agent and asks it to reply ACCEPT or DECLINE. The sender's watcher, `acstack handoff watch` (`cli/src/lib/ackwatch.ts`), grepped the receiver's transcript for that keyword, a convention an agent can drift from.
4
-
5
- The receiver now acknowledges by running `acstack handoff ack accept|decline --file <handoff-file> "<reason>"`. That command writes a sidecar `<handoff-file>.ack` file, which the watcher polls instead of the transcript.
6
-
7
- ## Considered options
8
-
9
- - Wording only – tighten the ACCEPT/DECLINE prompt further. Rejected: it is still a convention, and the model can still drift from it.
10
- - Lenient transcript matching – match more patterns in the transcript. Rejected: it keeps the same drift risk.
11
- - A PreToolUse hook that blocks work until the sidecar exists – the only hard guarantee. Rejected for now: scoping the hook to handoff-launched sessions is separate work. Revisit if this failure recurs.
12
-
13
- ## Consequences
14
-
15
- - The receiver can still read the handoff file first. It must run the ack command before any other tool use.
16
- - The watcher gains an **engaged** outcome. Engaged means no acknowledgement, but a tool call after the anchor read the handoff file or used Agent, Edit, Write, or Bash.
17
- - The sender sends one nudge after `ack_turns` turns, then restarts the watcher.
18
- - A final engaged outcome is reported as "proceeding, unacknowledged." The sender never relaunches the work elsewhere. Two agents on the same files is the one failure file ownership exists to prevent.
19
- - The transcript keyword match stays as a fallback, labelled `via: text`. It never writes the sidecar.
@@ -1,13 +0,0 @@
1
- # Dev setup is declared per host, not per project
2
-
3
- A dev setup – the machine-level tools an ACStack session runs inside, such as which agent orchestrator hosts the terminal panes and git worktrees and which browser-verification modes work – is recorded in the ACStack CLI's global config (`~/.config/acstack/config.json`, keys under `host.*`), not in the project's `acstack/project.yaml`. The same repository is opened on several machines with different setups, so a per-project value would have to be wrong on all but one of them.
4
-
5
- ## Considered options
6
-
7
- - `acstack/project.yaml`, like `frontend.browser.mode` – shareable and checked in, but forces one answer across every machine that opens the repo.
8
- - Host-level global config, with project.yaml keeping only a preference where one makes sense – chosen.
9
- - Both layers, with the project able to constrain the host – deferred; add only if a real conflict appears.
10
-
11
- ## Consequences
12
-
13
- Skills that change behaviour on the dev setup read the global config first and then check the runtime environment to see what is actually active. The project's `frontend.browser.mode` becomes a preference resolved against what the host declares available. Host setup cannot be committed with the repo, so a fresh machine needs `/acstack:host` before worktree and browser skills behave fully.
@@ -1,25 +0,0 @@
1
- # Two orchestrators coexist on one host, and a checkout's path names its owner
2
-
3
- An orchestrator is a tool that hosts agent terminal panes and git worktrees. Both herdr and Orca are orchestrators, and one host – a single developer machine – may run both at once.
4
-
5
- The host config declares each one as installed or not, at `host.orchestrators.herdr` and `host.orchestrators.orca`. A developer with both installed should not have to pick one, and the session environment already says which tool hosts a session.
6
-
7
- A session lives in the host that launched it and never moves. To continue work from the other host, open a new Claude session in the same checkout – one git worktree directory – from that host. ACStack's `/acstack:handoff` stays what it is, a handoff of a full context window.
8
-
9
- A checkout's path root names its owner. Orca owns `~/orca/workspaces/<repo>/`. Everything under herdr's worktree root, `~/.herdr/worktrees/<repo>/` by default, is herdr's.
10
-
11
- Any other path belongs to plain git. The session's host creates a checkout, and the owner removes it. The worktree skills check `orca worktree ps --json` and `herdr worktree list` before every removal, because neither tool sees the other's sessions.
12
-
13
- Orca lists herdr checkouts, and the paired phone lists them, once the repo's "show in worktree list" switch is on in the desktop app. No CLI sets it, so `/acstack:host` tells the user to.
14
-
15
- ## Considered options
16
-
17
- - One declared orchestrator per host, the earlier `host.orchestrator` enum. Rejected: it forces a choice the developer does not want to make.
18
- - A feature that moves a running session to the other host. Rejected: neither tool offers one, and a new session in the same checkout reaches the same place.
19
- - Either tool removes any checkout. Rejected on pilot evidence from 2026-08-23: Orca's `rm` refuses a path outside its own root, and herdr's `remove` deletes any directory and keeps the branch.
20
-
21
- ## Consequences
22
-
23
- The `teardown-worktree` skill picks the removal command from the checkout's path root, not from the session's host. It deletes the branch itself for a herdr checkout.
24
-
25
- The `new-worktree` skill never passes a path that crosses roots. A config that still sets the old `host.orchestrator` key fails `config check`, and `/acstack:host` re-declares both booleans.
@@ -1,89 +0,0 @@
1
- # A document opener service on the laptop, separate from the Playwriter bridge
2
-
3
- `acstack-open` sends a rendered page to the opener, a small HTTP service on
4
- the user's laptop. The opener stores the page and serves it back on an
5
- address only the laptop can reach (the loopback interface). It then hands
6
- that address to the user's default browser.
7
-
8
- The Playwriter bridge stays as it is, and it no longer shows a document to a
9
- person.
10
-
11
- A page renders on a development virtual machine, which has no browser of its
12
- own. The virtual machine already reaches the laptop through the bridge.
13
-
14
- The bridge is a Chrome extension plus a relay, meaning a small process on the
15
- laptop that the extension connects to. It lets an agent drive a real browser
16
- over the Chrome DevTools Protocol (CDP). Reusing it to show a page to a person
17
- looked like the cheaper answer.
18
-
19
- The two do not collapse into one. The bridge attaches one tab at a time, and
20
- only after someone clicks the extension icon. That click **arms** the tab.
21
-
22
- The bridge also drives a dedicated Chrome profile rather than the user's
23
- default browser. So it cannot satisfy "open this in my normal browser" at all,
24
- and every document through it costs an arming click first.
25
-
26
- The bridge exists so an agent can *drive* a browser. The opener exists so a
27
- person can *see* a page.
28
-
29
- ## Considered options
30
-
31
- **Drive the existing bridge**. Rejected. Arming the bridge takes one click
32
- per tab, inside a separate Chrome profile.
33
-
34
- Rewriting a live page over CDP also detaches the extension outright. The
35
- bridge then stays down until the user arms it again by hand.
36
-
37
- **Forward a port and serve from the virtual machine**. Rejected. The user's
38
- terminal would open an address that a forwarded port carries back to a server
39
- on the virtual machine.
40
-
41
- The reverse tunnel the bridge already maintains runs the wrong way, so this
42
- needs a second forward. That forward comes from a `LocalForward` line in the
43
- user's own SSH host block, and nothing in setup writes it. The page also dies
44
- when the server on the virtual machine stops, which is the common case when a
45
- session ends.
46
-
47
- **Print a clickable hyperlink in the terminal**. Kept as the fallback, not as
48
- the answer.
49
-
50
- The terminal already prints one today. It costs a deliberate click for every
51
- single document. The requirement was to read one document after another
52
- without ceremony.
53
-
54
- **Open the document in the editor instead of a browser**. Rejected.
55
-
56
- The user is moving away from an editor-hosted terminal toward a plain one.
57
- The user asked specifically for the default browser.
58
-
59
- ## Consequences
60
-
61
- A second always-on service now runs on the laptop, and every virtual machine
62
- gets one more tunnel task to carry it. This is deliberate.
63
-
64
- Setup already registers the relay and its tunnels as self-healing scheduled
65
- tasks. The opener inherits that machinery, its deployment, and its
66
- restart-on-change behaviour rather than inventing any.
67
-
68
- The opener gets its own tunnel rather than a second forward on the bridge's
69
- connection. `tunnel.ps1` passes `ExitOnForwardFailure=yes`, so one wedged
70
- port fails the whole `ssh` session. A stuck opener port would take the bridge
71
- down with it.
72
-
73
- The virtual machine can now ask the opener to restart the relay and to
74
- restart the tunnels. Those are two recovery actions the virtual machine could
75
- not perform before, and a human had to paste both into a shell. Arming stays
76
- manual, because it is behaviour of a third-party extension and nothing on
77
- either side can click it.
78
-
79
- The opener stores rendered documents on the laptop. They outlive the session
80
- that produced them. That is what makes a page still work after the virtual
81
- machine goes away.
82
-
83
- The opener prunes the store after a week.
84
-
85
- The service accepts a document and puts it on the user's screen, so a shared
86
- secret called the opener token guards it. Setup generates that token and
87
- copies it to the virtual machine. Loopback binding alone is not enough,
88
- because the reverse tunnel makes the port reachable by anything running on
89
- the virtual machine.
@@ -1,87 +0,0 @@
1
- # A session's own transcript decides lead or child, not the environment
2
-
3
- The `handoff` and `compact-and-continue` skills run only in a **lead session**,
4
- because both write state the lead alone owns. An agent decides which it is by
5
- planting a random mark in its own transcript and then asking which transcript
6
- holds it.
7
-
8
- A hit under `~/.claude/projects/<project>/<session>/subagents/` means the agent
9
- is a subagent or a teammate. No environment variable takes part in that
10
- decision.
11
-
12
- The first version read `CLAUDE_CODE_CHILD_SESSION` instead. Claude Code sets
13
- that variable to `1` in the environment of every Bash tool subprocess, in every
14
- session. So the check was true unconditionally, and both skills refused to run
15
- everywhere (#146).
16
-
17
- The variable marks "spawned by Claude Code", and nothing finer.
18
-
19
- ## Considered options
20
-
21
- - **A different environment variable.** Measured on Claude Code 2.1.241, an
22
- in-process subagent and an in-process teammate both report the lead's exact
23
- `CLAUDE_CODE_SESSION_ID`, `CLAUDE_PID` and `CLAUDE_CODE_ENTRYPOINT`. A child
24
- runs inside the lead's own process, so no variable separates them. Ruled out
25
- by measurement, not by preference.
26
-
27
- - **Drop the check and let a child run the skills.** Simplest, and wrong. A
28
- child shares the lead's `CLAUDE_CODE_SESSION_ID`, so a child's quiet marker
29
- silences a context-pressure nudge the lead still needs, and a child's
30
- `acstack/HANDOFF.md` overwrites the lead's anchor.
31
-
32
- - **Read `taskKind` from the agent's `.meta.json`.** The host does write one
33
- beside each agent transcript, naming `in_process_teammate` for a teammate and
34
- omitting `taskKind` for a plain subagent. An agent cannot tell which of those
35
- files is its own, so the file answers a question nobody can ask.
36
-
37
- - **Plant a mark, then find it.** Chosen. The mark is unique per agent, so the
38
- answer is the agent's own and never a sibling's.
39
-
40
- ## Consequences
41
-
42
- - The command polls for up to ten seconds rather than grepping once. The host
43
- writes the record carrying a command while that command still runs, roughly
44
- four seconds in.
45
-
46
- A single grep therefore runs too early, finds nothing and answers
47
- `lead` for everyone. A lead usually exits in about four seconds, as
48
- soon as its own record lands.
49
-
50
- - The check reads a Claude Code internal layout that no public contract
51
- describes. A host that renames the `subagents/` directory, or files agent
52
- transcripts elsewhere, turns every child into a `lead` verdict.
53
-
54
- - Absence of evidence reads as `lead`. A host that persists no transcript
55
- leaves the command empty-handed, and the skill proceeds. Failing closed is
56
- what produced #146, so the failure now falls on the side that keeps the
57
- skills runnable.
58
-
59
- - The agent transcripts alone decide. An agent's own mark reaches
60
- `<session>.jsonl` whether it leads or not. So the loop reads that file only
61
- as an early exit for a lead, never as evidence of a child.
62
-
63
- - The nonce placeholder stays angle-bracketed. `n=acstack-whoami-<nonce>` is a
64
- bash syntax error, so an agent that pastes the block without substituting
65
- fails loudly. A bare token would run instead. It would match every transcript
66
- in the session that had already read the skill file, so the command would
67
- answer `child` to a real lead.
68
-
69
- - The agent still chooses the nonce, and a language model samples randomness
70
- badly. Two agents in one session that pick the same eight characters read
71
- each other's transcripts. Generating the nonce at runtime cannot fix that.
72
-
73
- The mark has to sit in the command text for the command to find it. A
74
- value computed at runtime reaches the transcript only after the command
75
- ends.
76
-
77
- - Both skills carry their own copy of the block, rather than calling a shared
78
- script. `skills/new-worktree/detect-orchestrator.sh` shows the repo has that
79
- pattern. No home exists for a script two skills share, though.
80
-
81
- The repo also already repeats the context-pressure path expression in
82
- three places. `tests/test-skill-gates.sh` asserts the two copies match
83
- byte for byte. That assertion is what makes the duplication safe to keep.
84
-
85
- - `tests/test-skill-gates.sh` extracts the command from each `SKILL.md` and
86
- runs it against fixture transcript layouts. The fixtures encode the layout
87
- above, so they need revisiting whenever the host changes it.
@@ -1,37 +0,0 @@
1
- # The CLI audits, the skill interviews
2
-
3
- `acstack config check` is the only health check in ACStack. It reports what is
4
- wrong with a machine and a project. It changes nothing.
5
-
6
- `/acstack:setup` reads that report, then asks the user what to do about each
7
- failure. The skill writes the answers. Neither one does the other's job.
8
-
9
- The check reads `~/.claude/settings.json` and the two project settings files,
10
- even though Claude Code owns them and ACStack does not. A health check with a
11
- row it cannot see is a health check nobody can trust.
12
-
13
- ## Considered options
14
-
15
- ACStack had two commands named `check`.
16
-
17
- The CLI's audited the host axes. The config skill's audited the project's
18
- infrastructure in prose. Neither called the other, and a user could not tell
19
- them apart by name.
20
-
21
- Leaving the split in place keeps ACStack's CLI reading only ACStack's own
22
- files. It also lets the two audits drift apart. It leaves the project half
23
- untestable, because continuous integration cannot run prose in a skill body.
24
-
25
- ## Consequences
26
-
27
- The check grows a `--json` output, so the skill maps a failing row to the fix
28
- it offers. That output is an interface. Renaming a row identifier breaks the
29
- skill silently, so the row identifiers need tests.
30
-
31
- Every audit rule now lives in TypeScript and gets tested. No skill re-probes
32
- the machine with its own shell commands.
33
-
34
- A user who wants one setting changed runs `acstack config set <key> <value>`
35
- and answers no questions. The full key reference lives in
36
- `docs/config-reference.md`, because seventeen keys carry more nuance than a
37
- help string holds.
@@ -1,51 +0,0 @@
1
- # The config writer verifies its result instead of predicting it
2
-
3
- `acstack config set` writes a key into `acstack/project.yaml` by splicing the
4
- new value over the old value's bytes, so a hand-edited file keeps its comments
5
- and its spacing. Before writing, it parses what it built and compares that data
6
- against what the YAML document interface would have produced. The two must
7
- agree, or the write falls back to the document interface.
8
-
9
- The writer verifies that fallback the same way. It parses the emitted text and
10
- compares it against the same data. A write neither path can verify refuses with
11
- exit 1 and leaves the file byte for byte as it was.
12
-
13
- The comparison covers the whole file, not the key that changed.
14
-
15
- ## Considered options
16
-
17
- The first version predicted safety with guards on the node it was replacing.
18
- Three rounds of that shipped four ways to corrupt a user's file, each behind a
19
- green success message and exit code 0.
20
-
21
- A folded or literal block scalar's byte range runs past its trailing newline,
22
- so the splice ate the line break and destroyed the following key. An existing
23
- empty value has a zero-width range, so the write produced `test:npm test`.
24
-
25
- A new value spanning lines landed at column zero. A scalar inside a flow
26
- collection passed every guard, and a value holding a comma truncated the key
27
- and invented a second one beside it.
28
-
29
- Each guard was correct. Each author read the node and not the context around
30
- it. A user would have found the fifth shape.
31
-
32
- ## Consequences
33
-
34
- The writer costs one extra parse per write, which nobody running a command by
35
- hand will notice.
36
-
37
- A key-only comparison passes every test in the suite and every input a 2020
38
- case sweep could reach. The writer compares the whole file anyway. Narrowing it
39
- means arguing about shapes nobody has constructed yet, and that argument has
40
- already been wrong four times.
41
-
42
- Do not narrow it to the changed key on the grounds that no test covers the
43
- difference. No test can.
44
-
45
- The document interface was the trusted baseline until a fifth shape broke it. A
46
- whitespace-only value over a block scalar with a sibling key after it emitted a
47
- content line no parser reads back. The value returned as the empty string,
48
- behind exit 0.
49
-
50
- The splice refused that write correctly and handed it to a fallback nobody
51
- checked. The writer checks both paths now.