acstack 0.50.4 → 0.52.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 +7187 -6402
  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 +238 -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
@@ -0,0 +1,5 @@
1
+ id: cli
2
+ name: CLI package
3
+ summary: Ships the review command, local server, and browser review interface.
4
+ kind: component
5
+ parent: acstack
@@ -0,0 +1,39 @@
1
+ id: acstack-design
2
+ name: ACStack design review
3
+ summary: >-
4
+ ACStack guides design authoring, saves browser feedback, reconciles optional
5
+ map contributions, and records exact-revision approval with retained evidence.
6
+ detail: journey.md
7
+ elements:
8
+ - user.yaml
9
+ - acstack.yaml
10
+ - skills.yaml
11
+ - host.yaml
12
+ - cli.yaml
13
+ - review-runtime.yaml
14
+ - viewer.yaml
15
+ - store.yaml
16
+ - github.yaml
17
+ concerns:
18
+ - id: offline-review
19
+ name: Offline review
20
+ elements: [review-runtime, viewer, design-source]
21
+ requirement: >-
22
+ Reviewers can inspect the design without uploading project details
23
+ or fetching browser assets.
24
+ response: >-
25
+ The review command and server read bounded local source files and
26
+ embed validated graph data with bundled browser assets, without uploading
27
+ the design. Agent-side reads of GitHub-bound maps still require
28
+ network access.
29
+ - id: honest-scope
30
+ name: Honest review status
31
+ elements: [skills, review-runtime, viewer]
32
+ requirement: >-
33
+ An exported review artifact must not imply that a reviewer approved
34
+ a map or implementation.
35
+ response: >-
36
+ Comments and exports are not approval. Approval requires reconciled
37
+ feedback and contributions, resolved blocking questions, and the exact
38
+ source, review, comments, and map-input tuple. Implementation checks
39
+ remain separate.
@@ -0,0 +1,12 @@
1
+ id: github
2
+ name: GitHub
3
+ summary: Hosts a published copy of the Markdown companion when the developer chooses to share it.
4
+ kind: external-system
5
+ channels: [web]
6
+ detail: publication.md
7
+ relationships:
8
+ - id: publish-companion
9
+ from: user
10
+ to: github
11
+ direction: one-way
12
+ label: Optionally publishes the Markdown companion to
@@ -0,0 +1,14 @@
1
+ id: host
2
+ name: Agent session setup
3
+ summary: >-
4
+ Registers ACStack skill commands and adds rules for planning, coding,
5
+ and checking changes to the agent's session.
6
+ kind: component
7
+ parent: acstack
8
+ channels: [agent]
9
+ relationships:
10
+ - id: load-skills
11
+ from: host
12
+ to: skills
13
+ direction: one-way
14
+ label: Registers
@@ -0,0 +1,85 @@
1
+ ## Review the design before implementation
2
+
3
+ ACStack saves design feedback, reconciles comments and optional map contributions, and records human approval of the exact reviewed inputs.
4
+
5
+ This example keeps the existing architecture: Agent skills guide the agent; the Review command and server validate source and save review evidence. The Browser review interface shows the design and collects feedback and approval. Review the responsibilities, containment, and labeled arrows before implementation.
6
+
7
+ ### Author, review, reconcile, and approve
8
+
9
+ 1. The developer asks the agent to prepare a design through the Agent skills registered by Agent session setup
10
+ 2. The agent writes the entry, element YAML, and supporting Markdown in one bounded directory tree
11
+ 3. The agent runs `acstack design-doc design.yaml --markdown /tmp/acstack-design-review.md` with an unused output path and keeps the server running
12
+ 4. The server validates source and serves the prepared graph with bundled browser assets; the browser never reads YAML directly
13
+ 5. The developer saves comments, chooses Send to agent, and pastes the copied prompt into the agent session
14
+ 6. The agent reads the saved review, revises source, and uses `acstack design-review status design.yaml` to inspect feedback and optional map contributions
15
+ 7. The agent explicitly reconciles each selected comment and current contribution, then resolves blocking human questions or marks dropped scope out of scope
16
+ 8. The agent reopens changed source for review; the human chooses Approve this revision once reconciliation is current
17
+ 9. The agent requires `approval.valid: true` from status before implementation, then runs the separate implementation checks
18
+ 10. At map closeout, archive verifies implemented functional requirements in living specs, architecture decision records (ADRs), and agreed glossary terms before disposing of temporary nodes
19
+
20
+ The developer can manually publish the generated Markdown companion to GitHub. Publication does not transfer browser comments or approval, and ACStack does not track that publication automatically.
21
+
22
+ ### Approval belongs to exact inputs
23
+
24
+ - Approval binds `sourceRevision`, `reviewRevision`, `commentsDigest`, and `mapInputsDigest`, not the rendered page alone
25
+ - Each selected comment and current contribution needs one explicit disposition: `applied`, `retained`, or `needs-human`, with a rationale
26
+ - Unresolved blocking decisions or a `needs-human` disposition prevent approval; comments alone never authorize implementation
27
+ - Source, saved feedback, or meaningful contribution changes reopen the gate; presentation regeneration alone preserves approval
28
+
29
+ - Use `design-review status` for the current tuple and contribution keys
30
+ - Follow `skills/design-doc/SKILL.md` for the reconciliation schema and `design-review reconcile <entry> --input <json-file>`
31
+ - Select earlier feedback with `--review-file <canonical-review.json>` when reconciling that history
32
+ - Original comments stay with their original version
33
+ - Previously selected histories remain review obligations after later source changes
34
+
35
+ This revised example is a new draft requiring fresh human approval.
36
+
37
+ ### Map binding is optional
38
+
39
+ This portable example has no map binding. A project can add `planning: {tracker: files | github, map: <name>}` and put `Design entry: <repository-relative-path>` in its map root. Node bodies supply explicit design contributions; the map does not become the architecture graph.
40
+
41
+ Bundled browser assets require no external fetch or design upload. Agent-side reads of a GitHub-bound map still need GitHub access. The diagram's GitHub arrow describes manual Markdown publication, not tracker synchronization.
42
+
43
+ ### Archive preserves evidence; legacy import is explicit
44
+
45
+ - Archive checks current approval and reconciliation before closing a bound map
46
+ - Archive verifies implemented requirements against source and verification evidence
47
+ - Archive records qualifying ADRs and glossary terms
48
+ - Archive retains design sources, canonical reviews, import history, original legacy artifacts, and decision logs independently of node disposal
49
+
50
+ - Use `node walk`, `node frontier`, and `node diagram` for planning; ACStack retires `map --map` and `align-viewer` without aliases
51
+ - Import legacy feedback only through `design-review migrate` with an explicit target mapping
52
+ - Treat imported approval as historical; imported comments require reconciliation and fresh exact-revision approval
53
+ - Startup and archive never migrate automatically
54
+
55
+ ### Local source and optional GitHub publication
56
+
57
+ - Authored design files are the local YAML and supporting Markdown read by the Review command and server
58
+ - GitHub hosts a published copy of the generated companion only when the Project developer chooses to share it
59
+ - Git ignore rules control ordinary tracking; they neither publish files nor prevent local browser review
60
+ - Both the Authored design files and GitHub drawers explain source ownership, published copies, and ignore rules
61
+
62
+ ### Containment and arrows keep their existing meaning
63
+
64
+ The ACStack plugin contains Agent skills, Agent session setup, and the CLI package. The CLI package contains the Review command and server and the Browser review interface. The Project developer, Authored design files, and GitHub remain outside the plugin.
65
+
66
+ - Each component is one entity, shown collapsed or expanded
67
+ - Nesting means containment; arrows connect responsible entities, never ancestors to descendants
68
+ - Read one-way arrows as actor, action, and target: the server reads source, and the developer optionally publishes Markdown
69
+ - The bidirectional review-session arrow covers the prepared graph, posted comments, and retrieved comments
70
+ - Concerns describe shared requirements without changing containment
71
+
72
+ ### Optional repository context
73
+
74
+ - Authoring, reconciliation, approval, and migration guidance: `skills/design-doc/SKILL.md`
75
+ - Local review and lifecycle commands: `cli/src/commands/design-doc.ts`
76
+ - Bounded source validation, graph, and Markdown generation: `cli/src/lib/design-doc.ts`
77
+ - Contributions and exact-input approval: `cli/src/lib/design-map.ts`, `cli/src/lib/design-lifecycle.ts`
78
+ - Saved review history and legacy imports: `cli/src/lib/design-review.ts`, `cli/src/lib/design-migration.ts`
79
+ - Closeout and evidence retention: `skills/archive/SKILL.md`
80
+
81
+ - Run the review command from this example directory with a built CLI
82
+ - Choose `--port <port>` if another review uses the default port
83
+ - Use an unused path for each Markdown export
84
+ - Keep the companion beside source when its relative links must work on GitHub
85
+ - New designs default to Git-ignored `.acstack/designs/`; this repository intentionally tracks this public example
@@ -0,0 +1,16 @@
1
+ Authored design files define the design in the local checkout; GitHub hosts a published copy only if the developer chooses to share it.
2
+
3
+ - Local files drive the review
4
+ - The Review command and server read the local YAML and supporting Markdown to generate the browser view and Markdown companion
5
+ - Revise these source files when the design changes
6
+ - Local browser review and saved comments work without publishing design files to GitHub
7
+ - GitHub hosts a published copy
8
+ - The Project developer can commit and push the generated companion for others to read on GitHub
9
+ - The developer can publish the companion alone or include the authored source files
10
+ - GitHub does not replace the local files read by the review server or automatically receive its saved comments
11
+ - This diagram's publication arrow is separate from using GitHub issues as a map tracker
12
+ - Git ignore rules control tracking, not publication
13
+ - Ignore rules exclude matching untracked files from ordinary staging
14
+ - Removing an ignore rule does not stage, commit, or push anything
15
+ - Already tracked files remain tracked even if an ignore rule later matches them
16
+ - New project designs under `.acstack/` stay ignored by default; this public example is tracked separately
@@ -0,0 +1,24 @@
1
+ id: review-runtime
2
+ name: Review command and server
3
+ summary: >-
4
+ Reads and validates authored YAML, serves the browser review interface,
5
+ saves comments, and exports Markdown.
6
+ kind: component
7
+ parent: cli
8
+ channels: [cli, web]
9
+ relationships:
10
+ - id: export-design
11
+ from: skills
12
+ to: review-runtime
13
+ direction: one-way
14
+ label: Guides the agent to run
15
+ - id: read-source
16
+ from: review-runtime
17
+ to: design-source
18
+ direction: one-way
19
+ label: Reads design source
20
+ - id: review-session
21
+ from: review-runtime
22
+ to: viewer
23
+ direction: bidirectional
24
+ label: Exchanges the design and comments with
@@ -0,0 +1,22 @@
1
+ id: skills
2
+ name: Agent skills
3
+ summary: Guide the agent through authoring and exporting a design for review.
4
+ kind: component
5
+ parent: acstack
6
+ channels: [agent]
7
+ relationships:
8
+ - id: author-design
9
+ from: user
10
+ to: skills
11
+ direction: one-way
12
+ label: Requests design guidance from
13
+ - id: export-design
14
+ from: skills
15
+ to: review-runtime
16
+ direction: one-way
17
+ label: Guides the agent to run
18
+ - id: load-skills
19
+ from: host
20
+ to: skills
21
+ direction: one-way
22
+ label: Registers
@@ -0,0 +1,11 @@
1
+ id: design-source
2
+ name: Authored design files
3
+ summary: Holds the local YAML and supporting Markdown that the review server reads.
4
+ kind: store
5
+ detail: publication.md
6
+ relationships:
7
+ - id: read-source
8
+ from: review-runtime
9
+ to: design-source
10
+ direction: one-way
11
+ label: Reads design source
@@ -0,0 +1,15 @@
1
+ id: user
2
+ name: Project developer
3
+ summary: Authors the design and reviews the exported artifact locally.
4
+ kind: actor
5
+ relationships:
6
+ - id: author-design
7
+ from: user
8
+ to: skills
9
+ direction: one-way
10
+ label: Requests design guidance from
11
+ - id: publish-companion
12
+ from: user
13
+ to: github
14
+ direction: one-way
15
+ label: Optionally publishes the Markdown companion to
@@ -0,0 +1,13 @@
1
+ id: viewer
2
+ name: Browser review interface
3
+ summary: >-
4
+ Receives the prepared design graph and syncs comments with the local server.
5
+ kind: component
6
+ parent: cli
7
+ channels: [web]
8
+ relationships:
9
+ - id: review-session
10
+ from: review-runtime
11
+ to: viewer
12
+ direction: bidirectional
13
+ label: Exchanges the design and comments with
@@ -8,11 +8,9 @@
8
8
  #
9
9
  # The reminder text is EXTRACTED from output-styles/ac-writing-style.md on every
10
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
11
+ # one changes. The marked communication block is the canonical standard for
12
+ # chat and durable writing. Extract it in full, including nested guidance;
13
+ # headings and checklist item counts are not an extraction contract.
16
14
  #
17
15
  # Output is JSON only, with suppressOutput true, so nothing reaches the user's
18
16
  # transcript. The hook stays silent unless the active output style is this one.
@@ -66,21 +64,12 @@ awk '
66
64
  }
67
65
  function emit(s) { out = out esc(s) "\\n" }
68
66
 
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 }
67
+ /^<!-- acstack:communication:start -->$/ { shared = 1; next }
68
+ /^<!-- acstack:communication:end -->$/ { complete = shared; exit }
69
+ shared { emit($0) }
81
70
 
82
71
  END {
83
- if (out == "") exit 1
72
+ if (!complete || out == "") exit 1
84
73
  printf "{\"suppressOutput\": true, \"hookSpecificOutput\": {\"hookEventName\": \"UserPromptSubmit\", \"additionalContext\": \"ac-writing-style reminder\\n\\n%s\"}}\n", out
85
74
  }
86
75
  ' "$style_file" || silent
@@ -0,0 +1,17 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { readCommunicationStandard } from './lib/communication-standard.mjs';
3
+
4
+ try {
5
+ const { hook_event_name: event } = JSON.parse(readFileSync(0, 'utf8'));
6
+ if (event !== 'SessionStart' && event !== 'SubagentStart') {
7
+ throw new Error('Expected SessionStart or SubagentStart');
8
+ }
9
+ const standard = readCommunicationStandard(process.argv[2]);
10
+ console.log(JSON.stringify({
11
+ suppressOutput: true,
12
+ hookSpecificOutput: { hookEventName: event, additionalContext: standard },
13
+ }));
14
+ } catch (error) {
15
+ console.error(`acstack communication standard: ${error.message}`);
16
+ process.exitCode = 1;
17
+ }
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ # Startup context is independent of project activation and selected output style.
3
+ set -eu
4
+ root="${CLAUDE_PLUGIN_ROOT:-}"
5
+ [ -n "$root" ] || root="$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)"
6
+ exec node "$root/hooks/communication-standard.mjs" "$root"
@@ -40,7 +40,7 @@
40
40
  # nudge when it crosses each rung rather than on every single stop.
41
41
  #
42
42
  # The default rungs are workflow.handoff.nudge_warn and nudge_severe from
43
- # acstack/project.yaml (defaulting to 200000 / 500000), and then one rung
43
+ # .acstack/project.yaml (defaulting to 200000 / 500000), and then one rung
44
44
  # every workflow.handoff.nudge_step tokens (default 100000) above the last
45
45
  # one. Setting workflow.handoff.context_thresholds replaces the default rungs
46
46
  # entirely with the listed ones - written either block style (one "- item"
@@ -361,7 +361,7 @@ def read_config():
361
361
  "context_thresholds": None,
362
362
  }
363
363
  try:
364
- with open(os.path.join("acstack", "project.yaml"), encoding="utf-8", errors="replace") as f:
364
+ with open(os.path.join(".acstack", "project.yaml"), encoding="utf-8", errors="replace") as f:
365
365
  lines = f.read().split("\n")
366
366
  except OSError:
367
367
  return cfg
package/hooks/hooks.json CHANGED
@@ -1,6 +1,14 @@
1
1
  {
2
2
  "hooks": {
3
3
  "SessionStart": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/communication-standard.sh\""
9
+ }
10
+ ]
11
+ },
4
12
  {
5
13
  "hooks": [
6
14
  {
@@ -26,6 +34,16 @@
26
34
  ]
27
35
  }
28
36
  ],
37
+ "SubagentStart": [
38
+ {
39
+ "hooks": [
40
+ {
41
+ "type": "command",
42
+ "command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/communication-standard.sh\""
43
+ }
44
+ ]
45
+ }
46
+ ],
29
47
  "Stop": [
30
48
  {
31
49
  "hooks": [
@@ -0,0 +1,16 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ /** Read the only authored communication standard, refusing partial blocks. */
5
+ export function readCommunicationStandard(root) {
6
+ const file = join(root, 'output-styles', 'ac-writing-style.md');
7
+ const lines = readFileSync(file, 'utf8').split(/\r?\n/);
8
+ const starts = lines.flatMap((line, i) => line === '<!-- acstack:communication:start -->' ? [i] : []);
9
+ const ends = lines.flatMap((line, i) => line === '<!-- acstack:communication:end -->' ? [i] : []);
10
+ if (starts.length !== 1 || ends.length !== 1 || starts[0] >= ends[0]) {
11
+ throw new Error(`${file}: expected one ordered communication marker pair`);
12
+ }
13
+ const standard = lines.slice(starts[0] + 1, ends[0]).join('\n').trim();
14
+ if (!standard) throw new Error(`${file}: empty communication standard`);
15
+ return standard;
16
+ }
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ # Source from host hooks before reading config or writing project data.
3
+ acstack_has_legacy_project_data() {
4
+ local root="$1" name
5
+ for name in project.yaml domain-map.yaml; do
6
+ { [ -f "$root/acstack/$name" ] || [ -L "$root/acstack/$name" ]; } && return 0
7
+ done
8
+ for name in alignment-packs design-reviews maps specs changes archive decision-logs; do
9
+ { [ -d "$root/acstack/$name" ] || [ -L "$root/acstack/$name" ]; } && return 0
10
+ done
11
+ return 1
12
+ }
13
+
14
+ acstack_project_root() {
15
+ local root
16
+ root="$PWD"
17
+ while [ "$root" != / ]; do
18
+ if [ -d "$root/.acstack" ] || acstack_has_legacy_project_data "$root"; then
19
+ printf '%s\n' "$root"
20
+ return
21
+ fi
22
+ root=$(dirname "$root")
23
+ done
24
+ git rev-parse --show-toplevel 2>/dev/null || printf '%s\n' "$PWD"
25
+ }
26
+
27
+ acstack_ensure_project_data() {
28
+ local root="$1" bundled_cli="$2"
29
+ if acstack_has_legacy_project_data "$root"; then
30
+ echo 'acstack: legacy project data found; run ~/.claude/acstack/bin/acstack project-data migrate before using it.' >&2
31
+ fi
32
+ if ! (cd "$root" && "$bundled_cli" project-data ensure >&2); then
33
+ echo 'acstack: project-data ensure failed; ignore policy is not confirmed installed. Skipping project activation and private writes.' >&2
34
+ return 1
35
+ fi
36
+ # A second config root must never hide unmigrated project data.
37
+ ! acstack_has_legacy_project_data "$root"
38
+ }
@@ -9,13 +9,13 @@
9
9
  # the load-bearing state the summary may have compressed away (next action, task
10
10
  # ledger, agent-team file ownership, blockers).
11
11
  #
12
- # Active (pending) handoff lives at the fixed path acstack/HANDOFF.md, so this
12
+ # Active (pending) handoff lives at the fixed path .acstack/HANDOFF.md, so this
13
13
  # hook reads one known file with no CLI call. The file's frontmatter records the
14
14
  # change it belongs to. On consume, the file is MOVED into that change's own
15
15
  # folder, accumulating a per-change history:
16
16
  #
17
- # acstack/changes/<change>/handoffs/<timestamp>.md (when the change dir exists)
18
- # acstack/handoffs/<change>/<timestamp>.md (ad-hoc, or change archived)
17
+ # .acstack/changes/<change>/handoffs/<timestamp>.md (when the change dir exists)
18
+ # .acstack/handoffs/<change>/<timestamp>.md (ad-hoc, or change archived)
19
19
  #
20
20
  # Storing consumed handoffs inside the change dir means they travel with the
21
21
  # change when /acstack:archive moves it. Names are timestamped with a numeric
@@ -32,6 +32,12 @@
32
32
  set -u
33
33
 
34
34
  command -v python3 >/dev/null 2>&1 || exit 0
35
+ source "$(dirname "${BASH_SOURCE[0]}")/project-data.sh"
36
+ project_root=$(acstack_project_root)
37
+ export ACSTACK_LEGACY_PROJECT_DATA=0
38
+ acstack_has_legacy_project_data "$project_root" && ACSTACK_LEGACY_PROJECT_DATA=1
39
+ export ACSTACK_BUNDLED_CLI="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}/cli/bin/acstack.js"
40
+ cd "$project_root" || exit 0
35
41
 
36
42
  # Capture the hook payload from stdin before running python. The heredoc below
37
43
  # becomes python's stdin (the program source), so the payload must travel via an
@@ -40,7 +46,7 @@ ACSTACK_HOOK_INPUT="$(cat)"
40
46
  export ACSTACK_HOOK_INPUT
41
47
 
42
48
  python3 <<'PY'
43
- import json, os, re, shutil, sys
49
+ import json, os, re, shutil, subprocess, sys
44
50
 
45
51
  try:
46
52
  data = json.loads(os.environ.get("ACSTACK_HOOK_INPUT", ""))
@@ -53,7 +59,7 @@ if not isinstance(data, dict):
53
59
  if data.get("source") != "compact":
54
60
  sys.exit(0)
55
61
 
56
- active = os.path.join("acstack", "HANDOFF.md")
62
+ active = os.path.join(".acstack", "HANDOFF.md")
57
63
  try:
58
64
  with open(active, encoding="utf-8") as f:
59
65
  raw = f.read()
@@ -115,14 +121,22 @@ if not stamp:
115
121
  # Route to the change's own folder when that change dir exists, so consumed
116
122
  # handoffs travel with the change on /acstack:archive. Otherwise fall back to a
117
123
  # neutral top-level handoffs dir (ad-hoc work, or a change already archived).
118
- change_dir = os.path.join("acstack", "changes", change)
124
+ change_dir = os.path.join(".acstack", "changes", change)
119
125
  if change != "ad-hoc" and os.path.isdir(change_dir):
120
126
  archive_dir = os.path.join(change_dir, "handoffs")
121
127
  else:
122
- archive_dir = os.path.join("acstack", "handoffs", change)
128
+ archive_dir = os.path.join(".acstack", "handoffs", change)
123
129
 
124
130
  # Find a non-colliding destination: <stamp>.md, then <stamp>-2.md, -3.md, ...
125
131
  dest = None
132
+ try:
133
+ subprocess.run([os.environ["ACSTACK_BUNDLED_CLI"], "project-data", "ensure"],
134
+ check=True, stdout=sys.stderr, stderr=sys.stderr)
135
+ if os.environ["ACSTACK_LEGACY_PROJECT_DATA"] == "1":
136
+ raise OSError("Legacy project data found; run ~/.claude/acstack/bin/acstack project-data migrate first")
137
+ except (OSError, subprocess.CalledProcessError) as error:
138
+ print("acstack: project-data ensure failed; ignore policy is not confirmed installed. Leaving the active handoff untouched. " + str(error), file=sys.stderr)
139
+ sys.exit(0)
126
140
  try:
127
141
  os.makedirs(archive_dir, exist_ok=True)
128
142
  candidate = os.path.join(archive_dir, stamp + ".md")
@@ -17,7 +17,7 @@
17
17
  # Both symlinks point at ${CLAUDE_PLUGIN_ROOT}/cli/bin/acstack.js, which is a
18
18
  # tiny node wrapper that loads ../dist/index.js.
19
19
  #
20
- # When a project is initialized (acstack/project.yaml exists), the hook also
20
+ # When a project is initialized (.acstack/project.yaml exists), the hook also
21
21
  # injects the plugin's orchestrator instructions as additionalContext so installs
22
22
  # stay version-agnostic. Otherwise prints a one-line reminder.
23
23
 
@@ -181,7 +181,14 @@ if [ -n "$plugin_root" ]; then
181
181
  esac
182
182
  fi
183
183
 
184
- if [ ! -f acstack/project.yaml ]; then
184
+ # Install the ignore baseline even when setup has not written project.yaml.
185
+ source "${plugin_root}/hooks/project-data.sh"
186
+ project_root=$(acstack_project_root)
187
+ if ! acstack_ensure_project_data "$project_root" "$cli_wrapper"; then
188
+ exit 0
189
+ fi
190
+
191
+ if [ ! -f "$project_root/.acstack/project.yaml" ]; then
185
192
  echo 'acstack: no project config found. Run /acstack:setup to set up.' >&2
186
193
  exit 0
187
194
  fi
@@ -66,7 +66,17 @@ ACStack runs on Claude Code, Codex, and pi. The skills name each capability once
66
66
 
67
67
  ## Project configuration
68
68
 
69
- All project-specific commands and paths come from `acstack/project.yaml`. Read this file before you run any build, test or lint command. If it doesn't exist, prompt the user to run `/acstack:setup`.
69
+ - All ACStack-owned project data lives under `.acstack/` and stays local by default
70
+ - The root `.gitignore` is the sole tracking policy; user exceptions after its managed baseline opt individual parts in
71
+ - Before a configuration gate, CLI and host session startup run `~/.claude/acstack/bin/acstack project-data ensure`
72
+ - When creating `.acstack/` manually, run that command immediately; it needs no project config
73
+ - Filesystem creation alone triggers nothing; the next CLI invocation or session startup enforces the baseline, without a watcher
74
+ - Never force-add ignored project data, change the Git index, or create automatic tracking exceptions
75
+ - For legacy layouts, follow the explicit migration procedure in `docs/config-reference.md`
76
+ - Update installed tools first, stop old agents and reviews, migrate the selected checkout, then restart with updated tools
77
+ - Never silently migrate another checkout or work around legacy data by creating a partial `.acstack/` there
78
+
79
+ All project-specific commands and paths come from `.acstack/project.yaml`. Read this file before you run any build, test or lint command. If it doesn't exist, prompt the user to run `/acstack:setup`.
70
80
 
71
81
  Key fields:
72
82
 
@@ -250,18 +260,19 @@ flowchart TD
250
260
 
251
261
  Spec sync keeps living specs current, whichever workflow you ran. It runs as part of every `/acstack:commit`.
252
262
 
253
- When `workflow.spec_sync` is `true` in `acstack/project.yaml`:
263
+ When `workflow.spec_sync` is `true` in `.acstack/project.yaml`:
254
264
 
255
265
  1. Run `git diff --staged` to see what is changing
256
- 2. Map changed files to spec domains via `acstack/domain-map.yaml`
257
- 3. For each affected domain with a `acstack/specs/[domain]/spec.md`:
266
+ 2. Map changed files to spec domains via `.acstack/domain-map.yaml`
267
+ 3. For each affected domain with a `.acstack/specs/[domain]/spec.md`:
258
268
  - Analyze what the staged changes ADD, MODIFY, or REMOVE
259
269
  - Generate lightweight ADDED/MODIFIED/REMOVED entries
260
270
  - Update the spec.md
261
- 4. Stage updated spec files in the same commit
271
+ 4. Stage updated specs only when native `.gitignore` rules allow tracking
272
+ - Keep ignored specs updated locally; never force-add them or change the Git index to bypass the user's choice
262
273
  5. Flag unmapped source files. Prompt the user to map them.
263
274
 
264
- This is lightweight – retroactive spec documentation, not upfront planning. Specs converge toward reality with every commit.
275
+ Spec sync updates local records with every commit, including when those records stay ignored.
265
276
 
266
277
  ---
267
278
 
@@ -278,9 +289,9 @@ This is lightweight – retroactive spec documentation, not upfront planning. Sp
278
289
 
279
290
  ## Living specs
280
291
 
281
- - `acstack/specs/` contains the cumulative source of truth for the system
292
+ - `.acstack/specs/` contains the cumulative source of truth for the system
282
293
  - `/acstack:commit` updates them automatically through spec sync; `/acstack:archive` closes out a cleared map
283
- - Domain-organized per `acstack/domain-map.yaml`
294
+ - Domain-organized per `.acstack/domain-map.yaml`
284
295
  - Format: Given/When/Then, FR-NNN requirements
285
296
  - Bootstrap from existing codebase: `/acstack:bootstrap`
286
297
  - Map nodes: ACStack CLI (`~/.claude/acstack/bin/acstack node create | read | update | list`, plus the composed `node frontier` and `node walk` queries)
@@ -303,13 +314,13 @@ Read-only reviewers report discrepancies to the completion owner.
303
314
 
304
315
  **Before marking ANY task as complete, you MUST verify the project builds.**
305
316
 
306
- Read `acstack/project.yaml` for the specific commands. The general pattern:
317
+ Read `.acstack/project.yaml` for the specific commands. The general pattern:
307
318
 
308
319
  1. Run the build command if the project configures one
309
320
  2. Run lint
310
321
  3. Run typecheck if the project configures one
311
322
  4. Run the full test suite – ALL tests must pass
312
- 5. Compare the test count against `.test-baseline`. The count must not drop.
323
+ 5. Compare the test count against `.acstack/.test-baseline`. The count must not drop.
313
324
  6. Run the frontend build and lint if the project configures a frontend
314
325
 
315
326
  ### When to run
@@ -329,7 +340,7 @@ Read `acstack/project.yaml` for the specific commands. The general pattern:
329
340
 
330
341
  ## Frontend visual verification
331
342
 
332
- **This section applies only when `acstack/project.yaml` sets `frontend` and `workflow.frontend_verification` is `true`.**
343
+ **This section applies only when `.acstack/project.yaml` sets `frontend` and `workflow.frontend_verification` is `true`.**
333
344
 
334
345
  When a change touches frontend files, delegate real-browser verification to frontend-verifier after required checks pass. Never substitute a confidence claim for browser evidence.
335
346
 
@@ -337,7 +348,7 @@ The design pass runs before browser verification when the design gate is on, fol
337
348
 
338
349
  The frontend-verifier agent:
339
350
 
340
- 1. Reads the project's verification knowledge base (`<helpers_dir>/VERIFICATION-KNOWLEDGE.md`)
351
+ 1. Reads the project's verification knowledge base (`.acstack/verification/VERIFICATION-KNOWLEDGE.md`)
341
352
  2. Checks what frontend files changed
342
353
  3. Starts the dev server if it's not running
343
354
  4. Connects to a browser through the Chrome DevTools Protocol (CDP), over a remote tunnel or local headless Chromium
@@ -350,8 +361,8 @@ The frontend-verifier agent:
350
361
 
351
362
  Run `/acstack:setup` to set up browser verification. This creates:
352
363
 
353
- - **agent-browser.json** – CDP connection config in the project root
354
- - **VERIFICATION-KNOWLEDGE.md** – Evolving knowledge base of element patterns, gotchas, and proven verification sequences
364
+ - **`.acstack/agent-browser.json`** – CDP connection config, selected by an absolute `--config` path or `AGENT_BROWSER_CONFIG`
365
+ - **`.acstack/verification/VERIFICATION-KNOWLEDGE.md`** – Evolving knowledge base of element patterns, gotchas, and proven verification sequences
355
366
 
356
367
  `frontend.browser.mode` in project.yaml holds the browser environment: remote, headless, or local.
357
368