@os-eco/overstory-cli 0.6.5 → 0.6.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/README.md +60 -60
- package/agents/builder.md +16 -16
- package/agents/coordinator.md +57 -57
- package/agents/issue-reviews.md +71 -0
- package/agents/lead.md +43 -42
- package/agents/merger.md +15 -15
- package/agents/monitor.md +37 -37
- package/agents/pr-reviews.md +60 -0
- package/agents/prioritize.md +110 -0
- package/agents/release.md +56 -0
- package/agents/reviewer.md +15 -15
- package/agents/scout.md +18 -18
- package/agents/supervisor.md +78 -78
- package/package.json +1 -1
- package/src/agents/hooks-deployer.test.ts +23 -26
- package/src/agents/hooks-deployer.ts +9 -5
- package/src/agents/overlay.test.ts +5 -5
- package/src/agents/overlay.ts +11 -11
- package/src/commands/agents.ts +7 -6
- package/src/commands/clean.ts +5 -5
- package/src/commands/completions.test.ts +10 -10
- package/src/commands/completions.ts +26 -28
- package/src/commands/coordinator.test.ts +2 -2
- package/src/commands/coordinator.ts +12 -12
- package/src/commands/costs.ts +1 -1
- package/src/commands/dashboard.ts +8 -8
- package/src/commands/doctor.ts +4 -4
- package/src/commands/errors.ts +1 -1
- package/src/commands/feed.ts +1 -1
- package/src/commands/group.ts +3 -3
- package/src/commands/hooks.test.ts +7 -7
- package/src/commands/hooks.ts +7 -7
- package/src/commands/init.test.ts +6 -2
- package/src/commands/init.ts +19 -19
- package/src/commands/inspect.ts +19 -19
- package/src/commands/log.ts +3 -3
- package/src/commands/logs.ts +1 -1
- package/src/commands/mail.test.ts +2 -2
- package/src/commands/mail.ts +28 -11
- package/src/commands/merge.ts +7 -7
- package/src/commands/metrics.test.ts +1 -1
- package/src/commands/metrics.ts +2 -2
- package/src/commands/monitor.test.ts +5 -5
- package/src/commands/monitor.ts +4 -4
- package/src/commands/nudge.ts +1 -1
- package/src/commands/prime.test.ts +1 -1
- package/src/commands/prime.ts +2 -2
- package/src/commands/replay.ts +1 -1
- package/src/commands/run.ts +2 -2
- package/src/commands/sling.test.ts +84 -2
- package/src/commands/sling.ts +97 -9
- package/src/commands/spec.ts +8 -9
- package/src/commands/status.test.ts +2 -2
- package/src/commands/status.ts +2 -4
- package/src/commands/stop.ts +2 -2
- package/src/commands/supervisor.test.ts +1 -1
- package/src/commands/supervisor.ts +4 -4
- package/src/commands/trace.test.ts +2 -2
- package/src/commands/trace.ts +4 -4
- package/src/commands/watch.ts +5 -5
- package/src/commands/worktree.test.ts +3 -3
- package/src/commands/worktree.ts +11 -11
- package/src/doctor/dependencies.test.ts +5 -5
- package/src/doctor/dependencies.ts +2 -2
- package/src/doctor/logs.ts +1 -1
- package/src/doctor/structure.test.ts +1 -1
- package/src/doctor/structure.ts +1 -1
- package/src/doctor/version.test.ts +3 -3
- package/src/doctor/version.ts +1 -1
- package/src/e2e/init-sling-lifecycle.test.ts +6 -2
- package/src/index.ts +11 -9
- package/src/mail/client.test.ts +1 -1
- package/src/mail/client.ts +2 -2
- package/src/mulch/client.ts +1 -1
- package/src/worktree/tmux.test.ts +8 -3
- package/src/worktree/tmux.ts +19 -18
- package/templates/CLAUDE.md.tmpl +27 -27
- package/templates/hooks.json.tmpl +15 -11
- package/templates/overlay.md.tmpl +7 -7
|
@@ -66,7 +66,7 @@ describe("checkDependencies", () => {
|
|
|
66
66
|
expect(toolNames).toContain("tmux availability");
|
|
67
67
|
expect(toolNames).toContain("sd availability");
|
|
68
68
|
expect(toolNames).toContain("mulch availability");
|
|
69
|
-
expect(toolNames).toContain("
|
|
69
|
+
expect(toolNames).toContain("ov availability");
|
|
70
70
|
expect(toolNames).toContain("cn availability");
|
|
71
71
|
});
|
|
72
72
|
|
|
@@ -201,9 +201,9 @@ describe("checkDependencies", () => {
|
|
|
201
201
|
expect(mlAlias?.category).toBe("dependencies");
|
|
202
202
|
expect(["pass", "warn"]).toContain(mlAlias?.status ?? "");
|
|
203
203
|
}
|
|
204
|
-
const ovCheck = checks.find((c) => c.name === "
|
|
204
|
+
const ovCheck = checks.find((c) => c.name === "ov availability");
|
|
205
205
|
if (ovCheck?.status === "pass") {
|
|
206
|
-
const ovAlias = checks.find((c) => c.name === "
|
|
206
|
+
const ovAlias = checks.find((c) => c.name === "overstory alias");
|
|
207
207
|
expect(ovAlias).toBeDefined();
|
|
208
208
|
expect(["pass", "warn"]).toContain(ovAlias?.status ?? "");
|
|
209
209
|
}
|
|
@@ -229,9 +229,9 @@ describe("checkDependencies", () => {
|
|
|
229
229
|
}
|
|
230
230
|
});
|
|
231
231
|
|
|
232
|
-
test("includes
|
|
232
|
+
test("includes ov availability check", async () => {
|
|
233
233
|
const checks = await checkDependencies(mockConfig, "/tmp/.overstory");
|
|
234
|
-
const ovCheck = checks.find((c) => c.name === "
|
|
234
|
+
const ovCheck = checks.find((c) => c.name === "ov availability");
|
|
235
235
|
expect(ovCheck).toBeDefined();
|
|
236
236
|
expect(ovCheck?.category).toBe("dependencies");
|
|
237
237
|
});
|
|
@@ -42,10 +42,10 @@ export const checkDependencies: DoctorCheckFn = async (
|
|
|
42
42
|
installHint: "@os-eco/mulch-cli",
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
|
-
name: "
|
|
45
|
+
name: "ov",
|
|
46
46
|
versionFlag: "--version",
|
|
47
47
|
required: true,
|
|
48
|
-
alias: "
|
|
48
|
+
alias: "overstory",
|
|
49
49
|
installHint: "@os-eco/overstory-cli",
|
|
50
50
|
},
|
|
51
51
|
{
|
package/src/doctor/logs.ts
CHANGED
|
@@ -177,7 +177,7 @@ export const checkLogs: DoctorCheckFn = async (_config, overstoryDir): Promise<D
|
|
|
177
177
|
totalBytes > DISK_USAGE_WARN_THRESHOLD
|
|
178
178
|
? [
|
|
179
179
|
`Exceeds ${formatBytes(DISK_USAGE_WARN_THRESHOLD)} threshold`,
|
|
180
|
-
"Consider running '
|
|
180
|
+
"Consider running 'ov worktree clean --completed' to remove old logs",
|
|
181
181
|
]
|
|
182
182
|
: undefined,
|
|
183
183
|
fixable: totalBytes > DISK_USAGE_WARN_THRESHOLD,
|
|
@@ -104,7 +104,7 @@ describe("checkStructure", () => {
|
|
|
104
104
|
await Bun.write(
|
|
105
105
|
join(overstoryDir, ".gitignore"),
|
|
106
106
|
`# Wildcard+whitelist: ignore everything, whitelist tracked files
|
|
107
|
-
# Auto-healed by
|
|
107
|
+
# Auto-healed by ov prime on each session start
|
|
108
108
|
*
|
|
109
109
|
!.gitignore
|
|
110
110
|
!config.yaml
|
package/src/doctor/structure.ts
CHANGED
|
@@ -32,7 +32,7 @@ export const checkStructure: DoctorCheckFn = async (
|
|
|
32
32
|
category: "structure",
|
|
33
33
|
status: overstoryDirExists ? "pass" : "fail",
|
|
34
34
|
message: overstoryDirExists ? "Directory exists" : "Directory missing",
|
|
35
|
-
details: overstoryDirExists ? undefined : ["Run '
|
|
35
|
+
details: overstoryDirExists ? undefined : ["Run 'ov init' to create it"],
|
|
36
36
|
fixable: !overstoryDirExists,
|
|
37
37
|
});
|
|
38
38
|
|
|
@@ -70,7 +70,7 @@ describe("checkVersion", () => {
|
|
|
70
70
|
const versionCheck = checks.find((c) => c.name === "version-current");
|
|
71
71
|
expect(versionCheck).toBeDefined();
|
|
72
72
|
expect(versionCheck?.status).toBeOneOf(["pass", "warn", "fail"]);
|
|
73
|
-
expect(versionCheck?.message).toContain("
|
|
73
|
+
expect(versionCheck?.message).toContain("ov");
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
test("includes package-json-sync check", async () => {
|
|
@@ -88,8 +88,8 @@ describe("checkVersion", () => {
|
|
|
88
88
|
expect(versionCheck).toBeDefined();
|
|
89
89
|
|
|
90
90
|
if (versionCheck?.status === "pass") {
|
|
91
|
-
// Message should contain version in format "
|
|
92
|
-
expect(versionCheck.message).toMatch(/
|
|
91
|
+
// Message should contain version in format "ov vX.Y.Z"
|
|
92
|
+
expect(versionCheck.message).toMatch(/ov v\d+\.\d+\.\d+/);
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
|
package/src/doctor/version.ts
CHANGED
|
@@ -47,7 +47,7 @@ async function checkCurrentVersion(toolRoot: string): Promise<DoctorCheck> {
|
|
|
47
47
|
name: "version-current",
|
|
48
48
|
category: "version",
|
|
49
49
|
status: "pass",
|
|
50
|
-
message: `
|
|
50
|
+
message: `ov v${packageJson.version}`,
|
|
51
51
|
};
|
|
52
52
|
} catch (error) {
|
|
53
53
|
return {
|
|
@@ -22,9 +22,13 @@ import type { OverlayConfig } from "../types.ts";
|
|
|
22
22
|
const EXPECTED_AGENT_DEFS = [
|
|
23
23
|
"builder.md",
|
|
24
24
|
"coordinator.md",
|
|
25
|
+
"issue-reviews.md",
|
|
25
26
|
"lead.md",
|
|
26
27
|
"merger.md",
|
|
27
28
|
"monitor.md",
|
|
29
|
+
"pr-reviews.md",
|
|
30
|
+
"prioritize.md",
|
|
31
|
+
"release.md",
|
|
28
32
|
"reviewer.md",
|
|
29
33
|
"scout.md",
|
|
30
34
|
"supervisor.md",
|
|
@@ -109,7 +113,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
|
|
|
109
113
|
expect(config.project.name).toBeTruthy();
|
|
110
114
|
});
|
|
111
115
|
|
|
112
|
-
test("manifest loads successfully with all
|
|
116
|
+
test("manifest loads successfully with all 12 agents", async () => {
|
|
113
117
|
await initCommand({});
|
|
114
118
|
|
|
115
119
|
const manifestPath = join(tempDir, ".overstory", "agent-manifest.json");
|
|
@@ -269,7 +273,7 @@ describe("E2E: init→sling lifecycle on external project", () => {
|
|
|
269
273
|
expect(overlayContent).toContain("orchestrator");
|
|
270
274
|
expect(overlayContent).toContain("`src/main.ts`");
|
|
271
275
|
expect(overlayContent).toContain("`src/utils.ts`");
|
|
272
|
-
expect(overlayContent).toContain("
|
|
276
|
+
expect(overlayContent).toContain("ml prime typescript");
|
|
273
277
|
|
|
274
278
|
// No unresolved placeholders
|
|
275
279
|
expect(overlayContent).not.toMatch(/\{\{[A-Z_]+\}\}/);
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Overstory CLI — main entry point and command router.
|
|
5
5
|
*
|
|
6
6
|
* Routes subcommands to their respective handlers in src/commands/.
|
|
7
|
-
* Usage:
|
|
7
|
+
* Usage: ov <command> [args...]
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { Command } from "commander";
|
|
@@ -42,7 +42,7 @@ import { createWorktreeCommand } from "./commands/worktree.ts";
|
|
|
42
42
|
import { OverstoryError, WorktreeError } from "./errors.ts";
|
|
43
43
|
import { setQuiet } from "./logging/color.ts";
|
|
44
44
|
|
|
45
|
-
const VERSION = "0.6.
|
|
45
|
+
const VERSION = "0.6.6";
|
|
46
46
|
|
|
47
47
|
const COMMANDS = [
|
|
48
48
|
"agents",
|
|
@@ -113,9 +113,9 @@ function suggestCommand(input: string): string | undefined {
|
|
|
113
113
|
const program = new Command();
|
|
114
114
|
|
|
115
115
|
program
|
|
116
|
-
.name("
|
|
116
|
+
.name("ov")
|
|
117
117
|
.description("Multi-agent orchestration for Claude Code")
|
|
118
|
-
.version(`
|
|
118
|
+
.version(`ov v${VERSION}`, "-v, --version")
|
|
119
119
|
.option("-q, --quiet", "Suppress non-error output")
|
|
120
120
|
.option("--json", "JSON output")
|
|
121
121
|
.option("--verbose", "Verbose output");
|
|
@@ -295,7 +295,7 @@ program.on("command:*", (operands) => {
|
|
|
295
295
|
if (suggestion) {
|
|
296
296
|
process.stderr.write(`Did you mean '${suggestion}'?\n`);
|
|
297
297
|
}
|
|
298
|
-
process.stderr.write("Run '
|
|
298
|
+
process.stderr.write("Run 'ov --help' for usage.\n");
|
|
299
299
|
process.exit(1);
|
|
300
300
|
});
|
|
301
301
|
|
|
@@ -307,20 +307,22 @@ if (import.meta.main)
|
|
|
307
307
|
main().catch((err: unknown) => {
|
|
308
308
|
// Friendly message when running outside a git repository
|
|
309
309
|
if (err instanceof WorktreeError && err.message.includes("not a git repository")) {
|
|
310
|
-
process.stderr.write("Not in an overstory project. Run '
|
|
310
|
+
process.stderr.write("Not in an overstory project. Run 'ov init' first.\n");
|
|
311
311
|
process.exit(1);
|
|
312
312
|
}
|
|
313
313
|
if (err instanceof OverstoryError) {
|
|
314
314
|
process.stderr.write(`Error [${err.code}]: ${err.message}\n`);
|
|
315
|
-
process.
|
|
315
|
+
process.exitCode = 1;
|
|
316
|
+
return;
|
|
316
317
|
}
|
|
317
318
|
if (err instanceof Error) {
|
|
318
319
|
process.stderr.write(`Error: ${err.message}\n`);
|
|
319
320
|
if (process.argv.includes("--verbose")) {
|
|
320
321
|
process.stderr.write(`${err.stack}\n`);
|
|
321
322
|
}
|
|
322
|
-
process.
|
|
323
|
+
process.exitCode = 1;
|
|
324
|
+
return;
|
|
323
325
|
}
|
|
324
326
|
process.stderr.write(`Unknown error: ${String(err)}\n`);
|
|
325
|
-
process.
|
|
327
|
+
process.exitCode = 1;
|
|
326
328
|
});
|
package/src/mail/client.test.ts
CHANGED
|
@@ -225,7 +225,7 @@ describe("createMailClient", () => {
|
|
|
225
225
|
});
|
|
226
226
|
|
|
227
227
|
const result = client.checkInject("orchestrator");
|
|
228
|
-
expect(result).toContain(`
|
|
228
|
+
expect(result).toContain(`ov mail reply ${id}`);
|
|
229
229
|
});
|
|
230
230
|
|
|
231
231
|
test("formats multiple messages with correct count", () => {
|
package/src/mail/client.ts
CHANGED
|
@@ -96,7 +96,7 @@ function formatForInjection(messages: MailMessage[]): string {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
const lines: string[] = [
|
|
99
|
-
|
|
99
|
+
`You have ${messages.length} new message${messages.length === 1 ? "" : "s"}:`,
|
|
100
100
|
"",
|
|
101
101
|
];
|
|
102
102
|
|
|
@@ -108,7 +108,7 @@ function formatForInjection(messages: MailMessage[]): string {
|
|
|
108
108
|
if (msg.payload !== null && PROTOCOL_TYPES.has(msg.type)) {
|
|
109
109
|
lines.push(`Payload: ${msg.payload}`);
|
|
110
110
|
}
|
|
111
|
-
lines.push(`[Reply with:
|
|
111
|
+
lines.push(`[Reply with: ov mail reply ${msg.id} --body "..."]`);
|
|
112
112
|
lines.push("");
|
|
113
113
|
}
|
|
114
114
|
|
package/src/mulch/client.ts
CHANGED
|
@@ -116,7 +116,7 @@ export function createMulchClient(cwd: string): MulchClient {
|
|
|
116
116
|
args: string[],
|
|
117
117
|
context: string,
|
|
118
118
|
): Promise<{ stdout: string; stderr: string }> {
|
|
119
|
-
const { stdout, stderr, exitCode } = await runCommand(["
|
|
119
|
+
const { stdout, stderr, exitCode } = await runCommand(["ml", ...args], cwd);
|
|
120
120
|
if (exitCode !== 0) {
|
|
121
121
|
throw new AgentError(`mulch ${context} failed (exit ${exitCode}): ${stderr.trim()}`);
|
|
122
122
|
}
|
|
@@ -210,15 +210,19 @@ describe("createSession", () => {
|
|
|
210
210
|
}
|
|
211
211
|
});
|
|
212
212
|
|
|
213
|
-
test("still creates session when which overstory
|
|
213
|
+
test("still creates session when which ov and which overstory both fail (uses fallback)", async () => {
|
|
214
214
|
let callCount = 0;
|
|
215
215
|
spawnSpy.mockImplementation(() => {
|
|
216
216
|
callCount++;
|
|
217
217
|
if (callCount === 1) {
|
|
218
|
+
// which ov fails
|
|
219
|
+
return mockSpawnResult("", "ov not found", 1);
|
|
220
|
+
}
|
|
221
|
+
if (callCount === 2) {
|
|
218
222
|
// which overstory fails
|
|
219
223
|
return mockSpawnResult("", "overstory not found", 1);
|
|
220
224
|
}
|
|
221
|
-
if (callCount ===
|
|
225
|
+
if (callCount === 3) {
|
|
222
226
|
// tmux new-session
|
|
223
227
|
return mockSpawnResult("", "", 0);
|
|
224
228
|
}
|
|
@@ -230,7 +234,8 @@ describe("createSession", () => {
|
|
|
230
234
|
expect(pid).toBe(5555);
|
|
231
235
|
|
|
232
236
|
// The tmux command should contain the original command
|
|
233
|
-
|
|
237
|
+
// Call 0: which ov, Call 1: which overstory, Call 2: tmux new-session
|
|
238
|
+
const tmuxCallArgs = spawnSpy.mock.calls[2] as unknown[];
|
|
234
239
|
const cmd = tmuxCallArgs[0] as string[];
|
|
235
240
|
const tmuxCmd = cmd[7] as string;
|
|
236
241
|
expect(tmuxCmd).toContain("echo test");
|
package/src/worktree/tmux.ts
CHANGED
|
@@ -13,30 +13,31 @@ import { AgentError } from "../errors.ts";
|
|
|
13
13
|
/**
|
|
14
14
|
* Detect the directory containing the overstory binary.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Tries `which ov` first (the short alias), then falls back to
|
|
17
|
+
* `which overstory` (the original name). Both are registered in
|
|
18
|
+
* package.json bin, but depending on how the tool was installed
|
|
19
|
+
* (bun link, npm link, global install), only one may be on PATH.
|
|
19
20
|
*
|
|
20
21
|
* Returns null if detection fails.
|
|
21
22
|
*/
|
|
22
23
|
async function detectOverstoryBinDir(): Promise<string | null> {
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
// Try both command names — the alias migration may leave only one resolvable
|
|
25
|
+
for (const cmdName of ["ov", "overstory"]) {
|
|
26
|
+
try {
|
|
27
|
+
const proc = Bun.spawn(["which", cmdName], {
|
|
28
|
+
stdout: "pipe",
|
|
29
|
+
stderr: "pipe",
|
|
30
|
+
});
|
|
31
|
+
const exitCode = await proc.exited;
|
|
32
|
+
if (exitCode === 0) {
|
|
33
|
+
const binPath = (await new Response(proc.stdout).text()).trim();
|
|
34
|
+
if (binPath.length > 0) {
|
|
35
|
+
return dirname(resolve(binPath));
|
|
36
|
+
}
|
|
36
37
|
}
|
|
38
|
+
} catch {
|
|
39
|
+
// which not available or command not on PATH — try next
|
|
37
40
|
}
|
|
38
|
-
} catch {
|
|
39
|
-
// which not available or overstory not on PATH
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// Fallback: if process.argv[1] points to overstory's own entry point (src/index.ts),
|
package/templates/CLAUDE.md.tmpl
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# {{PROJECT_NAME}} — Overstory Orchestration
|
|
2
2
|
|
|
3
|
-
> Auto-generated by `
|
|
3
|
+
> Auto-generated by `ov init`. You may edit this file.
|
|
4
4
|
|
|
5
5
|
This project uses **overstory** for Claude Code agent orchestration. Your session
|
|
6
6
|
acts as the orchestrator: you decide what work to delegate, spawn worker agents,
|
|
@@ -10,34 +10,34 @@ monitor progress, and merge results.
|
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
# Spawn a worker agent
|
|
13
|
-
|
|
13
|
+
ov sling <bead-id> --capability <type> --name <agent-name> \
|
|
14
14
|
[--spec <path>] [--files file1,file2] [--parent <agent>] [--depth <n>]
|
|
15
15
|
|
|
16
16
|
# Check system status
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
ov status # Overview of all agents, worktrees, {{TRACKER_NAME}}
|
|
18
|
+
ov status --json # Machine-readable output
|
|
19
|
+
ov status --watch # Live updating
|
|
20
20
|
|
|
21
21
|
# Messaging (SQLite-backed, ~1-5ms per query)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
ov mail send --to <agent> --subject "..." --body "..."
|
|
23
|
+
ov mail check # Your inbox
|
|
24
|
+
ov mail list --unread # All unread messages
|
|
25
|
+
ov mail reply <id> --body "..."
|
|
26
26
|
|
|
27
27
|
# Merge completed work
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
ov merge --branch <name> # Merge a specific branch
|
|
29
|
+
ov merge --all # Merge all completed branches
|
|
30
|
+
ov merge --dry-run --branch <name> # Preview conflicts
|
|
31
31
|
|
|
32
32
|
# Worktree management
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
ov worktree list # Show all worktrees with status
|
|
34
|
+
ov worktree clean --completed # Remove finished worktrees
|
|
35
35
|
|
|
36
36
|
# Context and monitoring
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
ov prime # Reload context (config, mulch, recent activity)
|
|
38
|
+
ov watch --background # Start watchdog daemon
|
|
39
|
+
ov metrics # Performance summary
|
|
40
|
+
ov log <event> --agent <name> # Hook-driven event logging
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
## How to Spawn Agents
|
|
@@ -46,10 +46,10 @@ overstory log <event> --agent <name> # Hook-driven event logging
|
|
|
46
46
|
2. Choose a capability based on the task:
|
|
47
47
|
{{AGENT_DEFINITIONS}}
|
|
48
48
|
3. Assign exclusive file scope so agents do not conflict
|
|
49
|
-
4. Spawn: `
|
|
49
|
+
4. Spawn: `ov sling <bead-id> --capability <type> --name <unique-name> --files src/foo.ts,src/bar.ts`
|
|
50
50
|
|
|
51
51
|
Each spawned agent gets its own git worktree, branch, CLAUDE.md overlay, and
|
|
52
|
-
tmux session. Agents communicate via `
|
|
52
|
+
tmux session. Agents communicate via `ov mail` and report completion
|
|
53
53
|
by closing their {{TRACKER_NAME}} issue (`{{TRACKER_CLI}} close <id> --reason "summary"`).
|
|
54
54
|
|
|
55
55
|
## Hierarchical Delegation
|
|
@@ -58,10 +58,10 @@ You can spawn **team leads** that themselves spawn sub-workers:
|
|
|
58
58
|
|
|
59
59
|
```
|
|
60
60
|
Orchestrator (this session)
|
|
61
|
-
└──
|
|
62
|
-
├──
|
|
63
|
-
├──
|
|
64
|
-
└──
|
|
61
|
+
└── ov sling bd-xyz --capability lead --name build-lead
|
|
62
|
+
├── ov sling bd-abc --capability builder --name auth-login
|
|
63
|
+
├── ov sling bd-def --capability builder --name auth-signup
|
|
64
|
+
└── ov sling bd-ghi --capability builder --name auth-reset
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
Depth limit is configurable (default: 2). Leads use `--parent` and `--depth`
|
|
@@ -69,7 +69,7 @@ to track hierarchy.
|
|
|
69
69
|
|
|
70
70
|
## Checking Status
|
|
71
71
|
|
|
72
|
-
Run `
|
|
72
|
+
Run `ov status` to see:
|
|
73
73
|
- Active agents and their states (booting, working, stalled, zombie)
|
|
74
74
|
- Worktree locations and branches
|
|
75
75
|
- Beads issue progress
|
|
@@ -83,7 +83,7 @@ All merges target **{{CANONICAL_BRANCH}}**. Agents work on branches named
|
|
|
83
83
|
## Conventions
|
|
84
84
|
|
|
85
85
|
- Agents own files exclusively — no two agents modify the same file
|
|
86
|
-
- Use `
|
|
86
|
+
- Use `ov mail` for all inter-agent communication (not {{TRACKER_NAME}})
|
|
87
87
|
- Use `{{TRACKER_CLI}} close` to report task completion (not mail)
|
|
88
|
-
- Merge via `
|
|
88
|
+
- Merge via `ov merge`, not raw `git merge`
|
|
89
89
|
- Logs live in `.overstory/logs/` — never delete them manually
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
9
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov prime --agent {{AGENT_NAME}}"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "command",
|
|
13
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov mail check --inject --agent {{AGENT_NAME}}"
|
|
10
14
|
}
|
|
11
15
|
]
|
|
12
16
|
}
|
|
@@ -17,7 +21,7 @@
|
|
|
17
21
|
"hooks": [
|
|
18
22
|
{
|
|
19
23
|
"type": "command",
|
|
20
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
24
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov mail check --inject --agent {{AGENT_NAME}}"
|
|
21
25
|
}
|
|
22
26
|
]
|
|
23
27
|
}
|
|
@@ -28,7 +32,7 @@
|
|
|
28
32
|
"hooks": [
|
|
29
33
|
{
|
|
30
34
|
"type": "command",
|
|
31
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
35
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov log tool-start --agent {{AGENT_NAME}} --stdin"
|
|
32
36
|
}
|
|
33
37
|
]
|
|
34
38
|
},
|
|
@@ -37,7 +41,7 @@
|
|
|
37
41
|
"hooks": [
|
|
38
42
|
{
|
|
39
43
|
"type": "command",
|
|
40
|
-
"command": "read -r INPUT; CMD=$(echo \"$INPUT\" | sed 's/.*\"command\": *\"\\([^\"]*\\)\".*/\\1/'); if echo \"$CMD\" | grep -qE '\\bgit\\s+push\\b'; then echo '{\"decision\":\"block\",\"reason\":\"git push is blocked — use
|
|
44
|
+
"command": "read -r INPUT; CMD=$(echo \"$INPUT\" | sed 's/.*\"command\": *\"\\([^\"]*\\)\".*/\\1/'); if echo \"$CMD\" | grep -qE '\\bgit\\s+push\\b'; then echo '{\"decision\":\"block\",\"reason\":\"git push is blocked — use ov merge to integrate changes, push manually when ready\"}'; exit 0; fi;"
|
|
41
45
|
}
|
|
42
46
|
]
|
|
43
47
|
}
|
|
@@ -48,11 +52,11 @@
|
|
|
48
52
|
"hooks": [
|
|
49
53
|
{
|
|
50
54
|
"type": "command",
|
|
51
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
55
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov log tool-end --agent {{AGENT_NAME}} --stdin"
|
|
52
56
|
},
|
|
53
57
|
{
|
|
54
58
|
"type": "command",
|
|
55
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
59
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov mail check --inject --agent {{AGENT_NAME}} --debounce 500"
|
|
56
60
|
}
|
|
57
61
|
]
|
|
58
62
|
},
|
|
@@ -61,7 +65,7 @@
|
|
|
61
65
|
"hooks": [
|
|
62
66
|
{
|
|
63
67
|
"type": "command",
|
|
64
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
68
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov mail check --inject --agent {{AGENT_NAME}} --debounce 30000"
|
|
65
69
|
}
|
|
66
70
|
]
|
|
67
71
|
},
|
|
@@ -70,7 +74,7 @@
|
|
|
70
74
|
"hooks": [
|
|
71
75
|
{
|
|
72
76
|
"type": "command",
|
|
73
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; read -r INPUT; if echo \"$INPUT\" | grep -qE '\\bgit\\s+commit\\b'; then
|
|
77
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; read -r INPUT; if echo \"$INPUT\" | grep -qE '\\bgit\\s+commit\\b'; then ml diff HEAD~1 >/dev/null 2>&1 || true; fi; exit 0;"
|
|
74
78
|
}
|
|
75
79
|
]
|
|
76
80
|
}
|
|
@@ -81,11 +85,11 @@
|
|
|
81
85
|
"hooks": [
|
|
82
86
|
{
|
|
83
87
|
"type": "command",
|
|
84
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
88
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov log session-end --agent {{AGENT_NAME}} --stdin"
|
|
85
89
|
},
|
|
86
90
|
{
|
|
87
91
|
"type": "command",
|
|
88
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
92
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ml learn"
|
|
89
93
|
}
|
|
90
94
|
]
|
|
91
95
|
}
|
|
@@ -96,7 +100,7 @@
|
|
|
96
100
|
"hooks": [
|
|
97
101
|
{
|
|
98
102
|
"type": "command",
|
|
99
|
-
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0;
|
|
103
|
+
"command": "[ -z \"$OVERSTORY_AGENT_NAME\" ] && exit 0; ov prime --agent {{AGENT_NAME}} --compact"
|
|
100
104
|
}
|
|
101
105
|
]
|
|
102
106
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# DO NOT EDIT — Auto-generated by overstory
|
|
2
|
-
# This overlay was written by `
|
|
2
|
+
# This overlay was written by `ov sling`. Manual edits will be
|
|
3
3
|
# overwritten on the next spawn. Modify the template at
|
|
4
4
|
# templates/overlay.md.tmpl in the overstory repo instead.
|
|
5
5
|
|
|
@@ -50,26 +50,26 @@ Prime relevant domain knowledge before starting work:
|
|
|
50
50
|
|
|
51
51
|
## Communication
|
|
52
52
|
|
|
53
|
-
Use `
|
|
53
|
+
Use `ov mail` for all communication. Your address is **{{AGENT_NAME}}**.
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
56
|
# Check your inbox (do this regularly)
|
|
57
|
-
|
|
57
|
+
ov mail check --agent {{AGENT_NAME}}
|
|
58
58
|
|
|
59
59
|
# Send a status update to your parent
|
|
60
|
-
|
|
60
|
+
ov mail send --to {{PARENT_AGENT}} --subject "status" \
|
|
61
61
|
--body "Progress update here" --type status --agent {{AGENT_NAME}}
|
|
62
62
|
|
|
63
63
|
# Ask a question
|
|
64
|
-
|
|
64
|
+
ov mail send --to {{PARENT_AGENT}} --subject "question" \
|
|
65
65
|
--body "Your question here" --type question --priority high --agent {{AGENT_NAME}}
|
|
66
66
|
|
|
67
67
|
# Report completion
|
|
68
|
-
|
|
68
|
+
ov mail send --to {{PARENT_AGENT}} --subject "done" \
|
|
69
69
|
--body "Summary of what was done" --type result --agent {{AGENT_NAME}}
|
|
70
70
|
|
|
71
71
|
# Reply to a message
|
|
72
|
-
|
|
72
|
+
ov mail reply <message-id> --body "Your reply" --agent {{AGENT_NAME}}
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
## Spawning Sub-Workers
|