@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.
Files changed (79) hide show
  1. package/README.md +60 -60
  2. package/agents/builder.md +16 -16
  3. package/agents/coordinator.md +57 -57
  4. package/agents/issue-reviews.md +71 -0
  5. package/agents/lead.md +43 -42
  6. package/agents/merger.md +15 -15
  7. package/agents/monitor.md +37 -37
  8. package/agents/pr-reviews.md +60 -0
  9. package/agents/prioritize.md +110 -0
  10. package/agents/release.md +56 -0
  11. package/agents/reviewer.md +15 -15
  12. package/agents/scout.md +18 -18
  13. package/agents/supervisor.md +78 -78
  14. package/package.json +1 -1
  15. package/src/agents/hooks-deployer.test.ts +23 -26
  16. package/src/agents/hooks-deployer.ts +9 -5
  17. package/src/agents/overlay.test.ts +5 -5
  18. package/src/agents/overlay.ts +11 -11
  19. package/src/commands/agents.ts +7 -6
  20. package/src/commands/clean.ts +5 -5
  21. package/src/commands/completions.test.ts +10 -10
  22. package/src/commands/completions.ts +26 -28
  23. package/src/commands/coordinator.test.ts +2 -2
  24. package/src/commands/coordinator.ts +12 -12
  25. package/src/commands/costs.ts +1 -1
  26. package/src/commands/dashboard.ts +8 -8
  27. package/src/commands/doctor.ts +4 -4
  28. package/src/commands/errors.ts +1 -1
  29. package/src/commands/feed.ts +1 -1
  30. package/src/commands/group.ts +3 -3
  31. package/src/commands/hooks.test.ts +7 -7
  32. package/src/commands/hooks.ts +7 -7
  33. package/src/commands/init.test.ts +6 -2
  34. package/src/commands/init.ts +19 -19
  35. package/src/commands/inspect.ts +19 -19
  36. package/src/commands/log.ts +3 -3
  37. package/src/commands/logs.ts +1 -1
  38. package/src/commands/mail.test.ts +2 -2
  39. package/src/commands/mail.ts +28 -11
  40. package/src/commands/merge.ts +7 -7
  41. package/src/commands/metrics.test.ts +1 -1
  42. package/src/commands/metrics.ts +2 -2
  43. package/src/commands/monitor.test.ts +5 -5
  44. package/src/commands/monitor.ts +4 -4
  45. package/src/commands/nudge.ts +1 -1
  46. package/src/commands/prime.test.ts +1 -1
  47. package/src/commands/prime.ts +2 -2
  48. package/src/commands/replay.ts +1 -1
  49. package/src/commands/run.ts +2 -2
  50. package/src/commands/sling.test.ts +84 -2
  51. package/src/commands/sling.ts +97 -9
  52. package/src/commands/spec.ts +8 -9
  53. package/src/commands/status.test.ts +2 -2
  54. package/src/commands/status.ts +2 -4
  55. package/src/commands/stop.ts +2 -2
  56. package/src/commands/supervisor.test.ts +1 -1
  57. package/src/commands/supervisor.ts +4 -4
  58. package/src/commands/trace.test.ts +2 -2
  59. package/src/commands/trace.ts +4 -4
  60. package/src/commands/watch.ts +5 -5
  61. package/src/commands/worktree.test.ts +3 -3
  62. package/src/commands/worktree.ts +11 -11
  63. package/src/doctor/dependencies.test.ts +5 -5
  64. package/src/doctor/dependencies.ts +2 -2
  65. package/src/doctor/logs.ts +1 -1
  66. package/src/doctor/structure.test.ts +1 -1
  67. package/src/doctor/structure.ts +1 -1
  68. package/src/doctor/version.test.ts +3 -3
  69. package/src/doctor/version.ts +1 -1
  70. package/src/e2e/init-sling-lifecycle.test.ts +6 -2
  71. package/src/index.ts +11 -9
  72. package/src/mail/client.test.ts +1 -1
  73. package/src/mail/client.ts +2 -2
  74. package/src/mulch/client.ts +1 -1
  75. package/src/worktree/tmux.test.ts +8 -3
  76. package/src/worktree/tmux.ts +19 -18
  77. package/templates/CLAUDE.md.tmpl +27 -27
  78. package/templates/hooks.json.tmpl +15 -11
  79. package/templates/overlay.md.tmpl +7 -7
@@ -134,7 +134,7 @@ describe("generateOverlay", () => {
134
134
  const config = makeConfig({ mulchDomains: ["typescript", "testing"] });
135
135
  const output = await generateOverlay(config);
136
136
 
137
- expect(output).toContain("mulch prime typescript testing");
137
+ expect(output).toContain("ml prime typescript testing");
138
138
  });
139
139
 
140
140
  test("empty mulch domains shows fallback text", async () => {
@@ -159,7 +159,7 @@ describe("generateOverlay", () => {
159
159
  });
160
160
  const output = await generateOverlay(config);
161
161
 
162
- expect(output).toContain("overstory sling");
162
+ expect(output).toContain("ov sling");
163
163
  expect(output).toContain("--parent lead-alpha");
164
164
  expect(output).toContain("--depth 2");
165
165
  });
@@ -267,7 +267,7 @@ describe("generateOverlay", () => {
267
267
  const output = await generateOverlay(config);
268
268
 
269
269
  expect(output).toContain("bd close overstory-task1");
270
- expect(output).toContain("overstory mail send --to lead-alpha");
270
+ expect(output).toContain("ov mail send --to lead-alpha");
271
271
  });
272
272
 
273
273
  test("reviewer completion section uses coordinator when no parent", async () => {
@@ -284,8 +284,8 @@ describe("generateOverlay", () => {
284
284
  const config = makeConfig({ agentName: "worker-42" });
285
285
  const output = await generateOverlay(config);
286
286
 
287
- expect(output).toContain("overstory mail check --agent worker-42");
288
- expect(output).toContain("overstory mail send --to");
287
+ expect(output).toContain("ov mail check --agent worker-42");
288
+ expect(output).toContain("ov mail send --to");
289
289
  });
290
290
 
291
291
  test("output includes base agent definition content (Layer 1)", async () => {
@@ -24,14 +24,14 @@ function formatFileScope(fileScope: readonly string[]): string {
24
24
  }
25
25
 
26
26
  /**
27
- * Format mulch domains as a `mulch prime` command.
27
+ * Format mulch domains as a `ml prime` command.
28
28
  * Returns a human-readable fallback if no domains are configured.
29
29
  */
30
30
  function formatMulchDomains(domains: readonly string[]): string {
31
31
  if (domains.length === 0) {
32
32
  return "No specific expertise domains configured";
33
33
  }
34
- return `\`\`\`bash\nmulch prime ${domains.join(" ")}\n\`\`\``;
34
+ return `\`\`\`bash\nml prime ${domains.join(" ")}\n\`\`\``;
35
35
  }
36
36
 
37
37
  /**
@@ -90,9 +90,9 @@ function formatQualityGates(config: OverlayConfig): string {
90
90
  "",
91
91
  "Before reporting completion:",
92
92
  "",
93
- `1. **Record mulch learnings:** \`mulch record <domain> --type <convention|pattern|reference> --description "..."\` — capture reusable knowledge from your work`,
93
+ `1. **Record mulch learnings:** \`ml record <domain> --type <convention|pattern|reference> --description "..."\` — capture reusable knowledge from your work`,
94
94
  `2. **Close issue:** \`${config.trackerCli ?? "bd"} close ${config.taskId} --reason "summary of findings"\``,
95
- `3. **Send results:** \`overstory mail send --to ${config.parentAgent ?? "coordinator"} --subject "done" --body "Summary" --type result --agent ${config.agentName}\``,
95
+ `3. **Send results:** \`ov mail send --to ${config.parentAgent ?? "coordinator"} --subject "done" --body "Summary" --type result --agent ${config.agentName}\``,
96
96
  "",
97
97
  "You are a read-only agent. Do NOT commit, modify files, or run quality gates.",
98
98
  ].join("\n");
@@ -112,12 +112,12 @@ function formatQualityGates(config: OverlayConfig): string {
112
112
  "",
113
113
  ...gateLines,
114
114
  `${gateLines.length + 1}. **Commit:** all changes committed to your branch (${config.branchName})`,
115
- `${gateLines.length + 2}. **Record mulch learnings:** \`mulch record <domain> --type <convention|pattern|failure|decision> --description "..." --outcome-status success --outcome-agent ${config.agentName}\` — capture insights from your work`,
116
- `${gateLines.length + 3}. **Signal completion:** send \`worker_done\` mail to ${config.parentAgent ?? "coordinator"}: \`overstory mail send --to ${config.parentAgent ?? "coordinator"} --subject "Worker done: ${config.taskId}" --body "Quality gates passed." --type worker_done --agent ${config.agentName}\``,
115
+ `${gateLines.length + 2}. **Record mulch learnings:** \`ml record <domain> --type <convention|pattern|failure|decision> --description "..." --outcome-status success --outcome-agent ${config.agentName}\` — capture insights from your work`,
116
+ `${gateLines.length + 3}. **Signal completion:** send \`worker_done\` mail to ${config.parentAgent ?? "coordinator"}: \`ov mail send --to ${config.parentAgent ?? "coordinator"} --subject "Worker done: ${config.taskId}" --body "Quality gates passed." --type worker_done --agent ${config.agentName}\``,
117
117
  `${gateLines.length + 4}. **Close issue:** \`${config.trackerCli ?? "bd"} close ${config.taskId} --reason "summary of changes"\``,
118
118
  "",
119
119
  "Do NOT push to the canonical branch. Your work will be merged by the",
120
- "coordinator via `overstory merge`.",
120
+ "coordinator via `ov merge`.",
121
121
  ].join("\n");
122
122
  }
123
123
 
@@ -132,7 +132,7 @@ function formatConstraints(config: OverlayConfig): string {
132
132
  "",
133
133
  "- You are **read-only**: do NOT modify, create, or delete any files",
134
134
  "- Do NOT commit, push, or make any git state changes",
135
- `- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`overstory mail send --type result\``,
135
+ `- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`ov mail send --type result\``,
136
136
  "- If you encounter a blocking issue, send mail with `--priority urgent --type error`",
137
137
  ].join("\n");
138
138
  }
@@ -145,7 +145,7 @@ function formatConstraints(config: OverlayConfig): string {
145
145
  "- Only modify files in your File Scope",
146
146
  `- Commit only to your branch: ${config.branchName}`,
147
147
  "- Never push to the canonical branch",
148
- `- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`overstory mail send --type result\``,
148
+ `- Report completion via \`${config.trackerCli ?? "bd"} close\` AND \`ov mail send --type result\``,
149
149
  "- If you encounter a blocking issue, send mail with `--priority urgent --type error`",
150
150
  ].join("\n");
151
151
  }
@@ -159,10 +159,10 @@ function formatCanSpawn(config: OverlayConfig): string {
159
159
  return "You may NOT spawn sub-workers.";
160
160
  }
161
161
  return [
162
- "You may spawn sub-workers using `overstory sling`. Example:",
162
+ "You may spawn sub-workers using `ov sling`. Example:",
163
163
  "",
164
164
  "```bash",
165
- "overstory sling <task-id> --capability builder --name <worker-name> \\",
165
+ "ov sling <task-id> --capability builder --name <worker-name> \\",
166
166
  ` --parent ${config.agentName} --depth ${config.depth + 1}`,
167
167
  "```",
168
168
  ].join("\n");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory agents <sub> [--json]
2
+ * CLI command: ov agents <sub> [--json]
3
3
  *
4
4
  * Discover and query agents by capability.
5
5
  */
@@ -8,6 +8,7 @@ import { join } from "node:path";
8
8
  import { Command } from "commander";
9
9
  import { loadConfig } from "../config.ts";
10
10
  import { ValidationError } from "../errors.ts";
11
+ import { color } from "../logging/color.ts";
11
12
  import { openSessionStore } from "../sessions/compat.ts";
12
13
  import { type AgentSession, SUPPORTED_CAPABILITIES } from "../types.ts";
13
14
 
@@ -140,11 +141,11 @@ export async function discoverAgents(
140
141
  function getStateIcon(state: string): string {
141
142
  switch (state) {
142
143
  case "working":
143
- return "";
144
+ return color.cyan(">");
144
145
  case "booting":
145
- return "";
146
+ return color.green("-");
146
147
  case "stalled":
147
- return "";
148
+ return color.yellow("!");
148
149
  default:
149
150
  return " ";
150
151
  }
@@ -181,7 +182,7 @@ function printAgents(agents: DiscoveredAgent[]): void {
181
182
  }
182
183
 
183
184
  /**
184
- * Create the Commander command for `overstory agents`.
185
+ * Create the Commander command for `ov agents`.
185
186
  */
186
187
  export function createAgentsCommand(): Command {
187
188
  const cmd = new Command("agents").description("Discover and query agents");
@@ -229,7 +230,7 @@ export function createAgentsCommand(): Command {
229
230
  }
230
231
 
231
232
  /**
232
- * Entry point for `overstory agents <subcommand>`.
233
+ * Entry point for `ov agents <subcommand>`.
233
234
  */
234
235
  export async function agentsCommand(args: string[]): Promise<void> {
235
236
  const cmd = createAgentsCommand();
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory clean [--all] [--mail] [--sessions] [--metrics]
2
+ * CLI command: ov clean [--all] [--mail] [--sessions] [--metrics]
3
3
  * [--logs] [--worktrees] [--branches] [--agents] [--specs]
4
4
  *
5
5
  * Nuclear cleanup of overstory runtime state.
@@ -394,7 +394,7 @@ async function checkMulchHealth(repoRoot: string): Promise<{
394
394
  }
395
395
 
396
396
  /**
397
- * Entry point for `overstory clean [flags]`.
397
+ * Entry point for `ov clean [flags]`.
398
398
  *
399
399
  * @param opts - Command options
400
400
  */
@@ -556,7 +556,7 @@ export async function cleanCommand(opts: CleanOptions): Promise<void> {
556
556
  const healthLines: string[] = [];
557
557
 
558
558
  if (health.domainsNearLimit.length > 0) {
559
- healthLines.push("\n⚠️ Mulch domains approaching governance limits:");
559
+ healthLines.push("\nWarning: Mulch domains approaching governance limits:");
560
560
  for (const d of health.domainsNearLimit) {
561
561
  healthLines.push(
562
562
  ` ${d.domain}: ${d.recordCount} records (warn threshold: ${d.warnThreshold})`,
@@ -566,13 +566,13 @@ export async function cleanCommand(opts: CleanOptions): Promise<void> {
566
566
 
567
567
  if (health.stalePruneCandidates > 0) {
568
568
  healthLines.push(
569
- `\n📦 Stale records found: ${health.stalePruneCandidates} candidate${health.stalePruneCandidates === 1 ? "" : "s"} (run 'mulch prune' to remove)`,
569
+ `\nStale records found: ${health.stalePruneCandidates} candidate${health.stalePruneCandidates === 1 ? "" : "s"} (run 'mulch prune' to remove)`,
570
570
  );
571
571
  }
572
572
 
573
573
  if (health.doctorWarnings > 0 || health.doctorIssues > 0) {
574
574
  healthLines.push(
575
- `\n🩺 Mulch health check: ${health.doctorWarnings} warning${health.doctorWarnings === 1 ? "" : "s"}, ${health.doctorIssues} issue${health.doctorIssues === 1 ? "" : "s"} (run 'mulch doctor' for details)`,
575
+ `\nMulch health check: ${health.doctorWarnings} warning${health.doctorWarnings === 1 ? "" : "s"}, ${health.doctorIssues} issue${health.doctorIssues === 1 ? "" : "s"} (run 'mulch doctor' for details)`,
576
576
  );
577
577
  }
578
578
 
@@ -54,8 +54,8 @@ describe("COMMANDS array", () => {
54
54
  describe("generateBash", () => {
55
55
  it("should return a bash completion script", () => {
56
56
  const script = generateBash();
57
- expect(script).toContain("_overstory()");
58
- expect(script).toContain("complete -F _overstory overstory");
57
+ expect(script).toContain("_ov()");
58
+ expect(script).toContain("complete -F _ov ov");
59
59
  expect(script).toContain("_init_completion");
60
60
  });
61
61
 
@@ -87,8 +87,8 @@ describe("generateBash", () => {
87
87
  describe("generateZsh", () => {
88
88
  it("should return a zsh completion script", () => {
89
89
  const script = generateZsh();
90
- expect(script).toContain("#compdef overstory");
91
- expect(script).toContain("_overstory()");
90
+ expect(script).toContain("#compdef ov");
91
+ expect(script).toContain("_ov()");
92
92
  expect(script).toContain("_describe");
93
93
  expect(script).toContain("_arguments");
94
94
  });
@@ -119,7 +119,7 @@ describe("generateZsh", () => {
119
119
  describe("generateFish", () => {
120
120
  it("should return a fish completion script", () => {
121
121
  const script = generateFish();
122
- expect(script).toContain("complete -c overstory");
122
+ expect(script).toContain("complete -c ov");
123
123
  expect(script).toContain("__fish_use_subcommand");
124
124
  });
125
125
 
@@ -160,8 +160,8 @@ describe("completionsCommand", () => {
160
160
 
161
161
  try {
162
162
  completionsCommand(["bash"]);
163
- expect(output).toContain("_overstory()");
164
- expect(output).toContain("complete -F _overstory overstory");
163
+ expect(output).toContain("_ov()");
164
+ expect(output).toContain("complete -F _ov ov");
165
165
  } finally {
166
166
  process.stdout.write = originalWrite;
167
167
  }
@@ -178,8 +178,8 @@ describe("completionsCommand", () => {
178
178
 
179
179
  try {
180
180
  completionsCommand(["zsh"]);
181
- expect(output).toContain("#compdef overstory");
182
- expect(output).toContain("_overstory()");
181
+ expect(output).toContain("#compdef ov");
182
+ expect(output).toContain("_ov()");
183
183
  } finally {
184
184
  process.stdout.write = originalWrite;
185
185
  }
@@ -196,7 +196,7 @@ describe("completionsCommand", () => {
196
196
 
197
197
  try {
198
198
  completionsCommand(["fish"]);
199
- expect(output).toContain("complete -c overstory");
199
+ expect(output).toContain("complete -c ov");
200
200
  } finally {
201
201
  process.stdout.write = originalWrite;
202
202
  }
@@ -609,11 +609,11 @@ export const COMMANDS: readonly CommandDef[] = [
609
609
 
610
610
  export function generateBash(): string {
611
611
  const lines: string[] = [
612
- "# Bash completion for overstory",
612
+ "# Bash completion for ov",
613
613
  "# Source this file to enable completions:",
614
- "# source <(overstory --completions bash)",
614
+ "# source <(ov --completions bash)",
615
615
  "",
616
- "_overstory() {",
616
+ "_ov() {",
617
617
  " local cur prev words cword",
618
618
  " _init_completion || return",
619
619
  "",
@@ -668,19 +668,19 @@ export function generateBash(): string {
668
668
  lines.push(" return 0");
669
669
  lines.push("}");
670
670
  lines.push("");
671
- lines.push("complete -F _overstory overstory");
671
+ lines.push("complete -F _ov ov");
672
672
 
673
673
  return lines.join("\n");
674
674
  }
675
675
 
676
676
  export function generateZsh(): string {
677
677
  const lines: string[] = [
678
- "#compdef overstory",
679
- "# Zsh completion for overstory",
678
+ "#compdef ov",
679
+ "# Zsh completion for ov",
680
680
  "# Place this file in your fpath or source it:",
681
- "# source <(overstory --completions zsh)",
681
+ "# source <(ov --completions zsh)",
682
682
  "",
683
- "_overstory() {",
683
+ "_ov() {",
684
684
  " local -a commands",
685
685
  " commands=(",
686
686
  ];
@@ -778,24 +778,24 @@ export function generateZsh(): string {
778
778
  lines.push(" esac");
779
779
  lines.push("}");
780
780
  lines.push("");
781
- lines.push('_overstory "$@"');
781
+ lines.push('_ov "$@"');
782
782
 
783
783
  return lines.join("\n");
784
784
  }
785
785
 
786
786
  export function generateFish(): string {
787
787
  const lines: string[] = [
788
- "# Fish completion for overstory",
789
- "# Place this file in ~/.config/fish/completions/overstory.fish or source it:",
790
- "# overstory --completions fish | source",
788
+ "# Fish completion for ov",
789
+ "# Place this file in ~/.config/fish/completions/ov.fish or source it:",
790
+ "# ov --completions fish | source",
791
791
  "",
792
- "# Remove all existing completions for overstory",
793
- "complete -c overstory -e",
792
+ "# Remove all existing completions for ov",
793
+ "complete -c ov -e",
794
794
  "",
795
795
  "# Global options",
796
- "complete -c overstory -l help -d 'Show help'",
797
- "complete -c overstory -l version -d 'Show version'",
798
- "complete -c overstory -l completions -d 'Generate shell completions' -xa 'bash zsh fish'",
796
+ "complete -c ov -l help -d 'Show help'",
797
+ "complete -c ov -l version -d 'Show version'",
798
+ "complete -c ov -l completions -d 'Generate shell completions' -xa 'bash zsh fish'",
799
799
  "",
800
800
  ];
801
801
 
@@ -803,15 +803,13 @@ export function generateFish(): string {
803
803
  for (const cmd of COMMANDS) {
804
804
  // Command name
805
805
  lines.push(`# ${cmd.desc}`);
806
- lines.push(
807
- `complete -c overstory -f -n '__fish_use_subcommand' -a '${cmd.name}' -d '${cmd.desc}'`,
808
- );
806
+ lines.push(`complete -c ov -f -n '__fish_use_subcommand' -a '${cmd.name}' -d '${cmd.desc}'`);
809
807
 
810
808
  if (cmd.subcommands && cmd.subcommands.length > 0) {
811
809
  // Subcommand names
812
810
  for (const subcmd of cmd.subcommands) {
813
811
  lines.push(
814
- `complete -c overstory -f -n '__fish_seen_subcommand_from ${cmd.name}; and not __fish_seen_subcommand_from ${cmd.subcommands.map((s) => s.name).join(" ")}' -a '${subcmd.name}' -d '${subcmd.desc}'`,
812
+ `complete -c ov -f -n '__fish_seen_subcommand_from ${cmd.name}; and not __fish_seen_subcommand_from ${cmd.subcommands.map((s) => s.name).join(" ")}' -a '${subcmd.name}' -d '${subcmd.desc}'`,
815
813
  );
816
814
 
817
815
  // Subcommand flags
@@ -822,12 +820,12 @@ export function generateFish(): string {
822
820
 
823
821
  if (flag.values) {
824
822
  lines.push(
825
- `complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
823
+ `complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
826
824
  );
827
825
  } else if (flag.takesValue) {
828
- lines.push(`complete -c overstory -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
826
+ lines.push(`complete -c ov -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
829
827
  } else {
830
- lines.push(`complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
828
+ lines.push(`complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
831
829
  }
832
830
  }
833
831
  }
@@ -842,12 +840,12 @@ export function generateFish(): string {
842
840
 
843
841
  if (flag.values) {
844
842
  lines.push(
845
- `complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
843
+ `complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}' -xa '${flag.values.join(" ")}'`,
846
844
  );
847
845
  } else if (flag.takesValue) {
848
- lines.push(`complete -c overstory -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
846
+ lines.push(`complete -c ov -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
849
847
  } else {
850
- lines.push(`complete -c overstory -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
848
+ lines.push(`complete -c ov -f -n ${cond} -l '${flagName}' -d '${flag.desc}'`);
851
849
  }
852
850
  }
853
851
  }
@@ -875,7 +873,7 @@ export function completionsCommand(args: string[]): void {
875
873
 
876
874
  if (!shell) {
877
875
  process.stderr.write("Error: missing shell argument\n");
878
- process.stderr.write("Usage: overstory --completions <bash|zsh|fish>\n");
876
+ process.stderr.write("Usage: ov --completions <bash|zsh|fish>\n");
879
877
  process.exit(1);
880
878
  }
881
879
 
@@ -1025,9 +1025,9 @@ describe("buildCoordinatorBeacon", () => {
1025
1025
  test("includes startup instructions", () => {
1026
1026
  const beacon = buildCoordinatorBeacon();
1027
1027
  expect(beacon).toContain("mulch prime");
1028
- expect(beacon).toContain("overstory mail check --agent coordinator");
1028
+ expect(beacon).toContain("ov mail check --agent coordinator");
1029
1029
  expect(beacon).toContain("bd ready");
1030
- expect(beacon).toContain("overstory group status");
1030
+ expect(beacon).toContain("ov group status");
1031
1031
  });
1032
1032
 
1033
1033
  test("defaults to bd ready when no cliName provided", () => {
@@ -1,9 +1,9 @@
1
1
  /**
2
- * CLI command: overstory coordinator start|stop|status
2
+ * CLI command: ov coordinator start|stop|status
3
3
  *
4
4
  * Manages the persistent coordinator agent lifecycle. The coordinator runs
5
5
  * at the project root (NOT in a worktree), receives work via mail and beads,
6
- * and dispatches agents via overstory sling.
6
+ * and dispatches agents via ov sling.
7
7
  *
8
8
  * Unlike regular agents spawned by sling, the coordinator:
9
9
  * - Has no worktree (operates on the main working tree)
@@ -115,7 +115,7 @@ async function removeWatchdogPid(projectRoot: string): Promise<void> {
115
115
 
116
116
  /**
117
117
  * Default watchdog implementation for production use.
118
- * Starts/stops the watchdog daemon via `overstory watch --background`.
118
+ * Starts/stops the watchdog daemon via `ov watch --background`.
119
119
  */
120
120
  function createDefaultWatchdog(projectRoot: string): NonNullable<CoordinatorDeps["_watchdog"]> {
121
121
  return {
@@ -132,7 +132,7 @@ function createDefaultWatchdog(projectRoot: string): NonNullable<CoordinatorDeps
132
132
  }
133
133
 
134
134
  // Start watchdog in background
135
- const proc = Bun.spawn(["overstory", "watch", "--background"], {
135
+ const proc = Bun.spawn(["ov", "watch", "--background"], {
136
136
  cwd: projectRoot,
137
137
  stdout: "pipe",
138
138
  stderr: "pipe",
@@ -189,12 +189,12 @@ function createDefaultWatchdog(projectRoot: string): NonNullable<CoordinatorDeps
189
189
 
190
190
  /**
191
191
  * Default monitor implementation for production use.
192
- * Starts/stops the monitor agent via `overstory monitor start/stop`.
192
+ * Starts/stops the monitor agent via `ov monitor start/stop`.
193
193
  */
194
194
  function createDefaultMonitor(projectRoot: string): NonNullable<CoordinatorDeps["_monitor"]> {
195
195
  return {
196
196
  async start(): Promise<{ pid: number } | null> {
197
- const proc = Bun.spawn(["overstory", "monitor", "start", "--no-attach", "--json"], {
197
+ const proc = Bun.spawn(["ov", "monitor", "start", "--no-attach", "--json"], {
198
198
  cwd: projectRoot,
199
199
  stdout: "pipe",
200
200
  stderr: "pipe",
@@ -210,7 +210,7 @@ function createDefaultMonitor(projectRoot: string): NonNullable<CoordinatorDeps[
210
210
  }
211
211
  },
212
212
  async stop(): Promise<boolean> {
213
- const proc = Bun.spawn(["overstory", "monitor", "stop", "--json"], {
213
+ const proc = Bun.spawn(["ov", "monitor", "stop", "--json"], {
214
214
  cwd: projectRoot,
215
215
  stdout: "pipe",
216
216
  stderr: "pipe",
@@ -219,7 +219,7 @@ function createDefaultMonitor(projectRoot: string): NonNullable<CoordinatorDeps[
219
219
  return exitCode === 0;
220
220
  },
221
221
  async isRunning(): Promise<boolean> {
222
- const proc = Bun.spawn(["overstory", "monitor", "status", "--json"], {
222
+ const proc = Bun.spawn(["ov", "monitor", "status", "--json"], {
223
223
  cwd: projectRoot,
224
224
  stdout: "pipe",
225
225
  stderr: "pipe",
@@ -248,9 +248,9 @@ export function buildCoordinatorBeacon(cliName = "bd"): string {
248
248
  const parts = [
249
249
  `[OVERSTORY] ${COORDINATOR_NAME} (coordinator) ${timestamp}`,
250
250
  "Depth: 0 | Parent: none | Role: persistent orchestrator",
251
- "HIERARCHY: You ONLY spawn leads (overstory sling --capability lead). Leads spawn scouts, builders, reviewers. NEVER spawn non-lead agents directly.",
251
+ "HIERARCHY: You ONLY spawn leads (ov sling --capability lead). Leads spawn scouts, builders, reviewers. NEVER spawn non-lead agents directly.",
252
252
  "DELEGATION: For any exploration/scouting, spawn a lead who will spawn scouts. Do NOT explore the codebase yourself beyond initial planning.",
253
- `Startup: run mulch prime, check mail (overstory mail check --agent ${COORDINATOR_NAME}), check ${cliName} ready, check overstory group status, then begin work`,
253
+ `Startup: run mulch prime, check mail (ov mail check --agent ${COORDINATOR_NAME}), check ${cliName} ready, check ov group status, then begin work`,
254
254
  ];
255
255
  return parts.join(" — ");
256
256
  }
@@ -686,7 +686,7 @@ async function statusCoordinator(
686
686
  }
687
687
 
688
688
  /**
689
- * Create the Commander command for `overstory coordinator`.
689
+ * Create the Commander command for `ov coordinator`.
690
690
  */
691
691
  export function createCoordinatorCommand(deps: CoordinatorDeps = {}): Command {
692
692
  const cmd = new Command("coordinator").description("Manage the persistent coordinator agent");
@@ -735,7 +735,7 @@ export function createCoordinatorCommand(deps: CoordinatorDeps = {}): Command {
735
735
  }
736
736
 
737
737
  /**
738
- * Entry point for `overstory coordinator <subcommand>`.
738
+ * Entry point for `ov coordinator <subcommand>`.
739
739
  *
740
740
  * @param args - CLI arguments after "coordinator"
741
741
  * @param deps - Optional dependency injection for testing (tmux)
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory costs [--agent <name>] [--run <id>] [--by-capability] [--last <n>] [--self] [--json]
2
+ * CLI command: ov costs [--agent <name>] [--run <id>] [--by-capability] [--last <n>] [--self] [--json]
3
3
  *
4
4
  * Shows token/cost analysis and breakdown for agent sessions.
5
5
  * Data source: metrics.db via createMetricsStore().
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory dashboard [--interval <ms>] [--all]
2
+ * CLI command: ov dashboard [--interval <ms>] [--all]
3
3
  *
4
4
  * Rich terminal dashboard using raw ANSI escape codes (zero runtime deps).
5
5
  * Polls existing data sources and renders multi-panel layout with agent status,
@@ -402,7 +402,7 @@ async function loadDashboardData(
402
402
  * Render the header bar (line 1).
403
403
  */
404
404
  function renderHeader(width: number, interval: number, currentRunId?: string | null): string {
405
- const left = color.bold(`overstory dashboard v${PKG_VERSION}`);
405
+ const left = color.bold(`ov dashboard v${PKG_VERSION}`);
406
406
  const now = new Date().toLocaleTimeString();
407
407
  const scope = currentRunId ? ` [run: ${currentRunId.slice(0, 8)}]` : " [all runs]";
408
408
  const right = `${now}${scope} | refresh: ${interval}ms`;
@@ -438,15 +438,15 @@ function getStateColor(state: string): ColorFn {
438
438
  function getStateIcon(state: string): string {
439
439
  switch (state) {
440
440
  case "working":
441
- return "";
441
+ return ">";
442
442
  case "booting":
443
- return "";
443
+ return "-";
444
444
  case "stalled":
445
- return "";
445
+ return "!";
446
446
  case "zombie":
447
- return "";
447
+ return "x";
448
448
  case "completed":
449
- return "";
449
+ return "x";
450
450
  default:
451
451
  return "?";
452
452
  }
@@ -508,7 +508,7 @@ function renderAgentPanel(
508
508
  const duration = formatDuration(endTime - new Date(agent.startedAt).getTime());
509
509
  const durationPadded = pad(duration, 9);
510
510
  const tmuxAlive = data.status.tmuxSessions.some((s) => s.name === agent.tmuxSession);
511
- const tmuxDot = tmuxAlive ? color.green("") : color.red("");
511
+ const tmuxDot = tmuxAlive ? color.green(">") : color.red("x");
512
512
 
513
513
  const line = `${BOX.vertical} ${stateColor(icon)} ${name} ${capability} ${stateColor(state)} ${taskId} ${durationPadded} ${tmuxDot} ${BOX.vertical}`;
514
514
  output += `${CURSOR.cursorTo(startRow + 3 + i, 1)}${line}\n`;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory doctor [options]
2
+ * CLI command: ov doctor [options]
3
3
  *
4
4
  * Runs health checks on overstory subsystems and reports problems.
5
5
  */
@@ -77,10 +77,10 @@ function printHumanReadable(
77
77
 
78
78
  const icon =
79
79
  check.status === "pass"
80
- ? color.green("")
80
+ ? color.green("-")
81
81
  : check.status === "warn"
82
- ? color.yellow("")
83
- : color.red("");
82
+ ? color.yellow("!")
83
+ : color.red("x");
84
84
 
85
85
  w(` ${icon} ${check.message}\n`);
86
86
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory errors [--agent <name>] [--run <id>] [--json] [--since <ts>] [--until <ts>] [--limit <n>]
2
+ * CLI command: ov errors [--agent <name>] [--run <id>] [--json] [--since <ts>] [--until <ts>] [--limit <n>]
3
3
  *
4
4
  * Shows aggregated error-level events across all agents.
5
5
  * Errors can be filtered by agent name, run ID, or time range.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory feed [--follow] [--agent <name>...] [--run <id>]
2
+ * CLI command: ov feed [--follow] [--agent <name>...] [--run <id>]
3
3
  * [--since <ts>] [--limit <n>] [--interval <ms>] [--json]
4
4
  *
5
5
  * Unified real-time event stream across all agents — like `tail -f` for the fleet.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * CLI command: overstory group create|status|add|remove|list
2
+ * CLI command: ov group create|status|add|remove|list
3
3
  *
4
4
  * Manages TaskGroups for batch work coordination. Groups track collections
5
5
  * of beads issues and auto-close when all member issues are closed.
@@ -297,7 +297,7 @@ function printGroupProgress(progress: TaskGroupProgress): void {
297
297
  }
298
298
 
299
299
  /**
300
- * Create the Commander command for `overstory group`.
300
+ * Create the Commander command for `ov group`.
301
301
  */
302
302
  export function createGroupCommand(): Command {
303
303
  const cmd = new Command("group").description("Manage task groups for batch coordination");
@@ -472,7 +472,7 @@ export function createGroupCommand(): Command {
472
472
  }
473
473
 
474
474
  /**
475
- * Entry point for `overstory group <subcommand>`.
475
+ * Entry point for `ov group <subcommand>`.
476
476
  */
477
477
  export async function groupCommand(args: string[]): Promise<void> {
478
478
  const cmd = createGroupCommand();