@mobrienv/autoloop 0.7.4 → 0.9.1

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/README.md CHANGED
@@ -59,6 +59,9 @@ If Ralph is the broader experimentation surface, autoloop is the cleaner runtime
59
59
  - **Designed for agents too** -- autoloop is intentionally shaped as a surface that agents can use directly, not just a human operator CLI
60
60
  - **Dynamic chains** -- compose presets into multi-stage pipelines
61
61
  - **Persistent memory + profiles** -- loops accumulate learnings across runs and can load repo/user tuning profiles
62
+ - **Cost budgets + stall protection** -- stop runaway loops automatically with `event_loop.max_cost_usd` (journaled token cost) and `event_loop.stall_iterations` (repeated identical outputs)
63
+ - **Runtime budgets** -- bound wall-clock time with `event_loop.max_runtime` (whole loop) and `event_loop.max_iteration_runtime` (per iteration, for iterations that wait days on long-running workflows); both take `"3d"`/`"12h"`-style durations
64
+ - **Finish notifications** -- run any command when a loop ends (`[notify] command = "..."`) with run metadata in env vars and a JSON payload on stdin
62
65
 
63
66
  ## What autoloop is
64
67
 
@@ -140,23 +143,34 @@ The main commands are:
140
143
 
141
144
  ```
142
145
  autoloop run <preset-name|preset-dir> [prompt...] [flags]
143
- autoloop list
144
- autoloop loops [--all]
145
- autoloop loops show <run-id>
146
- autoloop loops artifacts <run-id>
146
+ autoloop init [--preset <name>] [dir]
147
+ autoloop list [--json]
148
+ autoloop loops [--all] [--json]
149
+ autoloop loops show <run-id> [--json]
150
+ autoloop loops artifacts <run-id> [--json]
147
151
  autoloop loops watch <run-id>
152
+ autoloop loops health [--verbose] [--json]
148
153
  autoloop inspect <artifact> [selector] [project-dir] [--format <md|terminal|text|json|csv|graph>]
149
154
  autoloop dashboard [--port <port>]
150
- autoloop worktree <list|show|merge|clean> [args]
151
- autoloop chain <list|run> [args]
155
+ autoloop worktree <list|show|diff|merge|clean> [args]
156
+ autoloop chain list [project-dir]
157
+ autoloop chain run <name> [project-dir] [prompt...] [--dry-run] [--json]
152
158
  autoloop emit <topic> [summary]
153
- autoloop memory <list|status|find|add|remove> [args]
159
+ autoloop memory <list|status|find|add|remove|compact|prune> [args]
154
160
  autoloop task <add|complete|update|remove|list> [args]
155
161
  autoloop runs clean [--max-age <days>]
162
+ autoloop stats [project-dir] [--json]
163
+ autoloop doctor [project-dir] [--json]
164
+ autoloop triage [project-dir] [--json]
156
165
  autoloop config <show|set|unset|path> [args]
166
+ autoloop capabilities
167
+ autoloop robot-docs
168
+ autoloop --version
157
169
  ```
158
170
 
159
- Use `run` to start work, `loops` and `inspect` to understand what happened, and `dashboard` when you want a local operator surface.
171
+ Use `run` to start work, `loops` and `inspect` to understand what happened, and `dashboard` when you want a local operator surface. `stats` summarizes success rates and cost per preset; `doctor` diagnoses the environment and `.autoloop` state. `triage` is the one-call status command for agents — runs, health, doctor, and recommended next commands in a single (optionally `--json`) invocation. `capabilities` prints the machine-readable CLI contract (commands, JSON surfaces, exit codes) and `robot-docs` prints a paste-ready agent handbook.
172
+
173
+ Errors always go to stderr with a documented exit code (0 success, 1 user-input error, 2 environment error), and mistyped commands, subcommands, and flags get a "Did you mean" correction instead of being misinterpreted.
160
174
 
161
175
  ### Flags
162
176
 
@@ -164,7 +178,7 @@ Use `run` to start work, `loops` and `inspect` to understand what happened, and
164
178
  |------|-------------|
165
179
  | `-h`, `--help` | Show usage |
166
180
  | `-v`, `--verbose` | Debug-level logging |
167
- | `-b`, `--backend` | Override backend command (e.g. `-b claude`) |
181
+ | `-b`, `--backend` | Override backend (e.g. `-b claude-sdk`, `-b pi`, `-b kiro`, or a command) |
168
182
  | `-p`, `--preset` | Resolve a named or custom preset |
169
183
  | `--chain` | Run an inline chain of comma-separated presets |
170
184
  | `--profile <spec>` | Activate a profile (`repo:<name>` or `user:<name>`), repeatable |
@@ -219,6 +233,7 @@ Bundled presets give you opinionated starting points for common workflows like c
219
233
  | `autospec` | Research, clarify, design, plan, and critique specifications |
220
234
  | `automerge` | Merge a completed worktree branch back into its base branch |
221
235
  | `autopr` | Turn the current branch into a reviewable pull request |
236
+ | `autowiki` | Ingest a queue of source URLs into an OKF-conformant LLM wiki of cross-linked concept pages |
222
237
 
223
238
  ## Creating custom presets
224
239
 
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export { type Config, defaults as configDefaults, get as configGet, getInt as co
3
3
  export { emit, run, runParallelBranchCli } from "@mobrienv/autoloop-harness";
4
4
  export type { EmitResult } from "@mobrienv/autoloop-harness/emit";
5
5
  export type { LoopEvent, LoopEventEmitter, } from "@mobrienv/autoloop-harness/events";
6
- export type { LoopContext, RunOptions, RunSummary, TriggerSource, Verdict, VerdictKind, } from "@mobrienv/autoloop-harness/types";
6
+ export type { LoopContext, RunOptions, RunSummary, StopReason, TriggerSource, Verdict, VerdictKind, } from "@mobrienv/autoloop-harness/types";
7
+ export { STOP_REASONS } from "@mobrienv/autoloop-harness/types";
package/dist/index.js CHANGED
@@ -16,4 +16,5 @@ export { loadProject as loadProjectConfig } from "@mobrienv/autoloop-core/config
16
16
  // without re-implementing the schema layer.
17
17
  export { defaults as configDefaults, get as configGet, getInt as configGetInt, getList as configGetList, parseToml as parseConfigToml, } from "@mobrienv/autoloop-core/config-schema";
18
18
  export { emit, run, runParallelBranchCli } from "@mobrienv/autoloop-harness";
19
+ export { STOP_REASONS } from "@mobrienv/autoloop-harness/types";
19
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,yEAAyE;AACzE,yEAAyE;AACzE,2EAA2E;AAC3E,EAAE;AACF,SAAS;AACT,8DAA8D;AAC9D,EAAE;AACF,gEAAgE;AAChE,iCAAiC;AACjC,sDAAsD;AACtD,QAAQ;AAER,OAAO,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAClF,uEAAuE;AACvE,4CAA4C;AAC5C,OAAO,EAEL,QAAQ,IAAI,cAAc,EAC1B,GAAG,IAAI,SAAS,EAChB,MAAM,IAAI,YAAY,EACtB,OAAO,IAAI,aAAa,EAExB,SAAS,IAAI,eAAe,GAC7B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,yEAAyE;AACzE,yEAAyE;AACzE,2EAA2E;AAC3E,EAAE;AACF,SAAS;AACT,8DAA8D;AAC9D,EAAE;AACF,gEAAgE;AAChE,iCAAiC;AACjC,sDAAsD;AACtD,QAAQ;AAER,OAAO,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAClF,uEAAuE;AACvE,4CAA4C;AAC5C,OAAO,EAEL,QAAQ,IAAI,cAAc,EAC1B,GAAG,IAAI,SAAS,EAChB,MAAM,IAAI,YAAY,EACtB,OAAO,IAAI,aAAa,EAExB,SAAS,IAAI,eAAe,GAC7B,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAe7E,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC"}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Deterministic mock ACP stdio server for autoloop integration tests.
4
+ *
5
+ * Speaks newline-delimited JSON-RPC 2.0 on stdin/stdout, implementing the
6
+ * minimal agent surface the autoloop ACP client exercises:
7
+ *
8
+ * initialize → echoes the requested protocol version
9
+ * session/new → returns a fixed session id
10
+ * session/set_mode → records the mode id
11
+ * session/set_model → records the model id
12
+ * session/prompt → requests tool permission from the client, streams an
13
+ * agent_message_chunk that reports the recorded
14
+ * mode/model/permission outcome, then ends the turn
15
+ *
16
+ * Environment knobs:
17
+ * MOCK_ACP_RESPONSE extra response text (defaults to "LOOP_COMPLETE")
18
+ * MOCK_ACP_KIRO_NOISE when "1", emits a provider-private `_kiro.dev/...`
19
+ * notification that ACP clients must filter out
20
+ */
21
+ export {};
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Deterministic mock ACP stdio server for autoloop integration tests.
4
+ *
5
+ * Speaks newline-delimited JSON-RPC 2.0 on stdin/stdout, implementing the
6
+ * minimal agent surface the autoloop ACP client exercises:
7
+ *
8
+ * initialize → echoes the requested protocol version
9
+ * session/new → returns a fixed session id
10
+ * session/set_mode → records the mode id
11
+ * session/set_model → records the model id
12
+ * session/prompt → requests tool permission from the client, streams an
13
+ * agent_message_chunk that reports the recorded
14
+ * mode/model/permission outcome, then ends the turn
15
+ *
16
+ * Environment knobs:
17
+ * MOCK_ACP_RESPONSE extra response text (defaults to "LOOP_COMPLETE")
18
+ * MOCK_ACP_KIRO_NOISE when "1", emits a provider-private `_kiro.dev/...`
19
+ * notification that ACP clients must filter out
20
+ */
21
+ let modeId = "none";
22
+ let modelId = "none";
23
+ let nextOutboundId = 1000;
24
+ const pendingOutbound = new Map();
25
+ function send(message) {
26
+ process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", ...message })}\n`);
27
+ }
28
+ function respond(id, result) {
29
+ send({ id, result });
30
+ }
31
+ function notify(method, params) {
32
+ send({ method, params });
33
+ }
34
+ function request(method, params) {
35
+ const id = nextOutboundId++;
36
+ return new Promise((resolve) => {
37
+ pendingOutbound.set(id, resolve);
38
+ send({ id, method, params });
39
+ });
40
+ }
41
+ async function handlePrompt(msg) {
42
+ const params = msg.params;
43
+ const permission = (await request("session/request_permission", {
44
+ sessionId: params.sessionId,
45
+ toolCall: {
46
+ toolCallId: "mock-tool-1",
47
+ title: "mock tool",
48
+ kind: "execute",
49
+ status: "pending",
50
+ },
51
+ options: [
52
+ { optionId: "allow", name: "Allow always", kind: "allow_always" },
53
+ { optionId: "reject", name: "Reject", kind: "reject_once" },
54
+ ],
55
+ }));
56
+ const outcome = permission?.outcome?.outcome ?? "none";
57
+ const optionId = permission?.outcome?.optionId ?? "none";
58
+ if (process.env.MOCK_ACP_KIRO_NOISE === "1") {
59
+ notify("_kiro.dev/heartbeat", { noise: true });
60
+ }
61
+ const extra = process.env.MOCK_ACP_RESPONSE ?? "LOOP_COMPLETE";
62
+ const text = `mock-acp mode=${modeId} model=${modelId} permission=${outcome}:${optionId}\n${extra}`;
63
+ notify("session/update", {
64
+ sessionId: params.sessionId,
65
+ update: {
66
+ sessionUpdate: "agent_message_chunk",
67
+ content: { type: "text", text },
68
+ },
69
+ });
70
+ if (msg.id !== undefined)
71
+ respond(msg.id, { stopReason: "end_turn" });
72
+ }
73
+ function handleMessage(msg) {
74
+ // Response to one of our outbound requests (permission flow)
75
+ if (msg.id !== undefined && msg.method === undefined) {
76
+ const resolve = pendingOutbound.get(msg.id);
77
+ if (resolve) {
78
+ pendingOutbound.delete(msg.id);
79
+ resolve(msg.result);
80
+ }
81
+ return;
82
+ }
83
+ switch (msg.method) {
84
+ case "initialize": {
85
+ const params = msg.params;
86
+ if (msg.id !== undefined)
87
+ respond(msg.id, {
88
+ protocolVersion: params?.protocolVersion ?? 1,
89
+ agentCapabilities: {},
90
+ });
91
+ return;
92
+ }
93
+ case "session/new":
94
+ if (msg.id !== undefined)
95
+ respond(msg.id, { sessionId: "mock-acp-session" });
96
+ return;
97
+ case "session/set_mode": {
98
+ modeId = String(msg.params?.modeId ?? "none");
99
+ if (msg.id !== undefined)
100
+ respond(msg.id, {});
101
+ return;
102
+ }
103
+ case "session/set_model": {
104
+ modelId = String(msg.params?.modelId ?? "none");
105
+ if (msg.id !== undefined)
106
+ respond(msg.id, {});
107
+ return;
108
+ }
109
+ case "session/prompt":
110
+ void handlePrompt(msg);
111
+ return;
112
+ default:
113
+ // Unknown request → empty result; notifications (e.g. session/cancel) ignored
114
+ if (msg.id !== undefined)
115
+ respond(msg.id, {});
116
+ return;
117
+ }
118
+ }
119
+ let buffer = "";
120
+ process.stdin.setEncoding("utf-8");
121
+ process.stdin.on("data", (chunk) => {
122
+ buffer += chunk;
123
+ const lines = buffer.split("\n");
124
+ buffer = lines.pop() ?? "";
125
+ for (const line of lines) {
126
+ const trimmed = line.trim();
127
+ if (!trimmed)
128
+ continue;
129
+ try {
130
+ handleMessage(JSON.parse(trimmed));
131
+ }
132
+ catch {
133
+ /* skip malformed input */
134
+ }
135
+ }
136
+ });
137
+ process.stdin.on("end", () => process.exit(0));
138
+ export {};
139
+ //# sourceMappingURL=mock-acp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-acp-server.js","sourceRoot":"","sources":["../../src/testing/mock-acp-server.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@
9
9
  * or accepts a fixture path as the first positional argument.
10
10
  */
11
11
  import { execFileSync } from "node:child_process";
12
- import { readFileSync } from "node:fs";
12
+ import { readFileSync, writeFileSync } from "node:fs";
13
13
  import { createRequire } from "node:module";
14
14
  function fixturePathFromArgs() {
15
15
  return process.argv[2] ?? "";
@@ -29,6 +29,8 @@ function loadFixture() {
29
29
  delay_ms: parsed.delay_ms ?? 0,
30
30
  emit_event: parsed.emit_event,
31
31
  emit_payload: parsed.emit_payload,
32
+ usage: parsed.usage,
33
+ trap_usr1: parsed.trap_usr1 ?? false,
32
34
  };
33
35
  }
34
36
  catch (err) {
@@ -56,6 +58,12 @@ function sleep(ms) {
56
58
  }
57
59
  async function main() {
58
60
  const fixture = loadFixture();
61
+ if (fixture.trap_usr1) {
62
+ process.on("SIGUSR1", () => {
63
+ process.stdout.write("mock-backend: interrupted by SIGUSR1\n");
64
+ process.exit(130);
65
+ });
66
+ }
59
67
  if (fixture.delay_ms > 0) {
60
68
  await sleep(fixture.delay_ms);
61
69
  }
@@ -65,6 +73,12 @@ async function main() {
65
73
  if (fixture.output) {
66
74
  process.stdout.write(fixture.output);
67
75
  }
76
+ if (fixture.usage) {
77
+ const usageFile = process.env.AUTOLOOP_USAGE_FILE;
78
+ if (usageFile) {
79
+ writeFileSync(usageFile, JSON.stringify(fixture.usage));
80
+ }
81
+ }
68
82
  process.exitCode = fixture.exit_code;
69
83
  }
70
84
  main().catch((err) => {
@@ -1 +1 @@
1
- {"version":3,"file":"mock-backend.js","sourceRoot":"","sources":["../../src/testing/mock-backend.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAU5C,SAAS,mBAAmB;IAC1B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/B,CAAC;AAED,SAAS,WAAW;IAClB,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,mBAAmB,EAAE,CAAC;IAC3E,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,8FAA8F,CAC/F,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAqB,CAAC;QACnD,OAAO;YACL,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,CAAC;YAChC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC;YAC9B,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,YAAY,EAAE,MAAM,CAAC,YAAY;SAClC,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yCAAyC,GAAG,IAAI,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAa,EAAE,OAAe;IAC/C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAE5D,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE;YAClE,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;YAClC,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,GAAG,IAAI,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAE9B,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;AACvC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,GAAG,IAAI,CAAC,CAAC;IACjE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"mock-backend.js","sourceRoot":"","sources":["../../src/testing/mock-backend.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobrienv/autoloop",
3
- "version": "0.7.4",
3
+ "version": "0.9.1",
4
4
  "license": "MIT",
5
5
  "description": "Simpler, opinionated loop harness for inspectable long-running agent workflows",
6
6
  "type": "module",
@@ -32,7 +32,10 @@
32
32
  "packages/harness",
33
33
  "packages/dashboard",
34
34
  "packages/kanban",
35
- "packages/cli"
35
+ "packages/cli",
36
+ "packages/issue-sync-core",
37
+ "packages/gh-sync",
38
+ "packages/linear-sync"
36
39
  ],
37
40
  "repository": {
38
41
  "type": "git",
@@ -62,7 +65,7 @@
62
65
  "format": "biome format src/ test/",
63
66
  "format:fix": "biome format --write src/ test/",
64
67
  "test": "node --experimental-vm-modules node_modules/.bin/vitest run",
65
- "test:coverage": "node --experimental-vm-modules node_modules/.bin/vitest run --coverage",
68
+ "test:coverage": "node --experimental-vm-modules node_modules/.bin/vitest run --no-file-parallelism --coverage",
66
69
  "test:watch": "node --experimental-vm-modules node_modules/.bin/vitest",
67
70
  "check": "biome check src/ test/ && tsc --noEmit && npm run test:coverage",
68
71
  "release": "node bin/release",
@@ -90,9 +93,9 @@
90
93
  "vitest": "^3.0.0"
91
94
  },
92
95
  "dependencies": {
93
- "@mobrienv/autoloop-cli": "0.7.4",
94
- "@mobrienv/autoloop-core": "0.7.4",
95
- "@mobrienv/autoloop-harness": "0.7.4",
96
- "@mobrienv/autoloop-presets": "0.7.4"
96
+ "@mobrienv/autoloop-cli": "0.9.1",
97
+ "@mobrienv/autoloop-core": "0.9.1",
98
+ "@mobrienv/autoloop-harness": "0.9.1",
99
+ "@mobrienv/autoloop-presets": "0.9.1"
97
100
  }
98
101
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "autoloop",
3
- "version": "0.7.4",
3
+ "version": "0.9.1",
4
4
  "description": "Run and operate autoloops — start runs, monitor progress, inject guidance, manage worktrees, inspect artifacts, and clean up.",
5
- "homepage": "https://github.com/mikeyobrien/autoloop-ts",
6
- "repository": "https://github.com/mikeyobrien/autoloop-ts",
5
+ "homepage": "https://github.com/mikeyobrien/autoloop",
6
+ "repository": "https://github.com/mikeyobrien/autoloop",
7
7
  "license": "MIT",
8
8
  "keywords": ["autoloop", "ai-agents", "autonomous", "coding"]
9
9
  }
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: autoloop
3
3
  description: Run and operate autoloops — start runs, monitor progress, inject guidance, manage worktrees, inspect artifacts, and clean up. Use when the user asks to run an autoloop, check loop status, merge/clean worktrees, or operate on runs.
4
- argument-hint: [run|status|guide|merge|clean|inspect] [args...]
4
+ argument-hint: "[run|status|guide|merge|clean|inspect] [args...]"
5
5
  ---
6
6
 
7
7
  # Autoloop Operations
@@ -32,7 +32,7 @@ autoloop run --chain autocode,autoqa "objective" --worktree
32
32
 
33
33
  **When to use `--automerge`:** When the user wants hands-off operation. Appends an automerge step that squash-merges on completion.
34
34
 
35
- **Backend override:** Use `-b claude` or `-b pi` or `-b kiro` to switch backends.
35
+ **Backend override:** Use `-b claude`, `-b pi`, `-b kiro`, `-b claude-agent-acp`, or `-b acp:<provider>:<command>` to switch backends.
36
36
 
37
37
  Use `run_in_background: true` on the Bash tool when starting runs so the user isn't blocked.
38
38
 
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: autoloop-acp
3
+ description: Drive autoloop over the Agent Client Protocol (ACP) — connect an external editor, harness, or agent to `autoloop acp` over stdio, send prompts/slash commands that map to autoloop verbs, and stream loop runs as tool calls. Use when wiring up or operating an ACP connection to autoloop from another system.
4
+ argument-hint: "[connect|run|<slash-command>] [args...]"
5
+ ---
6
+
7
+ # Autoloop over ACP
8
+
9
+ `autoloop acp` presents an **Agent Client Protocol** (ACP) interface over stdio. The external system (an editor, harness, or another agent) is the ACP **client**; autoloop is the ACP **agent**. This skill is for setting up that connection and driving autoloop through it. Parse `$ARGUMENTS` to determine what the user needs; if ambiguous, ask.
10
+
11
+ > Direction matters. This skill is about **other systems driving autoloop** (autoloop is the agent). The inverse — autoloop *consuming* an external ACP agent as a backend — is the separate `-b kiro` option and is **not** what this covers.
12
+
13
+ ## Launching the agent
14
+
15
+ ```bash
16
+ # Start the ACP agent on stdio (the client spawns this as a subprocess)
17
+ autoloop acp
18
+
19
+ # Surface debug logs as agent thoughts
20
+ autoloop acp --verbose # or -v
21
+
22
+ # Usage
23
+ autoloop acp --help # or -h
24
+ ```
25
+
26
+ **Transport rules (important):**
27
+ - Frames are **NDJSON over stdio**. **Stdout is the protocol channel** — nothing else may write to it. All logs go to **stderr**.
28
+ - The client therefore launches `autoloop acp` as a subprocess and speaks ACP on stdin/stdout. Don't pipe other output into stdout.
29
+
30
+ **Working directory (REQUIRED):** per session. The ACP client **must** set it via the `session/new` `cwd` field, as the absolute path of the target project directory. autoloop anchors **all run state** (journal, registry, `runs/`) on `cwd`. If `cwd` is missing or blank, `session/new` is **rejected** with a JSON-RPC `invalid params` error — autoloop does **not** silently fall back to its own launch directory, because doing so would misroute the entire run into the wrong project. `--project-dir` / `AUTOLOOP_PROJECT_DIR` only affect dashboard control; they are not a fallback for the session working directory.
31
+
32
+ ### Representative client config
33
+
34
+ ACP clients differ, but they spawn the agent as a command + args. A generic entry looks like:
35
+
36
+ ```json
37
+ {
38
+ "command": "autoloop",
39
+ "args": ["acp"]
40
+ }
41
+ ```
42
+
43
+ Add `"--verbose"` to `args` if needed. The client **must** send a valid `cwd` on `session/new` (see Working directory above). No authentication step is required — `authenticate` is a no-op because autoloop runs locally under the caller's own credentials.
44
+
45
+ ## What the client sees
46
+
47
+ On `initialize`, autoloop reports:
48
+ - `agentInfo`: `{ name: "autoloop", version: "0.1.0" }`
49
+ - `agentCapabilities`: `{ loadSession: false }` — sessions are not resumable; one session lives for the life of the connection and can launch many runs and quick commands over successive prompt turns.
50
+
51
+ On `session/new`, autoloop **requires** a valid `cwd` (rejecting the session otherwise) and advertises its verbs as **slash commands** (`available_commands_update`), each with a description and an input hint.
52
+
53
+ ## Prompt behaviour
54
+
55
+ Each prompt turn's text is dispatched as an autoloop command line:
56
+
57
+ - **Bare objective** (no recognised verb) → runs the default preset: `run autocode "<your prompt>"`. So sending `build the login page` starts an `autocode` loop on that objective.
58
+ - **Explicit verb** or **`/slash` command** always overrides the default (e.g. `run autofix "..."`, `/loops`, `inspect scratchpad`).
59
+ - A single outer **XML-ish wrapper** is stripped before parsing — `<user_message>`, `<user>`, `<message>`, `<query>`, or `<prompt>`. This makes model-driven clients that wrap prompts work transparently. Unrecognised tags are left untouched.
60
+ - Tokenising honours single and double quotes, so quoted objectives with spaces survive: `run autocode "Fix the login bug"`.
61
+ - An empty prompt returns help text.
62
+
63
+ ## Command surface
64
+
65
+ All 14 verbs work both as bare prompt lines and as `/slash` commands. They run in one of three modes:
66
+
67
+ ### Stream mode — long-running loops, streamed as ACP tool calls
68
+
69
+ | Verb | Hint | Description |
70
+ |---|---|---|
71
+ | `run` | `<preset> [objective] [flags]` | Start a loop with a preset (e.g. `run autocode "Fix bug"`) |
72
+ | `chain` | `<list\|run> [args]` | Run or list chains of presets |
73
+
74
+ These execute a loop and bridge its events onto ACP `session/update` notifications as tool calls. The turn ends with a summary message.
75
+
76
+ ### Capture mode — quick commands, returns captured text
77
+
78
+ | Verb | Hint | Description |
79
+ |---|---|---|
80
+ | `loops` | `[--all\|show <id>\|artifacts <id>\|health]` | List active/recent runs or show/health a run |
81
+ | `inspect` | `<artifact> [selector] [--format <fmt>]` | Inspect a run artifact (journal, scratchpad, metrics, ...) |
82
+ | `guide` | `[--run <id>] <message>` | Inject operator guidance into the next iteration of a run |
83
+ | `list` | | List available presets |
84
+ | `memory` | `<list\|status\|find\|add\|remove> [args]` | Manage persistent loop memory |
85
+ | `task` | `<add\|complete\|update\|remove\|list> [args]` | Manage loop tasks |
86
+ | `worktree` | `<list\|show\|merge\|clean> [args]` | Manage git worktrees for isolated runs |
87
+ | `runs` | `clean [--max-age <days>]` | Maintain run directories |
88
+ | `config` | `<show\|set\|unset\|path> [args]` | Show or edit autoloop configuration |
89
+ | `control` | `<show\|capabilities\|interrupt\|guide> <id>` | Inspect or control a live run |
90
+ | `emit` | `<topic> [summary]` | Emit a coordination topic event into a run |
91
+
92
+ These run synchronously with stdout/stderr captured and return the text as a single agent message.
93
+
94
+ ### Control mode — dashboard lifecycle
95
+
96
+ | Verb | Hint | Description |
97
+ |---|---|---|
98
+ | `dashboard` | `[start\|stop\|status] [--port <port>] [--host <host>]` | Start/stop the local dashboard and return its URL |
99
+
100
+ Handled directly by the agent. On start, the dashboard **URL is returned on its own line** so clients can linkify it.
101
+
102
+ ## Streaming & cancellation
103
+
104
+ - **Stream verbs** (`run`, `chain`) emit live `session/update` notifications as the loop runs, then a final summary with a stop reason.
105
+ - **Capture verbs** return their full captured output in one message.
106
+ - Cancel an in-flight turn with the ACP **`session/cancel`** notification — it aborts the active turn (and the running loop) for that session.
107
+
108
+ ## Quick reference
109
+
110
+ | The client wants to... | Send this prompt |
111
+ |---|---|
112
+ | Start a feature loop | `run autocode "..."` (or just the bare objective) |
113
+ | Fix a bug | `run autofix "..."` |
114
+ | List/inspect runs | `loops` / `loops show <id>` / `inspect scratchpad` |
115
+ | Steer a running loop | `guide "..."` |
116
+ | List presets | `list` |
117
+ | Open the dashboard | `dashboard start` (URL returned on its own line) |
118
+ | Cancel the current turn | ACP `session/cancel` notification |