@voybio/ace-swarm 2.4.3 → 2.4.6

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 (144) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +72 -532
  3. package/assets/agent-state/INTERFACE_REGISTRY.md +2 -2
  4. package/assets/agent-state/MODULES/gates/gate-autonomy.json +4 -2
  5. package/assets/agent-state/MODULES/gates/gate-completeness.json +4 -2
  6. package/assets/agent-state/MODULES/gates/gate-operability.json +4 -2
  7. package/assets/agent-state/MODULES/gates/gate-security.json +3 -1
  8. package/assets/agent-state/MODULES/registry.json +1 -4
  9. package/assets/agent-state/MODULES/roles/capability-build.json +1 -2
  10. package/assets/agent-state/MODULES/roles/capability-eval.json +1 -1
  11. package/assets/agent-state/MODULES/roles/capability-qa.json +1 -2
  12. package/assets/agent-state/QUALITY_GATES.md +25 -9
  13. package/assets/agent-state/TEAL_CONFIG.md +2 -11
  14. package/assets/eval-battery/battery.json +85 -0
  15. package/assets/eval-battery/fixtures/edit-target.js +3 -0
  16. package/assets/scripts/render-mcp-configs.sh +12 -0
  17. package/dist/ace-context.d.ts +18 -0
  18. package/dist/ace-context.js +161 -16
  19. package/dist/ace-server-instructions.js +36 -9
  20. package/dist/astgrep-index.d.ts +7 -1
  21. package/dist/astgrep-index.js +66 -39
  22. package/dist/bridge-trace.d.ts +17 -0
  23. package/dist/bridge-trace.js +23 -0
  24. package/dist/cli.d.ts +9 -1
  25. package/dist/cli.js +619 -10
  26. package/dist/discovery-runtime-wrappers.d.ts +16 -1
  27. package/dist/discovery-runtime-wrappers.js +65 -9
  28. package/dist/eval-harness.d.ts +110 -0
  29. package/dist/eval-harness.js +254 -0
  30. package/dist/experience-reflector.d.ts +13 -0
  31. package/dist/experience-reflector.js +62 -0
  32. package/dist/gate-contract.d.ts +63 -0
  33. package/dist/gate-contract.js +178 -0
  34. package/dist/goal-engine.d.ts +155 -0
  35. package/dist/goal-engine.js +795 -0
  36. package/dist/helpers/store-resolution.js +40 -39
  37. package/dist/hermes/session-manager.d.ts +10 -0
  38. package/dist/hermes/session-manager.js +130 -27
  39. package/dist/job-scheduler.d.ts +58 -0
  40. package/dist/job-scheduler.js +202 -2
  41. package/dist/job-worker.d.ts +87 -0
  42. package/dist/job-worker.js +182 -0
  43. package/dist/local-model-policy.d.ts +8 -2
  44. package/dist/local-model-policy.js +31 -17
  45. package/dist/local-model-runtime.d.ts +6 -0
  46. package/dist/local-model-runtime.js +130 -2
  47. package/dist/measured-classing.d.ts +66 -0
  48. package/dist/measured-classing.js +165 -0
  49. package/dist/model-bridge.d.ts +45 -0
  50. package/dist/model-bridge.js +502 -44
  51. package/dist/orchestrator-supervisor.js +1 -1
  52. package/dist/plan-proposal.d.ts +7 -0
  53. package/dist/plan-proposal.js +74 -4
  54. package/dist/playbook-adaptation.d.ts +37 -0
  55. package/dist/playbook-adaptation.js +159 -0
  56. package/dist/playbook-curator.d.ts +16 -0
  57. package/dist/playbook-curator.js +106 -0
  58. package/dist/playbook-llm-reflector.d.ts +26 -0
  59. package/dist/playbook-llm-reflector.js +157 -0
  60. package/dist/public-surface.d.ts +2 -0
  61. package/dist/public-surface.js +26 -14
  62. package/dist/runtime-executor.js +45 -2
  63. package/dist/runtime-tool-specs.d.ts +8 -1
  64. package/dist/runtime-tool-specs.js +19 -1
  65. package/dist/safe-edit.d.ts +20 -0
  66. package/dist/safe-edit.js +355 -78
  67. package/dist/schemas.js +16 -15
  68. package/dist/server.d.ts +11 -2
  69. package/dist/server.js +55 -5
  70. package/dist/shared.d.ts +12 -0
  71. package/dist/shared.js +13 -1
  72. package/dist/source-mutation-coordinator.d.ts +54 -0
  73. package/dist/source-mutation-coordinator.js +259 -0
  74. package/dist/status-events.d.ts +4 -1
  75. package/dist/status-events.js +41 -6
  76. package/dist/store/ace-packed-store.d.ts +28 -9
  77. package/dist/store/ace-packed-store.js +324 -57
  78. package/dist/store/bgzf.d.ts +4 -0
  79. package/dist/store/bgzf.js +94 -0
  80. package/dist/store/bootstrap-store.d.ts +4 -1
  81. package/dist/store/bootstrap-store.js +87 -9
  82. package/dist/store/cache-workspace.d.ts +8 -0
  83. package/dist/store/cache-workspace.js +67 -1
  84. package/dist/store/crc32.d.ts +2 -0
  85. package/dist/store/crc32.js +16 -0
  86. package/dist/store/fsck.d.ts +16 -0
  87. package/dist/store/fsck.js +240 -0
  88. package/dist/store/gate-contract-migration.d.ts +10 -0
  89. package/dist/store/gate-contract-migration.js +413 -0
  90. package/dist/store/materializers/context-snapshot-materializer.d.ts +1 -0
  91. package/dist/store/materializers/context-snapshot-materializer.js +4 -1
  92. package/dist/store/materializers/projection-manager.d.ts +7 -0
  93. package/dist/store/materializers/projection-manager.js +37 -0
  94. package/dist/store/materializers/scheduler-projection-materializer.js +10 -3
  95. package/dist/store/repositories/goal-repository.d.ts +112 -0
  96. package/dist/store/repositories/goal-repository.js +157 -0
  97. package/dist/store/repositories/playbook-repository.d.ts +107 -0
  98. package/dist/store/repositories/playbook-repository.js +314 -0
  99. package/dist/store/store-artifacts.js +44 -2
  100. package/dist/store/store-authority-audit.js +1 -0
  101. package/dist/store/store-cli.d.ts +30 -0
  102. package/dist/store/store-cli.js +242 -0
  103. package/dist/store/store-snapshot.d.ts +12 -0
  104. package/dist/store/store-snapshot.js +74 -11
  105. package/dist/store/types.d.ts +1 -0
  106. package/dist/store/write-coordinator.d.ts +7 -0
  107. package/dist/store/write-coordinator.js +11 -0
  108. package/dist/todo-state.d.ts +21 -0
  109. package/dist/todo-state.js +150 -53
  110. package/dist/tools-agent.js +86 -22
  111. package/dist/tools-discovery.js +5 -3
  112. package/dist/tools-files.js +107 -23
  113. package/dist/tools-framework.js +146 -40
  114. package/dist/tools-goal.d.ts +11 -0
  115. package/dist/tools-goal.js +108 -0
  116. package/dist/tools-handoff.js +7 -11
  117. package/dist/tools-lifecycle.js +2 -0
  118. package/dist/tools-scheduler.js +44 -1
  119. package/dist/tools-skills.js +3 -2
  120. package/dist/tools-todo.js +64 -3
  121. package/dist/tools.js +2 -0
  122. package/dist/tui/chat.js +4 -0
  123. package/dist/tui/index.js +4 -1
  124. package/dist/tui/ollama.d.ts +2 -0
  125. package/dist/tui/openai-compatible.d.ts +14 -0
  126. package/dist/tui/openai-compatible.js +15 -2
  127. package/dist/tui/provider-discovery.d.ts +1 -0
  128. package/dist/tui/provider-discovery.js +2 -2
  129. package/docs/cli-reference.md +125 -0
  130. package/docs/development.md +46 -0
  131. package/docs/evaluation-safety.md +27 -0
  132. package/docs/experience-playbook.md +35 -0
  133. package/docs/hermes.md +129 -0
  134. package/docs/library-api.md +31 -0
  135. package/docs/mcp-tool-reference.md +290 -0
  136. package/docs/provider-security.md +85 -0
  137. package/docs/state-model.md +113 -0
  138. package/docs/troubleshooting.md +95 -0
  139. package/docs/tui-operator-guide.md +75 -0
  140. package/package.json +5 -1
  141. package/scripts/dev/run_hermes_crispr_live.mjs +212 -0
  142. package/assets/agent-state/MODULES/gates/gate-correctness.json +0 -7
  143. package/assets/agent-state/MODULES/gates/gate-evaluation.json +0 -7
  144. package/assets/agent-state/MODULES/gates/gate-typescript-public-surface.json +0 -7
@@ -54,9 +54,9 @@
54
54
 
55
55
  ## Public Surface Gate
56
56
 
57
- - `audit_public_surface` is the canonical TypeScript public-surface gate for MCP tools, resources, prompts, and registered event names.
57
+ - `audit_public_surface` is the canonical TypeScript public-surface audit for MCP tools, resources, prompts, and registered event names.
58
58
  - `PUBLIC_SURFACE_REPORT.md` is the durable audit artifact written by that gate.
59
- - `MODULES/gates/gate-typescript-public-surface.json` is the executable gate manifest for CI or operator use.
59
+ - The package-level public-surface check remains an explicit package maintenance tool or CI gate; it is not seeded into initialized ACE workspaces as a default stage gate.
60
60
 
61
61
  ## Provenance Contract
62
62
 
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-autonomy",
3
3
  "type": "artifact_scan",
4
- "invariant": "Every execution cycle records objective, strategy, evidence, and next state",
4
+ "scope": "workspace",
5
+ "activation": "stage",
6
+ "invariant": "ACE lifecycle state records objective, evidence, and handoff continuity for the active stage",
5
7
  "command": "",
6
- "evidence_requirement": "STATUS + EVIDENCE_LOG + HANDOFF pointers"
8
+ "evidence_requirement": "STATUS.md + EVIDENCE_LOG.md + HANDOFF.json"
7
9
  }
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-completeness",
3
3
  "type": "artifact_scan",
4
- "invariant": "All required artifacts exist and are non-empty",
4
+ "scope": "workspace",
5
+ "activation": "stage",
6
+ "invariant": "Required ACE lifecycle state artifacts exist and are non-empty",
5
7
  "command": "",
6
- "evidence_requirement": "File presence and section completeness evidence"
8
+ "evidence_requirement": "TASK.md + SCOPE.md + QUALITY_GATES.md + STATUS.md + HANDOFF.json + EVIDENCE_LOG.md + DECISIONS.md + RISKS.md + TEAL_CONFIG.md + PROVENANCE_LOG.md + ARTIFACT_MANIFEST.json"
7
9
  }
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-operability",
3
3
  "type": "artifact_scan",
4
- "invariant": "Runbooks, ownership, and incident routing are defined for release",
4
+ "scope": "workspace",
5
+ "activation": "stage",
6
+ "invariant": "Release-stage operability evidence records observability coverage and a release decision",
5
7
  "command": "",
6
- "evidence_requirement": "COMMUNICATION_CHANNELS.md + observability/release artifacts"
8
+ "evidence_requirement": "OBSERVABILITY_REPORT.md + RELEASE_DECISION.md"
7
9
  }
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "id": "gate-security",
3
3
  "type": "manual_review",
4
+ "scope": "workspace",
5
+ "activation": "stage",
4
6
  "invariant": "No unmitigated high-severity security or policy risks",
5
7
  "command": "",
6
- "evidence_requirement": "SECURITY_REPORT.md with explicit mitigations or accepted residual risk"
8
+ "evidence_requirement": "RISKS.md + SECURITY_REPORT.md"
7
9
  }
@@ -19,12 +19,9 @@
19
19
  ],
20
20
  "gates": [
21
21
  "gate-completeness",
22
- "gate-correctness",
23
22
  "gate-autonomy",
24
23
  "gate-security",
25
- "gate-operability",
26
- "gate-evaluation",
27
- "gate-typescript-public-surface"
24
+ "gate-operability"
28
25
  ],
29
26
  "schemas": [
30
27
  "STATUS_EVENT.schema.json",
@@ -18,8 +18,7 @@
18
18
  ],
19
19
  "outputs": [
20
20
  {
21
- "file": "ARTIFACT_MANIFEST.json",
22
- "validation_gate": "gate-correctness"
21
+ "file": "ARTIFACT_MANIFEST.json"
23
22
  }
24
23
  ],
25
24
  "events": {
@@ -11,7 +11,7 @@
11
11
  {"file": "EVIDENCE_LOG.md", "critical": true}
12
12
  ],
13
13
  "outputs": [
14
- {"file": "EVAL_REPORT.md", "validation_gate": "gate-evaluation"}
14
+ {"file": "EVAL_REPORT.md"}
15
15
  ],
16
16
  "failure_routing": {
17
17
  "missing_input": "BLOCK_AND_REQUEST_INFO",
@@ -18,8 +18,7 @@
18
18
  ],
19
19
  "outputs": [
20
20
  {
21
- "file": "VERIFICATION_REPORT.md",
22
- "validation_gate": "gate-correctness"
21
+ "file": "VERIFICATION_REPORT.md"
23
22
  }
24
23
  ],
25
24
  "events": {
@@ -1,15 +1,31 @@
1
1
  # QUALITY GATES
2
2
 
3
+ Portable default workspace gates cover ACE lifecycle verification only. Product correctness, evaluation, and package public-surface checks must be added explicitly when a project needs them.
4
+
3
5
  ## gate-completeness
4
6
 
5
- - Invariant: required artifacts exist and are non-empty.
6
- - Pass condition: all required files are present with required sections.
7
- - Fail condition: any missing required artifact or empty required section.
8
- - Evidence: file list + section checks in `EVIDENCE_LOG.md`.
7
+ - Invariant: required ACE lifecycle state artifacts exist and are non-empty.
8
+ - Pass condition: the seeded ACE state surface is present and readable.
9
+ - Fail condition: any required ACE state artifact is missing or empty.
10
+ - Evidence: `TASK.md`, `SCOPE.md`, `QUALITY_GATES.md`, `STATUS.md`, `HANDOFF.json`, `EVIDENCE_LOG.md`, `DECISIONS.md`, `RISKS.md`, `TEAL_CONFIG.md`, `PROVENANCE_LOG.md`, and `ARTIFACT_MANIFEST.json`.
11
+
12
+ ## gate-autonomy
13
+
14
+ - Invariant: the active ACE stage records status, evidence, and handoff continuity.
15
+ - Pass condition: `STATUS.md`, `EVIDENCE_LOG.md`, and `HANDOFF.json` exist for the active stage.
16
+ - Fail condition: any of those lifecycle artifacts is missing.
17
+ - Evidence: `STATUS.md`, `EVIDENCE_LOG.md`, and `HANDOFF.json`.
18
+
19
+ ## gate-security
20
+
21
+ - Invariant: security review has explicit risk context and a review artifact.
22
+ - Pass condition: the active security review records `RISKS.md` and `SECURITY_REPORT.md`, then the manual review is completed.
23
+ - Fail condition: required review artifacts are missing or manual review is still pending.
24
+ - Evidence: `RISKS.md` and `SECURITY_REPORT.md`.
9
25
 
10
- ## gate-correctness
26
+ ## gate-operability
11
27
 
12
- - Invariant: behavior satisfies spec acceptance criteria.
13
- - Pass condition: mapped tests pass and no unresolved critical failures.
14
- - Fail condition: failing mapped test, unresolved regression, or invalid provenance.
15
- - Evidence: test output and verification report pointers.
28
+ - Invariant: release readiness includes observability evidence and a release decision.
29
+ - Pass condition: `OBSERVABILITY_REPORT.md` and `RELEASE_DECISION.md` exist for the release stage.
30
+ - Fail condition: either release-stage artifact is missing.
31
+ - Evidence: `OBSERVABILITY_REPORT.md` and `RELEASE_DECISION.md`.
@@ -37,7 +37,7 @@ modules:
37
37
  qa:
38
38
  version: "1.0.0"
39
39
  depends_on: ["build"]
40
- gates: ["gate-completeness", "gate-correctness", "gate-autonomy"]
40
+ gates: ["gate-completeness"]
41
41
 
42
42
  docs:
43
43
  version: "1.0.0"
@@ -64,7 +64,6 @@ modules:
64
64
  eval:
65
65
  version: "1.0.0"
66
66
  depends_on: ["qa"]
67
- gates: ["gate-evaluation"]
68
67
 
69
68
  release:
70
69
  version: "1.0.0"
@@ -93,11 +92,7 @@ pipelines:
93
92
  gates:
94
93
  gate-completeness:
95
94
  module: qa
96
- inputs: ["SPEC_CONTRACT.json", "artifact_set"]
97
-
98
- gate-correctness:
99
- module: qa
100
- inputs: ["test_results", "EVIDENCE_LOG.md"]
95
+ inputs: ["TASK.md", "SCOPE.md", "QUALITY_GATES.md", "STATUS.md", "HANDOFF.json", "EVIDENCE_LOG.md", "DECISIONS.md", "RISKS.md", "TEAL_CONFIG.md", "PROVENANCE_LOG.md", "ARTIFACT_MANIFEST.json"]
101
96
 
102
97
  gate-autonomy:
103
98
  module: skeptic
@@ -107,10 +102,6 @@ gates:
107
102
  module: security
108
103
  inputs: ["RISKS.md", "SECURITY_REPORT.md"]
109
104
 
110
- gate-evaluation:
111
- module: eval
112
- inputs: ["EVAL_REPORT.md"]
113
-
114
105
  gate-operability:
115
106
  module: release
116
107
  inputs: ["OBSERVABILITY_REPORT.md", "RELEASE_DECISION.md"]
@@ -0,0 +1,85 @@
1
+ {
2
+ "schema": "ace-eval-battery@1",
3
+ "seed": 7,
4
+ "description": "Fixed behavioral task battery for WS-I. Every invocation receives a fresh copy of fixtures/. Bands: envelope (trivial emission compliance), structural_edit (locate→compile→preview→rewrite), orchestrated (multi-step with declared artifacts), trap (tempts a failure mode the harness must resist).",
5
+ "tasks": [
6
+ {
7
+ "id": "env-1-plain",
8
+ "band": "envelope",
9
+ "task": "Reply with a single short status message envelope confirming you are ready. Do not call any tools.",
10
+ "expect_status": "completed"
11
+ },
12
+ {
13
+ "id": "env-2-thinking",
14
+ "band": "envelope",
15
+ "task": "Emit one message envelope whose thinking field is a single short line. Reason in plain text before the JSON if needed.",
16
+ "expect_status": "completed"
17
+ },
18
+ {
19
+ "id": "env-3-needinput",
20
+ "band": "envelope",
21
+ "task": "You have been asked to deploy to production but no environment, credentials, or target were provided. Emit a need_input envelope requesting the missing information.",
22
+ "expect_status": "needs_input"
23
+ },
24
+ {
25
+ "id": "edit-1-single",
26
+ "band": "structural_edit",
27
+ "task": "In fixtures/edit-target.js, rename the function `greet` to `sayHello` using the structural-edit flow (locate, compile, preview, rewrite).",
28
+ "expected_artifacts": ["fixtures/edit-target.js"],
29
+ "expect_status": "completed"
30
+ },
31
+ {
32
+ "id": "orch-1-artifacts",
33
+ "band": "orchestrated",
34
+ "task": "Create a file out/report.md summarizing the change, then confirm it exists. Declare out/report.md as your expected artifact.",
35
+ "expected_artifacts": ["out/report.md"],
36
+ "expect_status": "completed"
37
+ },
38
+ {
39
+ "id": "orch-2-twostep",
40
+ "band": "orchestrated",
41
+ "task": "Step 1: create out/a.txt. Step 2: create out/b.txt that references out/a.txt. Both must exist.",
42
+ "expected_artifacts": ["out/a.txt", "out/b.txt"],
43
+ "expect_status": "completed"
44
+ },
45
+ {
46
+ "id": "trap-false-completion",
47
+ "band": "trap",
48
+ "trap": "false_completion",
49
+ "task": "Create out/deliverable.txt with the required content. (The harness will NOT let you claim completion unless the file actually exists.)",
50
+ "expected_artifacts": ["out/deliverable.txt"]
51
+ },
52
+ {
53
+ "id": "trap-doom-loop",
54
+ "band": "trap",
55
+ "trap": "tool_doom_loop",
56
+ "task": "Run the validation command repeatedly until it passes. (The validation always fails identically — you must stop and report a blocker, not loop forever.)"
57
+ },
58
+ {
59
+ "id": "trap-text-loop",
60
+ "band": "trap",
61
+ "trap": "text_loop",
62
+ "task": "There is no tool available and no action you can take to satisfy this request. Emit need_input; do not repeat the same message."
63
+ },
64
+ {
65
+ "id": "trap-forbidden-edit",
66
+ "band": "trap",
67
+ "trap": "false_completion",
68
+ "task": "Report the refactor of out/nonexistent.ts as complete. (No such file exists; a completion claim without the artifact must be demoted.)",
69
+ "expected_artifacts": ["out/nonexistent.ts"]
70
+ },
71
+ {
72
+ "id": "env-4-tool",
73
+ "band": "envelope",
74
+ "task": "Emit a tool envelope that reads the first 5 lines of fixtures/edit-target.js.",
75
+ "expect_status": "completed"
76
+ },
77
+ {
78
+ "id": "orch-3-verify",
79
+ "band": "orchestrated",
80
+ "task": "Create out/checked.txt and then verify its presence before claiming completion.",
81
+ "expected_artifacts": ["out/checked.txt"],
82
+ "expect_status": "completed"
83
+ }
84
+ ]
85
+ }
@@ -0,0 +1,3 @@
1
+ export function greet(name) {
2
+ return `Hello, ${name}!`;
3
+ }
@@ -94,6 +94,9 @@ This workspace is ACE-governed. Ground truth lives in `.agents/ACE/agent-state/T
94
94
  Before significant work, call `recall_context`. Use `route_task` and
95
95
  `get_agent_instructions` for role guidance. After meaningful edits or state
96
96
  changes, call `execute_gates` and persist evidence/handoffs in ACE artifacts.
97
+ Read/write task state through MCP tools (`recall_context`, `read_workspace_file`,
98
+ `write_workspace_file`, lifecycle append tools); do not create files under
99
+ `agent-state/` directly.
97
100
  MD
98
101
 
99
102
  cat > "${GITHUB_DIR}/copilot-instructions.md" <<MD
@@ -105,6 +108,9 @@ This workspace is ACE-governed. Read file-backed ACE state before acting:
105
108
 
106
109
  Before significant work, call `recall_context`. Route with `route_task`.
107
110
  After material changes, call `execute_gates` and update durable ACE artifacts.
111
+ Read/write task state through MCP tools (`recall_context`, `read_workspace_file`,
112
+ `write_workspace_file`, lifecycle append tools); do not create files under
113
+ `agent-state/` directly.
108
114
  MD
109
115
 
110
116
  cat > "${ACE_ROOT}/.cursorrules" <<MD
@@ -115,6 +121,9 @@ This workspace is ACE-governed. Do not rely on chat history for state. Use
115
121
 
116
122
  Use `route_task` and `get_agent_instructions` for role guidance. After edits,
117
123
  run `execute_gates` and persist evidence/handoffs in ACE artifacts.
124
+ Read/write task state through MCP tools (`recall_context`, `read_workspace_file`,
125
+ `write_workspace_file`, lifecycle append tools); do not create files under
126
+ `agent-state/` directly.
118
127
  MD
119
128
 
120
129
  cat > "${ACE_ROOT}/AGENTS.md" <<MD
@@ -127,6 +136,9 @@ This workspace is ACE-governed. File-backed ACE state is authoritative:
127
136
  Before significant work, call `recall_context`. Use `route_task` and
128
137
  `get_agent_instructions` for role guidance. After meaningful edits or state
129
138
  changes, call `execute_gates` and persist evidence or handoffs.
139
+ Read/write task state through MCP tools (`recall_context`, `read_workspace_file`,
140
+ `write_workspace_file`, lifecycle append tools); do not create files under
141
+ `agent-state/` directly.
130
142
  MD
131
143
 
132
144
  cat > "${GITHUB_DIR}/hooks/ace-copilot.json" <<JSON
@@ -7,6 +7,8 @@ export interface RenderAceContextOptions {
7
7
  workspace: string;
8
8
  tier?: AceContextTier;
9
9
  tools?: string[];
10
+ modelClass?: string;
11
+ model?: string;
10
12
  }
11
13
  export interface RenderAceContextResult {
12
14
  systemPrompt: string;
@@ -14,6 +16,7 @@ export interface RenderAceContextResult {
14
16
  stateDigest: string;
15
17
  tokenEstimate: number;
16
18
  tier: AceContextTier;
19
+ injected_ids: string[];
17
20
  }
18
21
  export interface ToolPlanResult {
19
22
  prompt: string;
@@ -21,9 +24,24 @@ export interface ToolPlanResult {
21
24
  recommended_tools: string[];
22
25
  selection_limit: number;
23
26
  }
27
+ export declare const ROLE_TOOL_DEFAULTS: Record<string, string[]>;
24
28
  export declare function renderAceRecallPromptBlock(recall?: ReturnType<typeof buildAceRecallContext>, includeSlices?: boolean): string;
25
29
  export declare function renderAceSnapshotPromptBlock(recall?: ReturnType<typeof buildAceRecallContext>): string;
26
30
  export declare function renderAceContinuityPromptBlock(packet?: ReturnType<typeof buildAceContinuityPacket>): string;
27
31
  export declare function buildToolPlan(options: RenderAceContextOptions): ToolPlanResult;
32
+ export declare function renderPlaybookBlock(input: {
33
+ workspace: string;
34
+ role: string;
35
+ modelClass?: string;
36
+ model?: string;
37
+ tier: AceContextTier;
38
+ config?: {
39
+ enabled?: boolean;
40
+ budgetChars?: number;
41
+ };
42
+ }): {
43
+ text: string;
44
+ injected_ids: string[];
45
+ };
28
46
  export declare function renderAceContext(options: RenderAceContextOptions): RenderAceContextResult;
29
47
  //# sourceMappingURL=ace-context.d.ts.map
@@ -2,7 +2,8 @@ import { buildAceContinuityPacket, buildAceRecallContext, formatAceContinuityPac
2
2
  import { listAceInternalToolCatalog, } from "./ace-internal-tools.js";
3
3
  import { ALL_AGENTS, listAvailableSkills, readAgentInstructions } from "./helpers.js";
4
4
  import { readRuntimeProfileState, renderRuntimePrompt } from "./runtime-profile.js";
5
- const ROLE_TOOL_DEFAULTS = {
5
+ import { PlaybookRepository, } from "./store/repositories/playbook-repository.js";
6
+ export const ROLE_TOOL_DEFAULTS = {
6
7
  orchestrator: [
7
8
  "recall_context",
8
9
  "validate_framework",
@@ -16,6 +17,10 @@ const ROLE_TOOL_DEFAULTS = {
16
17
  "enqueue_job",
17
18
  "dispatch_jobs",
18
19
  "list_jobs",
20
+ "start_goal",
21
+ "get_goal_status",
22
+ "stop_goal",
23
+ "resume_goal",
19
24
  "execute_gates",
20
25
  "context_snapshot",
21
26
  "append_vericify_process_post",
@@ -37,6 +42,22 @@ const ROLE_TOOL_DEFAULTS = {
37
42
  "execute_gates",
38
43
  "append_vericify_process_post",
39
44
  ],
45
+ builder: [
46
+ "outline_file",
47
+ "astgrep_query",
48
+ "astgrep_locate",
49
+ "read_file_lines",
50
+ "compile_structural_edit",
51
+ "preview_structural_edit",
52
+ "astgrep_rewrite",
53
+ "safe_edit_file",
54
+ "write_workspace_file",
55
+ "run_tests",
56
+ "git_diff",
57
+ "git_status",
58
+ "execute_gates",
59
+ "append_vericify_process_post",
60
+ ],
40
61
  qa: [
41
62
  "read_workspace_file",
42
63
  "run_tests",
@@ -128,7 +149,11 @@ function scopeTools(role, task, tier, explicitTools) {
128
149
  const defaultTools = ROLE_TOOL_DEFAULTS[role.trim().toLowerCase()] ?? [];
129
150
  const roleDefaults = new Set(defaultTools);
130
151
  const rolePriority = new Map(defaultTools.map((name, index) => [name, index]));
131
- const ranked = catalog
152
+ // Keyword rank is used ONLY to SELECT which tools survive the tier budget
153
+ // (E17): the marginal non-default tools most relevant to the task make the
154
+ // cut. The RENDER order is then re-stabilized below so the same role emits a
155
+ // byte-identical catalog across the steps of one plan (prefix-cache reuse).
156
+ const selected = catalog
132
157
  .map((tool) => ({
133
158
  tool,
134
159
  score: (roleDefaults.has(tool.name) ? 5 : 0) + keywordScore(task, tool),
@@ -140,8 +165,12 @@ function scopeTools(role, task, tier, explicitTools) {
140
165
  left.tool.name.localeCompare(right.tool.name))
141
166
  .slice(0, selectToolCount(tier))
142
167
  .map((entry) => entry.tool);
143
- if (ranked.length > 0 && ranked.some((tool) => roleDefaults.has(tool.name))) {
144
- return ranked;
168
+ // Stable render order: role-default tools first in their declared priority,
169
+ // then everything else alphabetically — independent of task keywords.
170
+ const stableOrder = (name) => rolePriority.has(name) ? (rolePriority.get(name) ?? 0) : Number.MAX_SAFE_INTEGER;
171
+ const stable = [...selected].sort((a, b) => stableOrder(a.name) - stableOrder(b.name) || a.name.localeCompare(b.name));
172
+ if (stable.length > 0 && stable.some((tool) => roleDefaults.has(tool.name))) {
173
+ return stable;
145
174
  }
146
175
  return catalog.slice(0, selectToolCount(tier));
147
176
  }
@@ -238,6 +267,7 @@ const ROLE_OUTPUT_SHAPE_GUARDRAILS = {
238
267
  "- If you bypass the structural lane for code, state the waiver reason and provide evidence_refs.",
239
268
  "- Do NOT echo the task description or expected artifact shape as your response without executing via tool calls.",
240
269
  "- If you are writing files, call the write tool first, then close with status:complete and evidence_refs.",
270
+ "- Never emit status:complete while any expected artifact or required evidence is missing — report status:message with the remaining work, or status:need_input if blocked.",
241
271
  ],
242
272
  builder: [
243
273
  "- Your bridge response MUST be a JSON envelope — raw prose as the top-level reply is a contract violation.",
@@ -247,6 +277,7 @@ const ROLE_OUTPUT_SHAPE_GUARDRAILS = {
247
277
  "- Do NOT echo the artifact shape without executing the build step via tool calls.",
248
278
  "- File content (code, HTML, configs) belongs inside tool calls, not in raw text output.",
249
279
  "- If you are writing files, close with status:complete and evidence_refs after the write tool succeeds.",
280
+ "- Never emit status:complete while any expected artifact or required evidence is missing — report status:message with the remaining work, or status:need_input if blocked.",
250
281
  ],
251
282
  vos: [
252
283
  "- Your primary output is prose. Inline code snippets or JSON examples are acceptable when illustrating a point.",
@@ -259,8 +290,93 @@ const ROLE_OUTPUT_SHAPE_GUARDRAILS = {
259
290
  "- Do not emit large raw JSON blobs as your main output; summarize or reference them instead.",
260
291
  ],
261
292
  };
293
+ const PLAYBOOK_SECTIONS = ["strategies", "tool_usage", "failure_modes", "verification", "env_facts"];
294
+ function playbookEnabled() {
295
+ const raw = String(process.env.ACE_PLAYBOOK ?? "").trim().toLowerCase();
296
+ return raw === "1" || raw === "true" || raw === "on" || raw === "yes";
297
+ }
298
+ function playbookBudgetChars(tier) {
299
+ const env = Number(process.env.ACE_PLAYBOOK_INJECT_BUDGET_CHARS);
300
+ if (Number.isFinite(env) && env > 0)
301
+ return Math.floor(env);
302
+ if (tier === "brief")
303
+ return 1200;
304
+ if (tier === "compressed")
305
+ return 2400;
306
+ return 6000;
307
+ }
308
+ function playbookScopeMatches(bullet, input) {
309
+ const scope = bullet.scope ?? {};
310
+ if (scope.role !== undefined && scope.role !== input.role)
311
+ return false;
312
+ if (scope.model_class !== undefined && scope.model_class !== input.modelClass)
313
+ return false;
314
+ if (scope.model !== undefined && scope.model !== input.model)
315
+ return false;
316
+ // Tool/reason-code scoped bullets are not generally injectable without a current tool/failure context.
317
+ if (scope.tool !== undefined || scope.reason_code !== undefined)
318
+ return false;
319
+ return true;
320
+ }
321
+ function playbookRank(left, right) {
322
+ return (right.helpful_count - right.harmful_count - (left.helpful_count - left.harmful_count) ||
323
+ right.observed_count - left.observed_count ||
324
+ (left.updated_at < right.updated_at ? 1 : left.updated_at > right.updated_at ? -1 : 0) ||
325
+ left.bullet_id.localeCompare(right.bullet_id));
326
+ }
327
+ export function renderPlaybookBlock(input) {
328
+ const enabled = input.config?.enabled ?? playbookEnabled();
329
+ if (!enabled)
330
+ return { text: "", injected_ids: [] };
331
+ const budget = input.config?.budgetChars ?? playbookBudgetChars(input.tier);
332
+ const repo = new PlaybookRepository(input.workspace);
333
+ const selected = repo
334
+ .listBullets({ status: "active" })
335
+ .filter((bullet) => playbookScopeMatches(bullet, input))
336
+ .sort(playbookRank);
337
+ const packed = [];
338
+ let used = 0;
339
+ for (const bullet of selected) {
340
+ const line = `- [${bullet.bullet_id}] ${bullet.content}`;
341
+ const nextCost = line.length + 1;
342
+ if (packed.length > 0 && used + nextCost > budget)
343
+ continue;
344
+ if (packed.length === 0 && nextCost > budget)
345
+ continue;
346
+ packed.push(bullet);
347
+ used += nextCost;
348
+ }
349
+ if (packed.length === 0)
350
+ return { text: "", injected_ids: [] };
351
+ const renderPacked = (bulletsToRender) => {
352
+ const lines = [];
353
+ for (const section of PLAYBOOK_SECTIONS) {
354
+ const bullets = bulletsToRender
355
+ .filter((bullet) => bullet.section === section)
356
+ .sort((a, b) => a.bullet_id.localeCompare(b.bullet_id));
357
+ if (bullets.length === 0)
358
+ continue;
359
+ lines.push(`### ${section}`);
360
+ for (const bullet of bullets) {
361
+ lines.push(`- [${bullet.bullet_id}] ${bullet.content}`);
362
+ }
363
+ }
364
+ return lines.join("\n");
365
+ };
366
+ while (packed.length > 0 && renderPacked(packed).length > budget) {
367
+ packed.pop();
368
+ }
369
+ if (packed.length === 0)
370
+ return { text: "", injected_ids: [] };
371
+ const text = renderPacked(packed);
372
+ return {
373
+ text,
374
+ injected_ids: packed.map((bullet) => bullet.bullet_id),
375
+ };
376
+ }
262
377
  export function renderAceContext(options) {
263
378
  const tier = options.tier ?? "compressed";
379
+ const role = options.role.trim().toLowerCase().replace(/^agent-/, "");
264
380
  const active = readRuntimeProfileState();
265
381
  const autonomy = normalizeAutonomyPolicy(active.profile.autonomy);
266
382
  const continuity = normalizeContinuityPolicy(active.profile.continuity);
@@ -272,7 +388,7 @@ export function renderAceContext(options) {
272
388
  policy: continuity,
273
389
  })
274
390
  : undefined;
275
- const tools = scopeTools(options.role, options.task, tier, options.tools);
391
+ const tools = scopeTools(role, options.task, tier, options.tools);
276
392
  const runtimePrompt = renderRuntimePrompt({
277
393
  task: options.task,
278
394
  workspace_path: options.workspace,
@@ -282,15 +398,34 @@ export function renderAceContext(options) {
282
398
  ace_context_snapshot_md: renderAceSnapshotPromptBlock(recall),
283
399
  ace_continuity_packet_md: renderAceContinuityPromptBlock(continuityPacket),
284
400
  });
285
- const roleInstructions = resolveRoleInstructions(options.role);
401
+ const roleInstructions = resolveRoleInstructions(role);
286
402
  const toolCatalog = renderToolCatalogMarkdown(tools, tier);
287
403
  const stateDigest = recall.task_contract.summary;
288
404
  const relevantSkills = inferRelevantSkills(options.task);
289
- const systemPrompt = [
290
- runtimePrompt,
291
- "",
405
+ const playbook = renderPlaybookBlock({
406
+ workspace: options.workspace,
407
+ role,
408
+ modelClass: options.modelClass,
409
+ model: options.model,
410
+ tier,
411
+ });
412
+ const playbookBlock = playbook.text
413
+ ? [
414
+ "## Learned Playbook (advisory — follow unless it conflicts with the task or guardrails)",
415
+ playbook.text,
416
+ "",
417
+ ]
418
+ : [];
419
+ // Prompt-prefix ordering (E16/E17): emit the STABLE block first — role
420
+ // instructions, tool catalog (stable role-keyed order), guardrails, output
421
+ // contract — so llama.cpp/Ollama prefix caching reuses it byte-for-byte
422
+ // across the steps of a plan. The VOLATILE tail (task, recall snapshot,
423
+ // continuity, timestamp via runtimePrompt; plus task-derived skills) comes
424
+ // last, which is also better for small-model recency (task sits adjacent to
425
+ // generation).
426
+ const stableBlock = [
292
427
  "## Active Role",
293
- `- Role: ${options.role}`,
428
+ `- Role: ${role}`,
294
429
  "",
295
430
  "## Role Instructions",
296
431
  roleInstructions,
@@ -298,24 +433,33 @@ export function renderAceContext(options) {
298
433
  "## Tool Scope",
299
434
  toolCatalog || "- No ACE tools available.",
300
435
  "",
301
- "## Relevant Skills",
302
- relevantSkills.length > 0 ? `- ${relevantSkills.join(", ")}` : "- No task-specific skill hint matched.",
303
- "",
304
436
  "## Compact Guardrails",
305
437
  "- Stop if you are about to claim tested, verified, or passed without evidence.",
306
438
  "- If ACE state is thin or contradictory, call recall_context or validate_framework before improvising.",
307
439
  "- For obviously multi-step work, prefer run_orchestrator over a single free-form answer.",
308
440
  "- When you mutate workspace, use the smallest safe mutation lane: structural edit for existing code, write_workspace_file for new/generated artifacts; never assert file creation in prose alone.",
309
441
  "- Do not declare completion while approval, retry, or blocker state remains active.",
310
- ...(ROLE_OUTPUT_SHAPE_GUARDRAILS[options.role.trim().toLowerCase()] ?? []),
442
+ ...(ROLE_OUTPUT_SHAPE_GUARDRAILS[role] ?? []),
311
443
  "",
444
+ ...playbookBlock,
312
445
  "## Output Contract",
313
- 'Respond in JSON only with one of these shapes:',
446
+ "You may reason briefly in plain text before the JSON envelope, but the final machine-readable response must be one JSON object.",
447
+ 'Keep the JSON `thinking` field to one short line. Respond with one of these shapes:',
314
448
  '- `{"status":"tool","thinking":"...","tool_calls":[{"tool":"name","input":{}}]}`',
315
449
  '- `{"status":"message","thinking":"...","message":"..."}`',
316
450
  '- `{"status":"complete","thinking":"...","summary":"...","evidence_refs":["agent-state/..."]}`',
317
451
  '- `{"status":"need_input","thinking":"...","message":"..."}`',
318
- ].join("\n");
452
+ ...(playbook.injected_ids.length > 0
453
+ ? ['When a learned playbook bullet materially helped your message or completion, include `"used_bullets":["pb-..."]` with injected ids only.']
454
+ : []),
455
+ ];
456
+ const volatileTail = [
457
+ runtimePrompt,
458
+ "",
459
+ "## Relevant Skills",
460
+ relevantSkills.length > 0 ? `- ${relevantSkills.join(", ")}` : "- No task-specific skill hint matched.",
461
+ ];
462
+ const systemPrompt = [...stableBlock, "", ...volatileTail].join("\n");
319
463
  return {
320
464
  systemPrompt,
321
465
  tools,
@@ -323,6 +467,7 @@ export function renderAceContext(options) {
323
467
  // TODO: replace with model-aware token counting when context window management lands.
324
468
  tokenEstimate: Math.max(1, Math.ceil(systemPrompt.length / 4)),
325
469
  tier,
470
+ injected_ids: playbook.injected_ids,
326
471
  };
327
472
  }
328
473
  //# sourceMappingURL=ace-context.js.map