@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.
- package/CHANGELOG.md +78 -0
- package/README.md +72 -532
- package/assets/agent-state/INTERFACE_REGISTRY.md +2 -2
- package/assets/agent-state/MODULES/gates/gate-autonomy.json +4 -2
- package/assets/agent-state/MODULES/gates/gate-completeness.json +4 -2
- package/assets/agent-state/MODULES/gates/gate-operability.json +4 -2
- package/assets/agent-state/MODULES/gates/gate-security.json +3 -1
- package/assets/agent-state/MODULES/registry.json +1 -4
- package/assets/agent-state/MODULES/roles/capability-build.json +1 -2
- package/assets/agent-state/MODULES/roles/capability-eval.json +1 -1
- package/assets/agent-state/MODULES/roles/capability-qa.json +1 -2
- package/assets/agent-state/QUALITY_GATES.md +25 -9
- package/assets/agent-state/TEAL_CONFIG.md +2 -11
- package/assets/eval-battery/battery.json +85 -0
- package/assets/eval-battery/fixtures/edit-target.js +3 -0
- package/assets/scripts/render-mcp-configs.sh +12 -0
- package/dist/ace-context.d.ts +18 -0
- package/dist/ace-context.js +161 -16
- package/dist/ace-server-instructions.js +36 -9
- package/dist/astgrep-index.d.ts +7 -1
- package/dist/astgrep-index.js +66 -39
- package/dist/bridge-trace.d.ts +17 -0
- package/dist/bridge-trace.js +23 -0
- package/dist/cli.d.ts +9 -1
- package/dist/cli.js +619 -10
- package/dist/discovery-runtime-wrappers.d.ts +16 -1
- package/dist/discovery-runtime-wrappers.js +65 -9
- package/dist/eval-harness.d.ts +110 -0
- package/dist/eval-harness.js +254 -0
- package/dist/experience-reflector.d.ts +13 -0
- package/dist/experience-reflector.js +62 -0
- package/dist/gate-contract.d.ts +63 -0
- package/dist/gate-contract.js +178 -0
- package/dist/goal-engine.d.ts +155 -0
- package/dist/goal-engine.js +795 -0
- package/dist/helpers/store-resolution.js +40 -39
- package/dist/hermes/session-manager.d.ts +10 -0
- package/dist/hermes/session-manager.js +130 -27
- package/dist/job-scheduler.d.ts +58 -0
- package/dist/job-scheduler.js +202 -2
- package/dist/job-worker.d.ts +87 -0
- package/dist/job-worker.js +182 -0
- package/dist/local-model-policy.d.ts +8 -2
- package/dist/local-model-policy.js +31 -17
- package/dist/local-model-runtime.d.ts +6 -0
- package/dist/local-model-runtime.js +130 -2
- package/dist/measured-classing.d.ts +66 -0
- package/dist/measured-classing.js +165 -0
- package/dist/model-bridge.d.ts +45 -0
- package/dist/model-bridge.js +502 -44
- package/dist/orchestrator-supervisor.js +1 -1
- package/dist/plan-proposal.d.ts +7 -0
- package/dist/plan-proposal.js +74 -4
- package/dist/playbook-adaptation.d.ts +37 -0
- package/dist/playbook-adaptation.js +159 -0
- package/dist/playbook-curator.d.ts +16 -0
- package/dist/playbook-curator.js +106 -0
- package/dist/playbook-llm-reflector.d.ts +26 -0
- package/dist/playbook-llm-reflector.js +157 -0
- package/dist/public-surface.d.ts +2 -0
- package/dist/public-surface.js +26 -14
- package/dist/runtime-executor.js +45 -2
- package/dist/runtime-tool-specs.d.ts +8 -1
- package/dist/runtime-tool-specs.js +19 -1
- package/dist/safe-edit.d.ts +20 -0
- package/dist/safe-edit.js +355 -78
- package/dist/schemas.js +16 -15
- package/dist/server.d.ts +11 -2
- package/dist/server.js +55 -5
- package/dist/shared.d.ts +12 -0
- package/dist/shared.js +13 -1
- package/dist/source-mutation-coordinator.d.ts +54 -0
- package/dist/source-mutation-coordinator.js +259 -0
- package/dist/status-events.d.ts +4 -1
- package/dist/status-events.js +41 -6
- package/dist/store/ace-packed-store.d.ts +28 -9
- package/dist/store/ace-packed-store.js +324 -57
- package/dist/store/bgzf.d.ts +4 -0
- package/dist/store/bgzf.js +94 -0
- package/dist/store/bootstrap-store.d.ts +4 -1
- package/dist/store/bootstrap-store.js +87 -9
- package/dist/store/cache-workspace.d.ts +8 -0
- package/dist/store/cache-workspace.js +67 -1
- package/dist/store/crc32.d.ts +2 -0
- package/dist/store/crc32.js +16 -0
- package/dist/store/fsck.d.ts +16 -0
- package/dist/store/fsck.js +240 -0
- package/dist/store/gate-contract-migration.d.ts +10 -0
- package/dist/store/gate-contract-migration.js +413 -0
- package/dist/store/materializers/context-snapshot-materializer.d.ts +1 -0
- package/dist/store/materializers/context-snapshot-materializer.js +4 -1
- package/dist/store/materializers/projection-manager.d.ts +7 -0
- package/dist/store/materializers/projection-manager.js +37 -0
- package/dist/store/materializers/scheduler-projection-materializer.js +10 -3
- package/dist/store/repositories/goal-repository.d.ts +112 -0
- package/dist/store/repositories/goal-repository.js +157 -0
- package/dist/store/repositories/playbook-repository.d.ts +107 -0
- package/dist/store/repositories/playbook-repository.js +314 -0
- package/dist/store/store-artifacts.js +44 -2
- package/dist/store/store-authority-audit.js +1 -0
- package/dist/store/store-cli.d.ts +30 -0
- package/dist/store/store-cli.js +242 -0
- package/dist/store/store-snapshot.d.ts +12 -0
- package/dist/store/store-snapshot.js +74 -11
- package/dist/store/types.d.ts +1 -0
- package/dist/store/write-coordinator.d.ts +7 -0
- package/dist/store/write-coordinator.js +11 -0
- package/dist/todo-state.d.ts +21 -0
- package/dist/todo-state.js +150 -53
- package/dist/tools-agent.js +86 -22
- package/dist/tools-discovery.js +5 -3
- package/dist/tools-files.js +107 -23
- package/dist/tools-framework.js +146 -40
- package/dist/tools-goal.d.ts +11 -0
- package/dist/tools-goal.js +108 -0
- package/dist/tools-handoff.js +7 -11
- package/dist/tools-lifecycle.js +2 -0
- package/dist/tools-scheduler.js +44 -1
- package/dist/tools-skills.js +3 -2
- package/dist/tools-todo.js +64 -3
- package/dist/tools.js +2 -0
- package/dist/tui/chat.js +4 -0
- package/dist/tui/index.js +4 -1
- package/dist/tui/ollama.d.ts +2 -0
- package/dist/tui/openai-compatible.d.ts +14 -0
- package/dist/tui/openai-compatible.js +15 -2
- package/dist/tui/provider-discovery.d.ts +1 -0
- package/dist/tui/provider-discovery.js +2 -2
- package/docs/cli-reference.md +125 -0
- package/docs/development.md +46 -0
- package/docs/evaluation-safety.md +27 -0
- package/docs/experience-playbook.md +35 -0
- package/docs/hermes.md +129 -0
- package/docs/library-api.md +31 -0
- package/docs/mcp-tool-reference.md +290 -0
- package/docs/provider-security.md +85 -0
- package/docs/state-model.md +113 -0
- package/docs/troubleshooting.md +95 -0
- package/docs/tui-operator-guide.md +75 -0
- package/package.json +5 -1
- package/scripts/dev/run_hermes_crispr_live.mjs +212 -0
- package/assets/agent-state/MODULES/gates/gate-correctness.json +0 -7
- package/assets/agent-state/MODULES/gates/gate-evaluation.json +0 -7
- package/assets/agent-state/MODULES/gates/gate-typescript-public-surface.json +0 -7
package/dist/tools-handoff.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { ACE_TASKS_ROOT_REL,
|
|
6
|
+
import { ACE_TASKS_ROOT_REL, readTaskArtifact, WORKSPACE_ROOT, } from "./helpers.js";
|
|
7
|
+
import { writeStoreBlobQueued } from "./store/store-artifacts.js";
|
|
7
8
|
import { ROLE_ENUM, HANDOFF_VALIDATION_MODE, HANDOFF_LIFECYCLE_STATUS_ENUM, } from "./shared.js";
|
|
8
9
|
import { validateHandoffPayload, validateSwarmHandoffPayload, lintHandoffPayload, } from "./schemas.js";
|
|
9
10
|
import { acknowledgeHandoffSafe, getHandoffRegistryPath, readHandoffRegistry, registerHandoffSafe, } from "./handoff-registry.js";
|
|
@@ -241,13 +242,8 @@ export function registerHandoffTools(server) {
|
|
|
241
242
|
],
|
|
242
243
|
};
|
|
243
244
|
}
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
.replace(/[-:]/g, "")
|
|
247
|
-
.replace("T", "-")
|
|
248
|
-
.slice(0, 15);
|
|
249
|
-
const filePath = wsPath("tasks", `SWARM_HANDOFF.${from}_to_${to}_${timeStr}_${shortId}.json`);
|
|
250
|
-
await safeWriteAsync(filePath, JSON.stringify(handoff, null, 2));
|
|
245
|
+
const payloadStoreKey = `state/handoffs/payloads/${handoff.handoff_id}.json`;
|
|
246
|
+
const payloadPath = await writeStoreBlobQueued(WORKSPACE_ROOT, payloadStoreKey, JSON.stringify(handoff, null, 2), { operation_label: "create_handoff.payload" });
|
|
251
247
|
const registry = await registerHandoffSafe({
|
|
252
248
|
handoff_id: handoff.handoff_id,
|
|
253
249
|
from: handoff.router.from,
|
|
@@ -255,14 +251,14 @@ export function registerHandoffTools(server) {
|
|
|
255
251
|
title: handoff.task.title,
|
|
256
252
|
task_type: handoff.task.type,
|
|
257
253
|
priority: handoff.task.priority,
|
|
258
|
-
source_file:
|
|
254
|
+
source_file: payloadPath,
|
|
259
255
|
});
|
|
260
256
|
const runLedger = await appendRunLedgerEntrySafe({
|
|
261
257
|
tool: "create_handoff",
|
|
262
258
|
category: "major_update",
|
|
263
259
|
message: `Created handoff ${handoff.handoff_id} (${handoff.router.from} -> ${handoff.router.to})`,
|
|
264
260
|
artifacts: [
|
|
265
|
-
|
|
261
|
+
payloadPath,
|
|
266
262
|
"agent-state/handoff-registry.json",
|
|
267
263
|
],
|
|
268
264
|
metadata: {
|
|
@@ -282,7 +278,7 @@ export function registerHandoffTools(server) {
|
|
|
282
278
|
"# Handoff Created",
|
|
283
279
|
"",
|
|
284
280
|
`Schema: ${validation.schema}`,
|
|
285
|
-
`Saved to: ${
|
|
281
|
+
`Saved to: ${payloadPath}`,
|
|
286
282
|
`Handoff registry: ${registry.path}`,
|
|
287
283
|
`Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
|
|
288
284
|
`Scheduler job: ${schedulerSync.job_id} (${schedulerSync.enqueued ? "enqueued" : "already_exists"})`,
|
package/dist/tools-lifecycle.js
CHANGED
|
@@ -194,6 +194,8 @@ export function registerLifecycleTools(server) {
|
|
|
194
194
|
"",
|
|
195
195
|
`JSON: ${snapshot.json_path}`,
|
|
196
196
|
`HTML: ${snapshot.html_path}`,
|
|
197
|
+
`Read: ace read agent-state/kanban.json`,
|
|
198
|
+
`Open: ace read agent-state/kanban.html --out /tmp/ace-kanban.html && open /tmp/ace-kanban.html`,
|
|
197
199
|
`Updated: ${snapshot.generated_at}`,
|
|
198
200
|
`Counts: backlog=${snapshot.counts.backlog}, blocked=${snapshot.counts.blocked}, in_progress=${snapshot.counts.in_progress}, gated=${snapshot.counts.gated}, done=${snapshot.counts.done}`,
|
|
199
201
|
].join("\n"),
|
package/dist/tools-scheduler.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Job scheduler tool registrations.
|
|
3
3
|
*/
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { acknowledgeJob, completeJob, dispatchJobNow, dispatchJobs, enqueueJob, getJobLockTablePath, getJobQueuePath, getSchedulerLeasePath, readJobQueue, readJobLockTable, readSchedulerLease, } from "./job-scheduler.js";
|
|
5
|
+
import { acknowledgeJob, completeJob, dispatchJobNow, dispatchJobs, enqueueJob, getJobLockTablePath, getJobQueuePath, getSchedulerLeasePath, heartbeatJob, reapStaleRunningJobsTick, readJobQueue, readJobLockTable, readSchedulerLease, } from "./job-scheduler.js";
|
|
6
6
|
// Event emission handled in core job-scheduler.ts — no wrapper duplication.
|
|
7
7
|
const PRIORITY_BAND_ENUM = z.enum(["P0", "P1", "P2", "P3"]);
|
|
8
8
|
const JOB_STATUS_ENUM = z.enum([
|
|
@@ -196,6 +196,49 @@ export function registerSchedulerTools(server) {
|
|
|
196
196
|
],
|
|
197
197
|
};
|
|
198
198
|
});
|
|
199
|
+
server.tool("heartbeat_job", "Prove liveness for a running job so the heartbeat watchdog does not reap it; renews the owner lease", {
|
|
200
|
+
job_id: z.string(),
|
|
201
|
+
owner: z.string().optional().describe("Lease owner identity (defaults to capability-ops)"),
|
|
202
|
+
lease_ttl_seconds: z.number().int().min(5).max(3600).optional(),
|
|
203
|
+
now_iso: z.string().optional().describe("Optional deterministic clock override"),
|
|
204
|
+
}, async ({ job_id, owner, lease_ttl_seconds, now_iso }) => {
|
|
205
|
+
const result = await heartbeatJob({ job_id, owner, lease_ttl_seconds, now_iso });
|
|
206
|
+
return {
|
|
207
|
+
content: [
|
|
208
|
+
{
|
|
209
|
+
type: "text",
|
|
210
|
+
text: result.ok
|
|
211
|
+
? ["✅ Job heartbeat recorded", asJsonBlock(result)].join("\n")
|
|
212
|
+
: ["❌ heartbeat_job failed", result.error ?? "Unknown error", asJsonBlock(result)].join("\n"),
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
server.tool("reap_stale_jobs", "Run the heartbeat watchdog once: move running jobs with a stale worker heartbeat into unknown_recovery and release their locks", {
|
|
218
|
+
heartbeat_stale_seconds: z
|
|
219
|
+
.number()
|
|
220
|
+
.int()
|
|
221
|
+
.min(1)
|
|
222
|
+
.max(86_400)
|
|
223
|
+
.optional()
|
|
224
|
+
.describe("Staleness window in seconds (default 120)"),
|
|
225
|
+
now_iso: z.string().optional().describe("Optional deterministic clock override"),
|
|
226
|
+
}, async ({ heartbeat_stale_seconds, now_iso }) => {
|
|
227
|
+
const result = await reapStaleRunningJobsTick({ heartbeat_stale_seconds, now_iso });
|
|
228
|
+
return {
|
|
229
|
+
content: [
|
|
230
|
+
{
|
|
231
|
+
type: "text",
|
|
232
|
+
text: [
|
|
233
|
+
result.reaped_jobs > 0
|
|
234
|
+
? `🩺 Watchdog reaped ${result.reaped_jobs} stale job(s)`
|
|
235
|
+
: "🩺 Watchdog found no stale running jobs",
|
|
236
|
+
asJsonBlock(result),
|
|
237
|
+
].join("\n"),
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
};
|
|
241
|
+
});
|
|
199
242
|
server.tool("get_lock_table", "Read the scheduler lock table", {}, async () => ({
|
|
200
243
|
content: [
|
|
201
244
|
{
|
package/dist/tools-skills.js
CHANGED
|
@@ -49,9 +49,10 @@ export function registerSkillTools(server) {
|
|
|
49
49
|
.describe("Optional workspace-relative path for the audit report"),
|
|
50
50
|
}, async ({ write_artifact, artifact_path }) => {
|
|
51
51
|
const result = auditSkillCatalog();
|
|
52
|
+
const artifactPath = artifact_path || "agent-state/SKILL_AUDIT_REPORT.md";
|
|
52
53
|
const writtenPath = write_artifact === false
|
|
53
54
|
? undefined
|
|
54
|
-
: writeSkillAuditReport(result,
|
|
55
|
+
: writeSkillAuditReport(result, artifactPath);
|
|
55
56
|
const failCount = result.entries.filter((entry) => entry.status === "fail").length;
|
|
56
57
|
const warnCount = result.entries.filter((entry) => entry.status === "warn").length;
|
|
57
58
|
return {
|
|
@@ -62,7 +63,7 @@ export function registerSkillTools(server) {
|
|
|
62
63
|
`Portable-contract-ready skills: ${result.summary.portable_contract_ready_skills}/${result.summary.total_skills}`,
|
|
63
64
|
`Fail/Warn: ${failCount}/${warnCount}`,
|
|
64
65
|
...(result.rollout_backlog.slice(0, 5).map((line) => `- ${line}`)),
|
|
65
|
-
...(writtenPath ? [`- Artifact
|
|
66
|
+
...(writtenPath ? [`- Artifact: ${artifactPath}`, `- Read: ace read ${artifactPath}`, `- Store path: ${writtenPath}`] : []),
|
|
66
67
|
].join("\n"),
|
|
67
68
|
},
|
|
68
69
|
],
|
package/dist/tools-todo.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { ACE_TASKS_ROOT_REL, readTaskArtifact, resolveWritableTaskPath, safeWriteAsync, } from "./helpers.js";
|
|
6
6
|
import { TODO_STATUS_ENUM } from "./shared.js";
|
|
7
|
-
import { getTodoStatePath, readTodoState, syncTodoStateSafe, transitionTodoNodeSafe, } from "./todo-state.js";
|
|
7
|
+
import { appendTodoItemSafe, getTodoStatePath, readTodoState, syncTodoStateSafe, transitionTodoNodeSafe, } from "./todo-state.js";
|
|
8
8
|
import { appendRunLedgerEntrySafe, getRunLedgerPath, readRunLedger, } from "./run-ledger.js";
|
|
9
9
|
import { refreshKanbanArtifacts } from "./kanban.js";
|
|
10
10
|
export function registerTodoTools(server) {
|
|
@@ -19,7 +19,7 @@ export function registerTodoTools(server) {
|
|
|
19
19
|
},
|
|
20
20
|
],
|
|
21
21
|
}));
|
|
22
|
-
server.tool("update_todo", "Replace TODO board content or transition a TODO node status with gate validation", {
|
|
22
|
+
server.tool("update_todo", "Replace TODO board content, append a new TODO item, or transition a TODO node status with gate validation", {
|
|
23
23
|
new_content: z
|
|
24
24
|
.string()
|
|
25
25
|
.optional()
|
|
@@ -30,7 +30,68 @@ export function registerTodoTools(server) {
|
|
|
30
30
|
.describe("Todo node id to transition (transition mode)"),
|
|
31
31
|
status: TODO_STATUS_ENUM.optional().describe("Target status for transition mode"),
|
|
32
32
|
note: z.string().optional().describe("Optional transition context note"),
|
|
33
|
-
|
|
33
|
+
append_title: z
|
|
34
|
+
.string()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("Title for a new TODO item to append atomically (append mode). Prefer this over " +
|
|
37
|
+
"new_content when adding a single item — it is safe under concurrent callers, " +
|
|
38
|
+
"unlike a read-then-full-replace round trip."),
|
|
39
|
+
append_section: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Section heading to append the new item under (default: Active Work)"),
|
|
43
|
+
append_depends_on: z
|
|
44
|
+
.array(z.string())
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Node ids the new append-mode item depends on"),
|
|
47
|
+
append_id: z
|
|
48
|
+
.string()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe("Optional explicit node id for the new append-mode item"),
|
|
51
|
+
}, async ({ new_content, node_id, status, note, append_title, append_section, append_depends_on, append_id, }) => {
|
|
52
|
+
if (typeof append_title === "string") {
|
|
53
|
+
const appended = await appendTodoItemSafe(append_title, {
|
|
54
|
+
section: append_section,
|
|
55
|
+
depends_on: append_depends_on,
|
|
56
|
+
id: append_id,
|
|
57
|
+
});
|
|
58
|
+
if (!appended.ok) {
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{ type: "text", text: `❌ ${appended.error ?? "Failed to append TODO item."}` },
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const runLedger = await appendRunLedgerEntrySafe({
|
|
66
|
+
tool: "update_todo",
|
|
67
|
+
category: "info",
|
|
68
|
+
message: `Appended TODO item ${appended.node_id}`,
|
|
69
|
+
artifacts: [`${ACE_TASKS_ROOT_REL}/todo.md`, "agent-state/todo-state.json"],
|
|
70
|
+
metadata: {
|
|
71
|
+
mode: "append",
|
|
72
|
+
node_id: appended.node_id,
|
|
73
|
+
section: appended.section,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
const kanban = refreshKanbanArtifacts("tool:update_todo");
|
|
77
|
+
const counts = kanban.counts;
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: [
|
|
83
|
+
`✅ TODO item appended: ${appended.node_id}`,
|
|
84
|
+
`Section: ${appended.section}`,
|
|
85
|
+
`TODO state: ${appended.path}`,
|
|
86
|
+
`TODO markdown: ${appended.todo_path}`,
|
|
87
|
+
`Run ledger: ${runLedger.path} (${runLedger.entry.id})`,
|
|
88
|
+
`Kanban updated: ${kanban.html_path}`,
|
|
89
|
+
`Kanban counts: backlog=${counts.backlog}, blocked=${counts.blocked}, in_progress=${counts.in_progress}, gated=${counts.gated}, done=${counts.done}`,
|
|
90
|
+
].join("\n"),
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
34
95
|
if (typeof new_content === "string") {
|
|
35
96
|
const synced = await syncTodoStateSafe(new_content);
|
|
36
97
|
const path = await safeWriteAsync(resolveWritableTaskPath("todo"), new_content);
|
package/dist/tools.js
CHANGED
|
@@ -15,6 +15,7 @@ import { registerGitTools } from "./tools-git.js";
|
|
|
15
15
|
import { registerMemoryTools } from "./tools-memory.js";
|
|
16
16
|
import { registerDriftTools } from "./tools-drift.js";
|
|
17
17
|
import { registerSchedulerTools } from "./tools-scheduler.js";
|
|
18
|
+
import { registerGoalTools } from "./tools-goal.js";
|
|
18
19
|
import { registerSkillTools } from "./tools-skills.js";
|
|
19
20
|
const TOOL_REGISTRARS = [
|
|
20
21
|
registerAgentTools,
|
|
@@ -28,6 +29,7 @@ const TOOL_REGISTRARS = [
|
|
|
28
29
|
registerMemoryTools,
|
|
29
30
|
registerDriftTools,
|
|
30
31
|
registerSchedulerTools,
|
|
32
|
+
registerGoalTools,
|
|
31
33
|
registerSkillTools,
|
|
32
34
|
];
|
|
33
35
|
function createAllowlistedServer(server, allowed) {
|
package/dist/tui/chat.js
CHANGED
|
@@ -243,6 +243,10 @@ export class ChatSession extends EventEmitter {
|
|
|
243
243
|
const activeProvider = this.activeStreamProvider ?? this.provider;
|
|
244
244
|
this.streaming = false;
|
|
245
245
|
if (this.activeAceBridge) {
|
|
246
|
+
if (this.executionEngine === "hermes_local") {
|
|
247
|
+
this.hermesExecutor?.interrupt?.();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
246
250
|
this.aceBridge.interrupt();
|
|
247
251
|
return;
|
|
248
252
|
}
|
package/dist/tui/index.js
CHANGED
|
@@ -190,7 +190,7 @@ export class AceTui {
|
|
|
190
190
|
});
|
|
191
191
|
// Handle signals
|
|
192
192
|
process.on("SIGINT", () => {
|
|
193
|
-
// Ctrl+C
|
|
193
|
+
// Ctrl+C interrupts an active stream; while idle it is deliberately a no-op.
|
|
194
194
|
if (this.activeChatSession?.isStreaming()) {
|
|
195
195
|
this.activeChatSession.interrupt();
|
|
196
196
|
}
|
|
@@ -332,6 +332,9 @@ export class AceTui {
|
|
|
332
332
|
case "w":
|
|
333
333
|
this.closeCurrentTab();
|
|
334
334
|
return;
|
|
335
|
+
case "z":
|
|
336
|
+
this.suspend();
|
|
337
|
+
return;
|
|
335
338
|
}
|
|
336
339
|
}
|
|
337
340
|
// Alt+number → switch tab
|
package/dist/tui/ollama.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export interface ChatRequest {
|
|
|
36
36
|
model: string;
|
|
37
37
|
messages: ChatMessage[];
|
|
38
38
|
stream?: boolean;
|
|
39
|
+
/** "json" for generic JSON mode; a JSON Schema object for schema-constrained generation (Ollama ≥ 0.5). */
|
|
40
|
+
format?: "json" | Record<string, unknown> | string;
|
|
39
41
|
options?: {
|
|
40
42
|
temperature?: number;
|
|
41
43
|
top_p?: number;
|
|
@@ -15,6 +15,19 @@ export interface OpenAICompatibleChatRequest {
|
|
|
15
15
|
messages: OpenAICompatibleChatMessage[];
|
|
16
16
|
temperature?: number;
|
|
17
17
|
topP?: number;
|
|
18
|
+
maxTokens?: number;
|
|
19
|
+
responseFormat?: {
|
|
20
|
+
type: "json_object";
|
|
21
|
+
} | {
|
|
22
|
+
type: "json_schema";
|
|
23
|
+
json_schema: {
|
|
24
|
+
name: string;
|
|
25
|
+
schema: Record<string, unknown>;
|
|
26
|
+
strict?: boolean;
|
|
27
|
+
};
|
|
28
|
+
} | {
|
|
29
|
+
type: string;
|
|
30
|
+
};
|
|
18
31
|
onProviderEvent?: (event: OpenAICompatibleProviderEvent) => void;
|
|
19
32
|
}
|
|
20
33
|
export interface OpenAICompatibleChatChunk {
|
|
@@ -66,6 +79,7 @@ export declare class OpenAICompatibleClient {
|
|
|
66
79
|
private resolveProviderConfig;
|
|
67
80
|
private streamSseData;
|
|
68
81
|
}
|
|
82
|
+
export declare const ANTHROPIC_OPENAI_COMPATIBLE_BASE_URL = "https://api.anthropic.com/v1";
|
|
69
83
|
/**
|
|
70
84
|
* Resolve a GitHub / Copilot token from the environment or `gh` CLI.
|
|
71
85
|
* Checks: GITHUB_TOKEN → GH_TOKEN → `gh auth token` (sync exec).
|
|
@@ -172,6 +172,8 @@ export class OpenAICompatibleClient {
|
|
|
172
172
|
stream: true,
|
|
173
173
|
temperature: request.temperature,
|
|
174
174
|
top_p: request.topP,
|
|
175
|
+
max_tokens: request.maxTokens,
|
|
176
|
+
...(request.responseFormat ? { response_format: request.responseFormat } : {}),
|
|
175
177
|
};
|
|
176
178
|
const streamRes = await fetch(`${config.baseUrl}/chat/completions`, {
|
|
177
179
|
method: "POST",
|
|
@@ -263,6 +265,8 @@ export class OpenAICompatibleClient {
|
|
|
263
265
|
stream: false,
|
|
264
266
|
temperature: request.temperature,
|
|
265
267
|
top_p: request.topP,
|
|
268
|
+
max_tokens: request.maxTokens,
|
|
269
|
+
...(request.responseFormat ? { response_format: request.responseFormat } : {}),
|
|
266
270
|
};
|
|
267
271
|
const res = await fetch(`${config.baseUrl}/chat/completions`, {
|
|
268
272
|
method: "POST",
|
|
@@ -348,6 +352,8 @@ export class OpenAICompatibleClient {
|
|
|
348
352
|
stream: true,
|
|
349
353
|
temperature: request.temperature,
|
|
350
354
|
top_p: request.topP,
|
|
355
|
+
max_tokens: request.maxTokens,
|
|
356
|
+
...(request.responseFormat ? { response_format: request.responseFormat } : {}),
|
|
351
357
|
};
|
|
352
358
|
// llama.cpp rejects custom stream_options; only include for non-llama providers
|
|
353
359
|
if (provider !== 'llama.cpp') {
|
|
@@ -485,7 +491,10 @@ export class OpenAICompatibleClient {
|
|
|
485
491
|
const apiKey = override?.apiKey || providerKey || genericKey || process.env.CODEX_API_KEY?.trim();
|
|
486
492
|
return { provider, baseUrl, apiKey, headers: override?.headers };
|
|
487
493
|
}
|
|
488
|
-
const resolvedBaseUrl = override?.baseUrl ||
|
|
494
|
+
const resolvedBaseUrl = override?.baseUrl ||
|
|
495
|
+
providerBase ||
|
|
496
|
+
genericBase ||
|
|
497
|
+
(provider === "claude" ? ANTHROPIC_OPENAI_COMPATIBLE_BASE_URL : "");
|
|
489
498
|
const baseUrl = provider === "llama.cpp"
|
|
490
499
|
? buildOpenAiCompatibleBaseUrl(resolvedBaseUrl)
|
|
491
500
|
: stripTrailingSlash(resolvedBaseUrl);
|
|
@@ -559,6 +568,7 @@ function providerEnvPrefix(provider) {
|
|
|
559
568
|
return provider === "llama.cpp" ? "LLAMA_CPP" : provider.toUpperCase();
|
|
560
569
|
}
|
|
561
570
|
const GITHUB_MODELS_BASE_URL = "https://models.github.com/v1";
|
|
571
|
+
export const ANTHROPIC_OPENAI_COMPATIBLE_BASE_URL = "https://api.anthropic.com/v1";
|
|
562
572
|
/**
|
|
563
573
|
* Resolve a GitHub / Copilot token from the environment or `gh` CLI.
|
|
564
574
|
* Checks: GITHUB_TOKEN → GH_TOKEN → `gh auth token` (sync exec).
|
|
@@ -612,7 +622,10 @@ export function diagnoseProviderRuntimeConfig(providerInput, override) {
|
|
|
612
622
|
message: "Missing API key for provider 'codex'. Set CODEX_API_KEY or OPENAI_API_KEY before sending chat messages.",
|
|
613
623
|
};
|
|
614
624
|
}
|
|
615
|
-
const baseUrl = stripTrailingSlash(override?.baseUrl ||
|
|
625
|
+
const baseUrl = stripTrailingSlash(override?.baseUrl ||
|
|
626
|
+
providerBase ||
|
|
627
|
+
genericBase ||
|
|
628
|
+
(provider === "claude" ? ANTHROPIC_OPENAI_COMPATIBLE_BASE_URL : ""));
|
|
616
629
|
const apiKey = override?.apiKey || providerKey || genericKey || "";
|
|
617
630
|
const missing = [];
|
|
618
631
|
if (!baseUrl) {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export declare const DEFAULT_OLLAMA_MODEL = "llama3.1:8b";
|
|
16
16
|
export declare const DEFAULT_LLAMA_CPP_MODEL = "local-model";
|
|
17
|
+
export declare const DEFAULT_HOSTED_MODELS: Readonly<Record<"codex" | "claude" | "gemini" | "copilot", string>>;
|
|
17
18
|
export declare const LOCAL_LLM_PROVIDERS: readonly ["ollama", "llama.cpp"];
|
|
18
19
|
export type LocalLlmProvider = (typeof LOCAL_LLM_PROVIDERS)[number];
|
|
19
20
|
export interface ProviderDiscoveryOptions {
|
|
@@ -18,9 +18,9 @@ import { join, resolve } from "node:path";
|
|
|
18
18
|
import { readStoreJsonSync } from "../store/store-snapshot.js";
|
|
19
19
|
export const DEFAULT_OLLAMA_MODEL = "llama3.1:8b";
|
|
20
20
|
export const DEFAULT_LLAMA_CPP_MODEL = "local-model";
|
|
21
|
-
const DEFAULT_HOSTED_MODELS = {
|
|
21
|
+
export const DEFAULT_HOSTED_MODELS = {
|
|
22
22
|
codex: "gpt-5",
|
|
23
|
-
claude: "claude-
|
|
23
|
+
claude: "claude-opus-4-8",
|
|
24
24
|
gemini: "gemini-2.5-pro",
|
|
25
25
|
copilot: "copilot/gpt-5-mini",
|
|
26
26
|
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
> Companion to the [Quick Start in the README](../README.md#quick-start).
|
|
4
|
+
|
|
5
|
+
The bare `ace` commands below assume a global install (`npm install -g @voybio/ace-swarm`); without one, prefix each with `npx -y @voybio/ace-swarm` — e.g. `npx -y @voybio/ace-swarm mcp`.
|
|
6
|
+
|
|
7
|
+
## Commands
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
+--------------------------------------------+-------------------------------------------------------+
|
|
11
|
+
| Command | Purpose |
|
|
12
|
+
+--------------------------------------------+-------------------------------------------------------+
|
|
13
|
+
| `ace mcp [--profile host-min|full]` / `ace serve` | Start MCP server over stdio |
|
|
14
|
+
| `ace mcp-shadow --tools <csv>` | Start filtered shadow MCP server (Hermes use) |
|
|
15
|
+
| `ace tui [options]` | Open the terminal operator surface |
|
|
16
|
+
| `ace init [options]` | Seed the ACE store and optional host stubs |
|
|
17
|
+
| `ace connect [provider] [options]` | Register a live local runtime or hosted provider |
|
|
18
|
+
| `ace turnkey [options]` | Project store-backed host surface stubs |
|
|
19
|
+
| `ace doctor [options]` | Validate ACE runtime + MCP readiness |
|
|
20
|
+
| `ace goal <start|status|run|resume|stop>` | Drive a self-paced, evidence-gated goal loop |
|
|
21
|
+
| `ace ls [prefix] [--keys] [--json]` | List store-backed artifacts by logical path |
|
|
22
|
+
| `ace read <path> [--out f] [--source] [--json] [--prefer disk|store]` | Read a store/workspace file (aliases: get, cat) |
|
|
23
|
+
| `ace fsck [--json] [--repair]` | Validate ACEPACK structure, CRCs, orphans |
|
|
24
|
+
| `ace cache [options]` | DEPRECATED legacy ingest/clean command; it is not an alias for compaction |
|
|
25
|
+
| `ace compact [--no-sweep]` | Compact the store and sweep loose generated artifacts |
|
|
26
|
+
| `ace migrate [store-path]` | Import a legacy file workspace into the store |
|
|
27
|
+
| `ace repair` | Re-materialize host files and repair store assets |
|
|
28
|
+
| `ace add skills [name|all]` | Install packaged skill packs into the store |
|
|
29
|
+
| `ace playbook <list|show|add|tag|gc>` | Inspect and curate the experience playbook |
|
|
30
|
+
| `ace eval [--adapt] [options]` | Run the eval harness / adaptation cycle |
|
|
31
|
+
| `ace mcp-config [--client <name>|--all]` | Print baked client snippets for optional install |
|
|
32
|
+
| `ace preconfig` | Write .mcp-config/ bundle for all clients |
|
|
33
|
+
| `ace paths` | Show resolved package and workspace paths |
|
|
34
|
+
| `ace help` | Show help |
|
|
35
|
+
+--------------------------------------------+-------------------------------------------------------+
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Examples
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Bootstrap a workspace with a hosted provider
|
|
42
|
+
ace init --project "My App" --llm claude --client-config-bundle
|
|
43
|
+
|
|
44
|
+
# Bootstrap with a local Ollama model and write VS Code MCP config
|
|
45
|
+
ace init --project "My App" --llm ollama --model qwen3:8b \
|
|
46
|
+
--base-url http://localhost:11434 --mcp-config
|
|
47
|
+
|
|
48
|
+
# Connect to a running llama.cpp server from a Hugging Face model
|
|
49
|
+
ace connect llama-server --hf bartowski/gemma-3-4b-it-GGUF \
|
|
50
|
+
--base-url http://localhost:8080
|
|
51
|
+
|
|
52
|
+
# Run doctor checks with auto-scan of common local endpoints
|
|
53
|
+
ace doctor --scan
|
|
54
|
+
|
|
55
|
+
# Run doctor checks for a specific provider + model
|
|
56
|
+
ace doctor --llm ollama --model qwen3:8b --base-url http://localhost:11434
|
|
57
|
+
|
|
58
|
+
# Run optional Hermes checks with user-supplied Hermes/Python
|
|
59
|
+
ACE_HERMES_ROOT=/path/to/hermes-agent HERMES_PYTHON=/path/to/python \
|
|
60
|
+
ace doctor --llm llama.cpp --model gemma-3-4b-it --base-url http://localhost:8080 --hermes
|
|
61
|
+
|
|
62
|
+
# Repair a missing Ollama model and re-probe runtime readiness
|
|
63
|
+
ace doctor --llm ollama --model qwen3:8b --repair-ollama
|
|
64
|
+
|
|
65
|
+
# Print VS Code MCP config snippet to stdout
|
|
66
|
+
ace mcp-config --client vscode
|
|
67
|
+
|
|
68
|
+
# Write config bundles for every supported client at workspace root
|
|
69
|
+
ace preconfig
|
|
70
|
+
|
|
71
|
+
# Launch TUI with optional Hermes engine against a local llama.cpp server
|
|
72
|
+
ACE_HERMES_ROOT=/path/to/hermes-agent HERMES_PYTHON=/path/to/python \
|
|
73
|
+
ace tui --provider llama.cpp --base-url http://localhost:8080 --model gemma-3-4b-it --hermes
|
|
74
|
+
|
|
75
|
+
# Compact the store and sweep loose generated artifacts
|
|
76
|
+
ace compact
|
|
77
|
+
ace compact --no-sweep
|
|
78
|
+
|
|
79
|
+
# List and read store-backed artifacts a human otherwise can't see on disk
|
|
80
|
+
ace ls agent-state
|
|
81
|
+
ace read agent-state/kanban.json
|
|
82
|
+
ace read agent-state/STORE_AUTHORITY_AUDIT.md --out /tmp/audit.md
|
|
83
|
+
|
|
84
|
+
# Validate ACEPACK structure/CRCs/orphans, optionally repairing safe issues
|
|
85
|
+
ace fsck
|
|
86
|
+
ace fsck --repair
|
|
87
|
+
|
|
88
|
+
# Start a self-paced goal, watch it, stop it if needed.
|
|
89
|
+
# The objective needs at least one machine-checkable obligation -- a declared
|
|
90
|
+
# artifact or a `verify: <command>` criterion -- or `start` refuses it with
|
|
91
|
+
# `contract_uncheckable` rather than completing on the model's own say-so.
|
|
92
|
+
ace goal start "Ship the auth module. verify: npm test" --budget-hours 2 --detach
|
|
93
|
+
ace goal status
|
|
94
|
+
ace goal stop <goal_id>
|
|
95
|
+
|
|
96
|
+
# Experimental: list and inspect the learned experience playbook
|
|
97
|
+
ace playbook list
|
|
98
|
+
ace playbook show pb-1234abcd
|
|
99
|
+
ace playbook add --section verification --content "Require evidence refs before completion."
|
|
100
|
+
ace playbook add --section failure_modes --reason-code false_completion_no_evidence \
|
|
101
|
+
--content "Require evidence refs before completion."
|
|
102
|
+
ace playbook tag pb-1234abcd helpful
|
|
103
|
+
|
|
104
|
+
# Experimental: run an eval adaptation cycle
|
|
105
|
+
ace eval --adapt --models qwen3:8b,gemma3:4b --epochs 2 \
|
|
106
|
+
--battery ./my-battery.json --out agent-state/eval-reports
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Playbook sections are `strategies`, `tool_usage`, `failure_modes`, `verification`,
|
|
110
|
+
and `env_facts`; list statuses are `active`, `quarantined`, and `retired`.
|
|
111
|
+
Lessons from every producer without evidence are stored as `quarantined` and
|
|
112
|
+
are not prompt-injected.
|
|
113
|
+
|
|
114
|
+
## Selected options
|
|
115
|
+
|
|
116
|
+
- `ace mcp --profile <host-min|full>` selects the visible tool schema; `full` is the default.
|
|
117
|
+
- `ace turnkey --no-client-config-bundle` skips the host-facing config stubs created by default.
|
|
118
|
+
- `ace playbook add --reason-code <code>` scopes a lesson to a matching failure class.
|
|
119
|
+
- `ace eval` accepts `--model`/`--models`, `--battery <path>`, `--out <dir>`, and `--adapt`; `--epochs <n>` applies only to adaptation runs.
|
|
120
|
+
- `ace read` accepts `--source` and `--json` in addition to `--out` and `--prefer`.
|
|
121
|
+
|
|
122
|
+
Eval is non-destructive by default: every task, model, baseline, and adapted
|
|
123
|
+
epoch runs in a new disposable workspace seeded only from the battery's adjacent
|
|
124
|
+
`fixtures/` directory. Expected artifacts are scored inside that workspace and
|
|
125
|
+
recorded by SHA-256 in the scorecard, so stale project files cannot pass a run.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Development
|
|
2
|
+
|
|
3
|
+
> Companion to the [README](../README.md).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd ace-mcp-server
|
|
7
|
+
npm install
|
|
8
|
+
npm run build
|
|
9
|
+
npm test
|
|
10
|
+
npm run start
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run the Hermes live driver from a source checkout. The script is included in the npm package as of 2.4.6, but it imports the checkout/package `dist/` tree and is a diagnostic, not a supported production command. It exits nonzero if setup, protocol, or artifact checks fail.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run build
|
|
17
|
+
# with a local llama.cpp or Ollama runtime running:
|
|
18
|
+
ACE_WORKSPACE_ROOT=$PWD \
|
|
19
|
+
ACE_HERMES_ROOT=/path/to/hermes-agent \
|
|
20
|
+
HERMES_PYTHON=/path/to/hermes-python \
|
|
21
|
+
ACE_LIVE_PROVIDERS=llama.cpp \
|
|
22
|
+
ACE_LIVE_LLAMA_CPP_BASE_URL=http://127.0.0.1:8080/v1 \
|
|
23
|
+
ACE_LIVE_LLAMA_CPP_MODEL=gemma-3-4b-it \
|
|
24
|
+
ACE_LIVE_HERMES_MAX_TURNS=3 \
|
|
25
|
+
node scripts/dev/run_hermes_crispr_live.mjs
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`ACE_LIVE_OUTPUT_ONLY=1` deliberately bypasses tool writing and is only for inspecting raw model output; it cannot satisfy the driver’s evidence-gated job check.
|
|
29
|
+
|
|
30
|
+
## Key source files
|
|
31
|
+
|
|
32
|
+
| File | Role |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `src/index.ts` | Package entry point |
|
|
35
|
+
| `src/cli.ts` | CLI command dispatch |
|
|
36
|
+
| `src/server.ts` | MCP server setup and stdio transport |
|
|
37
|
+
| `src/tools.ts` | Tool registration hub (delegates to domain modules) |
|
|
38
|
+
| `src/hermes/session-manager.ts` | `HermesSubprocessExecutor` — Hermes subprocess lifecycle |
|
|
39
|
+
| `src/hermes/bridge-protocol.ts` | Frame decoder for the Hermes bridge protocol |
|
|
40
|
+
| `src/model-bridge.ts` | Model bridge interface and process orchestration |
|
|
41
|
+
| `src/goal-engine.ts` | Goal engine — self-paced, evidence-gated objective loop |
|
|
42
|
+
| `src/job-worker.ts` | In-process job worker for the scheduler execution loop |
|
|
43
|
+
| `src/public-surface.ts` | Public surface audit and schema-bound entry map |
|
|
44
|
+
| `src/store/ace-packed-store.ts` | ACEPACK binary store read/write |
|
|
45
|
+
| `src/local-model-policy.ts` | Operator allow/block policy for local models |
|
|
46
|
+
| `scripts/hermes_bridge_worker.py` | Packaged Python worker for the Hermes bridge |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Evaluation Safety and Reproducibility
|
|
2
|
+
|
|
3
|
+
`ace eval` executes tasks that may create and modify files. Packaged battery runs are therefore isolated from the caller's checkout.
|
|
4
|
+
|
|
5
|
+
## Isolation contract
|
|
6
|
+
|
|
7
|
+
- Each model, epoch, and task receives a fresh temporary workspace.
|
|
8
|
+
- Battery fixtures are copied into that workspace before execution.
|
|
9
|
+
- A task cannot inherit artifacts from an earlier task or epoch.
|
|
10
|
+
- Temporary workspaces are removed after the result and artifact provenance have been recorded.
|
|
11
|
+
|
|
12
|
+
Do not treat an evaluation task as safe merely because its prompt sounds read-only. Review custom batteries before running them and never configure an evaluation workspace to point at a valuable checkout.
|
|
13
|
+
|
|
14
|
+
## Provenance
|
|
15
|
+
|
|
16
|
+
Evaluation results record the task identity, isolated workspace identity, and hashes for produced artifacts. Hashes establish what bytes were evaluated after the temporary workspace is removed; they do not prove that an artifact is semantically correct. Correctness remains the responsibility of the task verifier and its evidence requirements.
|
|
17
|
+
|
|
18
|
+
For reproducible comparisons, pin the battery, model identifier, provider configuration, ACE version, and relevant environment variables. A provider-backed result may still vary when the remote model or serving stack changes behind a stable name.
|
|
19
|
+
|
|
20
|
+
## Failure interpretation
|
|
21
|
+
|
|
22
|
+
- A missing required artifact is a failed task, not a zero-score success.
|
|
23
|
+
- An artifact left by a previous task must never satisfy a later task.
|
|
24
|
+
- Provider launch, timeout, and protocol failures are execution failures and must remain distinguishable from verifier failures.
|
|
25
|
+
- Preserve the result record when diagnosing a failure; do not rely on a temporary workspace surviving cleanup.
|
|
26
|
+
|
|
27
|
+
See [CLI Reference](cli-reference.md) for command syntax and [Troubleshooting](troubleshooting.md) for common failure paths.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Experience Playbook (experimental)
|
|
2
|
+
|
|
3
|
+
> Companion to the [README](../README.md). This feature is experimental and off by default for prompt injection.
|
|
4
|
+
|
|
5
|
+
The playbook is an evidence-gated lessons store under `agent-state/playbook/`. Evidence-free lessons from every producer are retained as `quarantined`; only active, scope-matched lessons can be reused across runs.
|
|
6
|
+
|
|
7
|
+
Prompt injection is off by default. Set `ACE_PLAYBOOK=1` to inject active, scope-matched lessons into the stable system prompt block. Deterministic reflection can run at direct-lane run end while injection is off; disable it with `ACE_PLAYBOOK_REFLECT=0`.
|
|
8
|
+
|
|
9
|
+
The playbook is conservative by design. Use `ace eval --adapt` to compare baseline and adapted scorecards for your own models before changing defaults. `agent-state/PLAYBOOK.md` is a derived projection and can be regenerated with `ace playbook list`, `add`, `tag`, or `gc`.
|
|
10
|
+
|
|
11
|
+
The legacy `get_lessons` / `add_lesson` MCP tools read and write playbook bullets.
|
|
12
|
+
`add_lesson` currently creates a quarantined note because its legacy schema has no evidence field.
|
|
13
|
+
|
|
14
|
+
## CLI
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# List and inspect lessons
|
|
18
|
+
ace playbook list
|
|
19
|
+
ace playbook show pb-1234abcd
|
|
20
|
+
ace playbook add --section verification --content "Require evidence refs before completion."
|
|
21
|
+
ace playbook tag pb-1234abcd helpful
|
|
22
|
+
ace playbook gc
|
|
23
|
+
|
|
24
|
+
# Run an eval adaptation cycle and compare scorecards
|
|
25
|
+
ace eval --adapt --model qwen3:8b
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The packaged battery ships at `assets/eval-battery/battery.json` and is used by
|
|
29
|
+
default; pass `--battery <path>` to run your own. Each task/model/epoch runs in a
|
|
30
|
+
fresh disposable workspace seeded from the `fixtures/` directory adjacent to
|
|
31
|
+
the battery. Scorecards hash the artifacts created in that run; the caller's
|
|
32
|
+
project and stale artifacts are never used for scoring.
|
|
33
|
+
|
|
34
|
+
The packaged fixture includes `fixtures/edit-target.js`, used by both
|
|
35
|
+
`edit-1-single` and `env-4-tool`.
|