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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +14 -7
- package/agents/codex/frontend-verifier.toml +89 -6
- package/agents/codex/task-checker.toml +83 -2
- package/agents/codex/task-executor.toml +83 -1
- package/agents/codex/test-writer.toml +77 -1
- package/agents/frontend-verifier.md +13 -6
- package/agents/task-checker.md +7 -2
- package/agents/task-executor.md +7 -1
- package/agents/test-writer.md +1 -1
- package/assets/terminal-workspace/config.example.yaml +1 -1
- package/assets/terminal-workspace/helpers/acstack-md +12 -4
- package/assets/terminal-workspace/helpers/acstack-open +10 -2
- package/cli/dist/index.js +10142 -9369
- package/cli/dist/index.js.map +4 -4
- package/cli/package.json +1 -1
- package/docs/config-reference.md +113 -14
- package/docs/dev-setups.md +4 -4
- package/docs/terminal-workspace.md +1 -1
- package/docs/workflows.md +22 -16
- package/examples/design-doc/acstack/README.md +273 -0
- package/examples/design-doc/acstack/acstack.yaml +4 -0
- package/examples/design-doc/acstack/cli.yaml +5 -0
- package/examples/design-doc/acstack/design.yaml +39 -0
- package/examples/design-doc/acstack/github.yaml +12 -0
- package/examples/design-doc/acstack/host.yaml +14 -0
- package/examples/design-doc/acstack/journey.md +85 -0
- package/examples/design-doc/acstack/publication.md +16 -0
- package/examples/design-doc/acstack/review-runtime.yaml +24 -0
- package/examples/design-doc/acstack/skills.yaml +22 -0
- package/examples/design-doc/acstack/store.yaml +11 -0
- package/examples/design-doc/acstack/user.yaml +15 -0
- package/examples/design-doc/acstack/viewer.yaml +13 -0
- package/hooks/ac-writing-style-reminder.sh +7 -18
- package/hooks/communication-standard.mjs +17 -0
- package/hooks/communication-standard.sh +6 -0
- package/hooks/context-pressure.sh +2 -2
- package/hooks/hooks.json +18 -0
- package/hooks/lib/communication-standard.mjs +16 -0
- package/hooks/project-data.sh +38 -0
- package/hooks/session-start-handoff.sh +21 -7
- package/hooks/session-start.sh +9 -2
- package/orchestrator/AGENTS.md +25 -14
- package/output-styles/ac-writing-style.md +75 -276
- package/package.json +2 -1
- package/pi/agents/frontend-verifier.md +89 -6
- package/pi/agents/task-checker.md +83 -2
- package/pi/agents/task-executor.md +83 -1
- package/pi/agents/test-writer.md +77 -1
- package/pi/extension.ts +70 -12
- package/profiles/fullstack-python.yaml +1 -1
- package/profiles/node-typescript.yaml +1 -1
- package/profiles/python.yaml +1 -1
- package/skills/archive/SKILL.md +53 -36
- package/skills/bootstrap/SKILL.md +6 -6
- package/skills/bridge/SKILL-VM.md +11 -2
- package/skills/bridge/SKILL-WINDOWS.md +3 -3
- package/skills/browser-verify/SKILL.md +14 -5
- package/skills/code-review/SKILL.md +8 -2
- package/skills/commit/SKILL.md +7 -6
- package/skills/compact-and-continue/SKILL.md +9 -8
- package/skills/design-doc/SKILL.md +235 -0
- package/skills/explore/SKILL.md +1 -1
- package/skills/grilling/SKILL.md +4 -4
- package/skills/handoff/SKILL.md +4 -4
- package/skills/host/SKILL.md +1 -1
- package/skills/host/detect-host.sh +2 -2
- package/skills/host/notes.md +2 -2
- package/skills/host/questions.md +1 -1
- package/skills/implement/SKILL.md +20 -13
- package/skills/implement/decision-log.md +9 -8
- package/skills/implement/design-pass.md +16 -2
- package/skills/map/SKILL.md +15 -71
- package/skills/map/alignment.md +18 -27
- package/skills/map/frontend.md +1 -1
- package/skills/map/materialising.md +74 -0
- package/skills/map/trackers/files.md +4 -6
- package/skills/pre-commit-review/SKILL.md +15 -9
- package/skills/pre-commit-review/auto-fix.md +1 -1
- package/skills/quick-fix/SKILL.md +1 -1
- package/skills/record-context/SKILL.md +6 -6
- package/skills/setup/SKILL.md +15 -50
- package/skills/setup/browser.md +2 -2
- package/skills/setup/first-run.md +19 -8
- package/skills/setup/report.md +3 -2
- package/skills/setup/row-fixes.md +56 -9
- package/skills/sync/SKILL.md +12 -11
- package/skills/terminal-workspace/SKILL.md +1 -1
- package/skills/test-conventions/SKILL.md +2 -2
- package/skills/visual-docs/SKILL.md +69 -235
- package/skills/writing/SKILL.md +29 -217
- package/skills/writing/examples.md +62 -129
- package/docs/adr/0001-ste-writing-standard.md +0 -16
- package/docs/adr/0002-version-gate-not-auto-bump.md +0 -35
- package/docs/adr/0003-handoff-ack-command.md +0 -19
- package/docs/adr/0004-dev-setup-per-host.md +0 -13
- package/docs/adr/0005-two-orchestrators-per-host.md +0 -25
- package/docs/adr/0006-document-opener-service.md +0 -89
- package/docs/adr/0007-lead-check-reads-the-transcript.md +0 -87
- package/docs/adr/0008-cli-audits-skill-interviews.md +0 -37
- package/docs/adr/0009-verify-the-write-not-the-writer.md +0 -51
- package/docs/adr/0010-promote-dev-to-main-by-fast-forward.md +0 -115
- package/docs/adr/0011-node-header-is-the-edge-encoding.md +0 -20
- package/docs/adr/0012-node-kind-is-a-closed-set-of-five.md +0 -31
- package/docs/adr/0013-the-diagram-renderer-is-pure.md +0 -23
- package/docs/adr/0014-reading-a-node-hides-its-generated-diagram.md +0 -29
- package/docs/adr/0015-a-node-id-links-to-its-issue-through-an-anchor.md +0 -37
- package/docs/adr/0016-the-map-root-carries-no-status-of-its-own.md +0 -21
- package/docs/adr/0017-call-impeccable-copy-only-its-questions.md +0 -13
- package/docs/adr/0018-alignment-packs-use-local-viewers.md +0 -11
- package/docs/adr/index.md +0 -18
|
@@ -1,153 +1,86 @@
|
|
|
1
1
|
# Writing examples
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
5
|
+
## A short reply needs only the answer
|
|
6
6
|
|
|
7
|
-
- Write: The
|
|
8
|
-
-
|
|
7
|
+
- Write: The build passes
|
|
8
|
+
- Avoid: `## Context`, `## Problem`, and `## Solution` sections to report a successful build
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Preserve the reason when it changes the action
|
|
11
11
|
|
|
12
|
-
- Write:
|
|
13
|
-
-
|
|
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
|
-
|
|
19
|
+
## Give each level one question to answer
|
|
16
20
|
|
|
17
|
-
- Write:
|
|
18
|
-
-
|
|
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
|
-
|
|
29
|
+
The first list names blockers at the same level.
|
|
30
|
+
The second mixes a blocker, an action, and history.
|
|
21
31
|
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
42
|
+
## Define unfamiliar terms before relying on them
|
|
31
43
|
|
|
32
|
-
- Write: Work the frontier, the nodes ready to work now
|
|
33
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
- Not: an ADR
|
|
55
|
+
## Keep necessary qualifications and evidence
|
|
42
56
|
|
|
43
|
-
|
|
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
|
-
|
|
46
|
-
- Not: the browser verification knowledge base file
|
|
62
|
+
## Choose clear words without enforcing word counts
|
|
47
63
|
|
|
48
|
-
|
|
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
|
-
|
|
51
|
-
- Not: Update spec in domain directory.
|
|
71
|
+
## Show relationships without inventing containment
|
|
52
72
|
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
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.
|