opencodekit 0.12.2 → 0.12.3

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 (32) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.opencode/AGENTS.md +40 -417
  3. package/dist/template/.opencode/agent/build.md +53 -0
  4. package/dist/template/.opencode/agent/planner.md +0 -1
  5. package/dist/template/.opencode/agent/rush.md +38 -0
  6. package/dist/template/.opencode/command/accessibility-check.md +1 -1
  7. package/dist/template/.opencode/command/commit.md +1 -1
  8. package/dist/template/.opencode/command/create.md +68 -441
  9. package/dist/template/.opencode/command/finish.md +82 -252
  10. package/dist/template/.opencode/command/fix-ci.md +52 -247
  11. package/dist/template/.opencode/command/fix-types.md +32 -292
  12. package/dist/template/.opencode/command/fix-ui.md +49 -234
  13. package/dist/template/.opencode/command/fix.md +57 -194
  14. package/dist/template/.opencode/command/handoff.md +66 -243
  15. package/dist/template/.opencode/command/implement.md +67 -231
  16. package/dist/template/.opencode/command/issue.md +42 -190
  17. package/dist/template/.opencode/command/plan.md +86 -442
  18. package/dist/template/.opencode/command/pr.md +3 -1
  19. package/dist/template/.opencode/command/research-and-implement.md +69 -370
  20. package/dist/template/.opencode/command/research.md +72 -197
  21. package/dist/template/.opencode/command/resume.md +70 -438
  22. package/dist/template/.opencode/command/status.md +11 -11
  23. package/dist/template/.opencode/command/triage.md +23 -18
  24. package/dist/template/.opencode/memory/project/commands.md +139 -7
  25. package/dist/template/.opencode/memory/project/gotchas.md +85 -0
  26. package/dist/template/.opencode/plugin/beads.ts +181 -16
  27. package/dist/template/.opencode/skill/beads/SKILL.md +15 -0
  28. package/dist/template/.opencode/skill/context-engineering/SKILL.md +94 -0
  29. package/dist/template/.opencode/skill/memory-system/SKILL.md +107 -0
  30. package/dist/template/.opencode/skill/session-management/SKILL.md +111 -0
  31. package/dist/template/.opencode/skill/tool-priority/SKILL.md +115 -0
  32. package/package.json +1 -1
@@ -17,7 +17,7 @@ Analyze open tasks and optimize prioritization using dependency graph analysis,
17
17
  ## Phase 1: Initialize Beads Connection
18
18
 
19
19
  ```typescript
20
- bd_init({ _: true, team: "project", role: "triage" });
20
+ bd_init({ team: "project", role: "build" });
21
21
  ```
22
22
 
23
23
  ## Phase 2: Gather Workspace State
@@ -27,7 +27,7 @@ Run in parallel:
27
27
  ```typescript
28
28
  bd_status({ include_agents: true });
29
29
  bd_ls({ status: "open", limit: 50, offset: 0 });
30
- bd_reservations({ reason: "Check active file locks" });
30
+ bd_reservations();
31
31
  bd_inbox({ n: 10, unread: true, global: true });
32
32
 
33
33
  // Search for past discussions on recurring issues
@@ -199,14 +199,14 @@ AGENT WORKLOAD
199
199
  ━━━━━━━━━━━━━━
200
200
  Agent │ Active │ Completed │ Load
201
201
  ──────────┼────────┼───────────┼──────
202
- fe-agent │ 2 │ 8 │ HIGH
203
- be-agent │ 1 │ 12 │ MEDIUM
204
- qa-agent │ 0 │ 5 │ LOW
202
+ build-1 │ 2 │ 8 │ HIGH
203
+ build-2 │ 1 │ 12 │ MEDIUM
204
+ review │ 0 │ 5 │ LOW
205
205
 
206
206
  RECOMMENDATIONS
207
207
  ━━━━━━━━━━━━━━━
208
- 1. 🔴 URGENT: bd-abc12 is blocking 4 tasks - assign to be-agent
209
- 2. 🟡 REBALANCE: fe-agent has high load - redistribute to qa-agent
208
+ 1. 🔴 URGENT: bd-abc12 is blocking 4 tasks - assign to build agent
209
+ 2. 🟡 REBALANCE: build-1 has high load - redistribute to review agent
210
210
  3. 🟢 PARALLEL: Start Track A and B simultaneously
211
211
  4. ⚠️ STALE: bd-old99 has no activity for 7 days - review or close
212
212
 
@@ -221,12 +221,13 @@ If `--auto-assign` flag:
221
221
 
222
222
  ```typescript
223
223
  const assignmentRules = {
224
- // Role detection from task tags/title
225
- "frontend|ui|css|react|vue": "fe",
226
- "backend|api|database|server": "be",
227
- "test|qa|e2e|integration": "qa",
228
- "deploy|ci|docker|infra": "devops",
229
- "mobile|ios|android|react-native": "mobile",
224
+ // All implementation work goes to build agents
225
+ "frontend|ui|css|react|vue": "build",
226
+ "backend|api|database|server": "build",
227
+ "deploy|ci|docker|infra": "build",
228
+ "mobile|ios|android|react-native": "build",
229
+ // Review/QA work goes to review agent
230
+ "test|qa|e2e|integration": "review",
230
231
  };
231
232
 
232
233
  // Load balancing: prefer agent with lowest active count
@@ -253,12 +254,12 @@ for (const task of readyTasks.filter((t) => !t.assignee && t.priority <= 2)) {
253
254
  AUTO-ASSIGNMENTS
254
255
  ━━━━━━━━━━━━━━━━
255
256
 
256
- ✓ bd-abc12 → be-agent (detected: backend, API)
257
- ✓ bd-def34 → fe-agent (detected: frontend, React)
258
- ✓ bd-ghi56 → devops (detected: infrastructure)
257
+ ✓ bd-abc12 → build (detected: backend, API)
258
+ ✓ bd-def34 → build (detected: frontend, React)
259
+ ✓ bd-ghi56 → build (detected: infrastructure)
259
260
 
260
261
  Skipped:
261
- - bd-xyz99: Already assigned to qa-agent
262
+ - bd-xyz99: Already assigned to review agent
262
263
  - bd-old88: No matching role detected (manual assignment needed)
263
264
  ```
264
265
 
@@ -293,7 +294,11 @@ console.log("3. Review individually");
293
294
  ## Phase 9: Sync and Notify
294
295
 
295
296
  ```typescript
296
- bd_sync({ reason: "Triage complete" });
297
+
298
+ ```
299
+
300
+ ```typescript
301
+ bd_sync({ reason: "Sync triage changes" });
297
302
 
298
303
  // Broadcast triage summary if significant changes
299
304
  if (assignmentsMade > 0 || priorityChanges > 0) {
@@ -52,14 +52,146 @@ OPENCODE_DISABLE_PRUNE=true # Disable DCP pruning
52
52
  "nudgeFrequency": 8 // LLM nudged every 8 tool calls (default: 10)
53
53
  ```
54
54
 
55
+ ## Beads CLI (Core)
56
+
57
+ The `bd` command is your issue tracker. JSONL is source of truth, SQLite is cache.
58
+
59
+ ### Essential Commands
60
+
61
+ ```bash
62
+ bd ready # Unblocked tasks (use this to find work)
63
+ bd list --status=open # All open issues
64
+ bd show <id> # Full details
65
+ bd create "Title" -t task -p 2 # Create (type: task/bug/feature/epic, priority: 0-4)
66
+ bd update <id> --status in_progress # Claim work
67
+ bd close <id> --reason "Done" # Complete
68
+ bd sync # Export/commit/push (always run at session end)
69
+ ```
70
+
71
+ ### Dependencies
72
+
73
+ ```bash
74
+ bd dep add <child> <parent> --type blocks # Child blocked until parent closes
75
+ bd dep tree <id> # Visualize dependency chain
76
+ bd blocked # Show all blocked issues
77
+ ```
78
+
79
+ ### Coordination
80
+
81
+ ```bash
82
+ bd list --status in_progress # See what's claimed by others
83
+ git pull && bd import # Get latest from team
84
+ bd sync # Push your changes
85
+ ```
86
+
87
+ ### Priority Levels
88
+
89
+ - **P0** - Critical (security, data loss)
90
+ - **P1** - High (major features, important bugs)
91
+ - **P2** - Medium (default)
92
+ - **P3** - Low
93
+ - **P4** - Backlog
94
+
95
+ ### Sandbox Mode
96
+
97
+ If running in restricted environment (Claude Code, etc.):
98
+
99
+ ```bash
100
+ bd --sandbox ready
101
+ # Or: bd --no-daemon --no-auto-flush --no-auto-import list
102
+ ```
103
+
104
+ ## Beads Plugin Tools (For OpenCode Agents)
105
+
106
+ This project's plugin (`.opencode/plugin/beads.ts`) provides typed tools that wrap the CLI.
107
+
108
+ ### Session Lifecycle
109
+
110
+ ```typescript
111
+ bd_init({ role: "build" }); // Join workspace - MUST call first
112
+ bd_claim(); // Get next ready task, mark in_progress
113
+ bd_reserve({ paths: ["src/foo.ts"] }); // Lock files before editing
114
+ // ... do work ...
115
+ bd_done({ id: "bd-xxx", msg: "Done" }); // Close + release locks + sync
116
+ ```
117
+
118
+ ### Task Management
119
+
120
+ ```typescript
121
+ bd_add({ title: "Task", pri: 2, type: "task" }); // Create issue
122
+ bd_show({ id: "bd-xxx" }); // Get full details
123
+ bd_ls({ status: "open", limit: 10 }); // List issues
124
+ bd_ready(); // Ready-to-work tasks
125
+ bd_update({ id: "bd-xxx", status: "in_progress" }); // Update issue
126
+ bd_search({ query: "auth" }); // Search issues
127
+ ```
128
+
129
+ ### File Locking (Plugin-Only)
130
+
131
+ ```typescript
132
+ bd_reserve({ paths: ["src/a.ts", "src/b.ts"], ttl: 600 }); // Lock files
133
+ bd_reservations(); // List active locks
134
+ bd_release({ paths: ["src/a.ts"] }); // Release specific
135
+ bd_release(); // Release all
136
+ ```
137
+
138
+ ### Messaging (Plugin-Only)
139
+
140
+ ```typescript
141
+ bd_msg({ subj: "Done", to: "all", global: true }); // Broadcast
142
+ bd_inbox({ n: 5, unread: true }); // Check messages
143
+ bd_ack({ ids: ["msg-abc", "msg-def"] }); // Mark messages as read
144
+ ```
145
+
146
+ ### Agent Coordination (Plugin-Only)
147
+
148
+ ```typescript
149
+ bd_whois(); // See all agents and their current work
150
+ bd_whois({ agent: "build-abc" }); // Lookup specific agent
151
+ ```
152
+
153
+ ### Maintenance
154
+
155
+ ```typescript
156
+ bd_sync(); // Sync with git
157
+ bd_status({ include_agents: true }); // Workspace overview
158
+ bd_doctor(); // Check database health
159
+ bd_cleanup({ days: 7 }); // Remove old closed issues
160
+ ```
161
+
55
162
  ## Beads Workflow
56
163
 
164
+ ### Start Work
165
+
57
166
  ```bash
58
- bd ready # Show issues ready to work (no blockers)
59
- bd list --status=open # All open issues
60
- bd show <id> # Full issue details with dependencies
61
- bd create --title="..." --type=task --priority=2
62
- bd update <id> --status=in_progress
63
- bd close <id> --reason="Completed"
64
- bd sync # Commit and push changes
167
+ bd ready # Find unblocked task
168
+ bd update bd-xxx --status in_progress # Claim it
169
+ git checkout -b bd-xxx # Create branch
65
170
  ```
171
+
172
+ ### During Work
173
+
174
+ ```bash
175
+ git commit -m "WIP: bd-xxx - [progress]" # Checkpoint commits
176
+ bd sync # Sync beads state
177
+ ```
178
+
179
+ ### End Session
180
+
181
+ ```bash
182
+ git add -A && git commit -m "bd-xxx: [summary]"
183
+ bd close bd-xxx --reason "Completed: [what]"
184
+ bd sync
185
+ git push
186
+ ```
187
+
188
+ ### Handoff (If Not Finishing)
189
+
190
+ ```bash
191
+ git commit -m "WIP: bd-xxx - [where stopped]"
192
+ # Create handoff in .beads/artifacts/bd-xxx/handoffs/
193
+ bd sync
194
+ git push
195
+ ```
196
+
197
+ Resume later with: `/resume bd-xxx`
@@ -58,3 +58,88 @@ If tools are unexpectedly blocked:
58
58
  2. Check project config: `.opencode/opencode.json`
59
59
  3. Project config takes precedence
60
60
  4. Use `"*": "ask"` as base rule to debug which pattern is matching
61
+
62
+ ## Beads Gotchas
63
+
64
+ ### Core Beads CLI vs This Project's Plugin
65
+
66
+ **Core beads CLI** (`bd`) is the upstream tool from steveyegge/beads.
67
+
68
+ **This project's plugin** (`.opencode/plugin/beads.ts`) wraps the CLI and adds:
69
+
70
+ - `bd_done()` - closes task + releases locks + syncs in one call
71
+ - `bd_reserve()` / `bd_release()` - atomic file locking via mkdir
72
+ - `bd_claim()` - finds ready task + marks in_progress
73
+ - `bd_msg()` / `bd_inbox()` / `bd_ack()` - agent-to-agent messaging
74
+ - `bd_whois()` - agent directory lookup (who's working on what)
75
+ - Agent state (current task, reserved files, agent ID)
76
+
77
+ ### Which To Use
78
+
79
+ | Context | Use |
80
+ | -------------------- | ----------------------- |
81
+ | OpenCode agents | Plugin tools (`bd_*()`) |
82
+ | Shell scripts, CI/CD | CLI (`bd`) |
83
+ | Human terminal | CLI (`bd`) |
84
+
85
+ ### Plugin Tools (Preferred for Agents)
86
+
87
+ ```typescript
88
+ bd_init({ role: "build" }); // Join workspace
89
+ bd_claim(); // Get next ready task
90
+ bd_reserve({ paths: ["src/foo.ts"] }); // Lock files
91
+ // ... do work ...
92
+ bd_done({ id: "bd-xxx", msg: "Done" }); // Close + release + sync
93
+ ```
94
+
95
+ ### CLI Commands (For Scripts/Humans)
96
+
97
+ ```bash
98
+ bd create "Task title" -t task -p 2 # Create
99
+ bd update bd-xxx --status in_progress # Claim
100
+ bd close bd-xxx --reason "Done" # Complete
101
+ bd sync # Push to git
102
+ ```
103
+
104
+ ### Hash-Based IDs Prevent Collisions
105
+
106
+ Beads uses hash IDs (`bd-a3f8`) not sequential IDs (`bd-1`, `bd-2`). This eliminates merge conflicts when multiple agents create issues on different branches.
107
+
108
+ Don't assume sequential IDs. Always use `bd show` to get exact IDs.
109
+
110
+ ### `bd ready` Is Your Friend
111
+
112
+ `bd ready` shows tasks with NO unresolved blockers. Use it to find work instead of `bd list`.
113
+
114
+ ### Dependencies Block Work
115
+
116
+ ```bash
117
+ bd dep add bd-child bd-parent --type blocks
118
+ ```
119
+
120
+ Now `bd-child` won't appear in `bd ready` until `bd-parent` closes. Check `bd blocked` to see what's waiting.
121
+
122
+ ### Git Is The Coordination Layer
123
+
124
+ No central server. Agents coordinate via:
125
+
126
+ 1. Issue status (in_progress = claimed)
127
+ 2. Git branches
128
+ 3. `bd sync` to push/pull changes
129
+
130
+ ### Sandbox Environments (Claude Code, etc.)
131
+
132
+ Daemon can't be killed by sandbox. Use:
133
+
134
+ ```bash
135
+ bd --sandbox ready
136
+ # Or: bd --no-daemon --no-auto-flush --no-auto-import list
137
+ ```
138
+
139
+ ### 30-Second Debounce
140
+
141
+ Rapid operations get batched into single JSONL flush after 30s. Force immediate sync:
142
+
143
+ ```bash
144
+ bd sync
145
+ ```
@@ -366,10 +366,12 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
366
366
  filePath: string,
367
367
  reason?: string,
368
368
  ttlSeconds = 600,
369
+ overrideAgent?: string,
369
370
  ): Promise<{ acquired: boolean; holder?: string }> {
370
371
  const lockPath = lockDir(filePath);
371
372
  const now = Date.now();
372
373
  const expires = now + ttlSeconds * 1000;
374
+ const agentToUse = overrideAgent || state.agentId;
373
375
 
374
376
  // Atomic: mkdir fails if dir exists
375
377
  try {
@@ -384,10 +386,10 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
384
386
  if (lock.expires < now) {
385
387
  // Expired - remove and retry
386
388
  await $`rm -rf ${lockPath}`.cwd(directory).quiet();
387
- return acquireLock(filePath, reason, ttlSeconds);
389
+ return acquireLock(filePath, reason, ttlSeconds, overrideAgent);
388
390
  }
389
391
 
390
- if (lock.agent === state.agentId) {
392
+ if (lock.agent === agentToUse) {
391
393
  // We already hold this lock - refresh it
392
394
  lock.expires = expires;
393
395
  await $`echo ${JSON.stringify(lock)} > ${metaPath}`
@@ -400,14 +402,14 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
400
402
  } catch {
401
403
  // Corrupted lock - remove and retry
402
404
  await $`rm -rf ${lockPath}`.cwd(directory).quiet();
403
- return acquireLock(filePath, reason, ttlSeconds);
405
+ return acquireLock(filePath, reason, ttlSeconds, overrideAgent);
404
406
  }
405
407
  }
406
408
 
407
409
  // Lock acquired - write metadata
408
410
  const lockData: LockData = {
409
411
  path: filePath,
410
- agent: state.agentId,
412
+ agent: agentToUse,
411
413
  reason,
412
414
  created: now,
413
415
  expires,
@@ -597,7 +599,7 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
597
599
  role: tool.schema
598
600
  .string()
599
601
  .optional()
600
- .describe("Role: fe|be|mobile|devops|qa"),
602
+ .describe("Role: build|rush|explore|planner|review|scout|vision"),
601
603
  },
602
604
  async execute(args) {
603
605
  await $`bd init`
@@ -670,11 +672,17 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
670
672
  .default("completed")
671
673
  .describe("Completion message"),
672
674
  },
673
- async execute(args) {
675
+ async execute(args, context) {
674
676
  const taskId = args.id || state.currentTask;
675
677
  if (!taskId) return json({ error: "No task ID" });
676
678
 
677
- const closeResult = await bdClose(taskId, args.msg);
679
+ // Audit trail
680
+ const auditAgent = context?.agent || state.agentId;
681
+
682
+ const closeResult = await bdClose(
683
+ taskId,
684
+ `${args.msg} [by ${auditAgent}]`,
685
+ );
678
686
  if (closeResult.error) return json({ error: closeResult.error });
679
687
 
680
688
  // Release all locks
@@ -708,7 +716,9 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
708
716
  tags: tool.schema
709
717
  .array(tool.schema.string())
710
718
  .optional()
711
- .describe("Role tags: fe,be,mobile,devops,qa"),
719
+ .describe(
720
+ "Agent tags: build,rush,explore,planner,review,scout,vision",
721
+ ),
712
722
  parent: tool.schema.string().optional().describe("Parent issue ID"),
713
723
  deps: tool.schema
714
724
  .array(tool.schema.string())
@@ -754,7 +764,9 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
754
764
  "Assign task to role (leader only). Adds tag and notifies.",
755
765
  args: {
756
766
  id: tool.schema.string().describe("Issue ID"),
757
- role: tool.schema.string().describe("Role: fe|be|mobile|devops|qa"),
767
+ role: tool.schema
768
+ .string()
769
+ .describe("Role: build|rush|explore|planner|review|scout|vision"),
758
770
  notify: tool.schema
759
771
  .boolean()
760
772
  .default(true)
@@ -882,16 +894,24 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
882
894
  .default(600)
883
895
  .describe("Seconds until expiry"),
884
896
  },
885
- async execute(args) {
897
+ async execute(args, context) {
886
898
  if (!args.paths?.length) return json({ error: "paths required" });
887
899
 
900
+ // Log who is reserving for audit
901
+ const reservingAgent = context?.agent || state.agentId;
902
+
888
903
  await ensureReservationsDir();
889
904
 
890
905
  const granted: string[] = [];
891
906
  const conflicts: { path: string; holder?: string }[] = [];
892
907
 
893
908
  for (const path of args.paths) {
894
- const result = await acquireLock(path, args.reason, args.ttl);
909
+ const result = await acquireLock(
910
+ path,
911
+ args.reason,
912
+ args.ttl,
913
+ reservingAgent,
914
+ );
895
915
  if (result.acquired) {
896
916
  granted.push(path);
897
917
  } else {
@@ -963,12 +983,15 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
963
983
  .default(false)
964
984
  .describe("Send to all workspaces"),
965
985
  },
966
- async execute(args) {
986
+ async execute(args, context) {
967
987
  if (!args.subj) return json({ error: "subj required" });
968
988
 
989
+ // Use context agent if available for audit trail
990
+ const senderAgent = context?.agent || state.agentId;
991
+
969
992
  const msg: Message = {
970
993
  id: `msg-${Date.now().toString(36)}`,
971
- from: state.agentId,
994
+ from: senderAgent,
972
995
  to: args.to || "all",
973
996
  subj: args.subj,
974
997
  body: args.body,
@@ -1000,6 +1023,117 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
1000
1023
  },
1001
1024
  }),
1002
1025
 
1026
+ bd_ack: tool({
1027
+ description: "Acknowledge message(s). Marks as read.",
1028
+ args: {
1029
+ ids: tool.schema
1030
+ .array(tool.schema.string())
1031
+ .describe("Message IDs to acknowledge"),
1032
+ },
1033
+ async execute(args) {
1034
+ if (!args.ids?.length) return json({ error: "ids required" });
1035
+
1036
+ try {
1037
+ const content =
1038
+ await $`cat ${RESERVATIONS_DIR}/messages.jsonl 2>/dev/null`
1039
+ .cwd(directory)
1040
+ .text();
1041
+
1042
+ if (!content.trim()) return json({ acked: 0 });
1043
+
1044
+ const idsToAck = new Set(args.ids);
1045
+ let acked = 0;
1046
+
1047
+ const msgs = content
1048
+ .trim()
1049
+ .split("\n")
1050
+ .map((line) => {
1051
+ try {
1052
+ const msg = JSON.parse(line) as Message;
1053
+ if (idsToAck.has(msg.id) && !msg.read) {
1054
+ msg.read = true;
1055
+ acked++;
1056
+ }
1057
+ return msg;
1058
+ } catch {
1059
+ return null;
1060
+ }
1061
+ })
1062
+ .filter((m): m is Message => m !== null);
1063
+
1064
+ const newContent = msgs.map((m) => JSON.stringify(m)).join("\n");
1065
+ await $`echo ${newContent} > ${RESERVATIONS_DIR}/messages.jsonl`
1066
+ .cwd(directory)
1067
+ .quiet();
1068
+
1069
+ return json({ ok: 1, acked });
1070
+ } catch {
1071
+ return json({ acked: 0 });
1072
+ }
1073
+ },
1074
+ }),
1075
+
1076
+ bd_whois: tool({
1077
+ description: "Agent directory lookup. See who's working on what.",
1078
+ args: {
1079
+ agent: tool.schema
1080
+ .string()
1081
+ .optional()
1082
+ .describe("Agent ID to lookup (empty=all)"),
1083
+ },
1084
+ async execute(args) {
1085
+ const locks = await getAllLocks();
1086
+ const { tasks: inProgressTasks } = await bdList({
1087
+ status: "in_progress",
1088
+ });
1089
+
1090
+ // Build agent activity map
1091
+ const agentMap: Record<
1092
+ string,
1093
+ {
1094
+ files: string[];
1095
+ task?: string;
1096
+ role?: string;
1097
+ }
1098
+ > = {};
1099
+
1100
+ // Add locks info
1101
+ for (const lock of locks) {
1102
+ if (!agentMap[lock.agent]) {
1103
+ agentMap[lock.agent] = { files: [] };
1104
+ }
1105
+ agentMap[lock.agent].files.push(lock.path);
1106
+ if (lock.task) {
1107
+ agentMap[lock.agent].task = lock.task;
1108
+ }
1109
+ }
1110
+
1111
+ // Add current agent info
1112
+ if (!agentMap[state.agentId]) {
1113
+ agentMap[state.agentId] = { files: [] };
1114
+ }
1115
+ agentMap[state.agentId].role = state.role || undefined;
1116
+ if (state.currentTask) {
1117
+ agentMap[state.agentId].task = state.currentTask;
1118
+ }
1119
+
1120
+ // Filter if specific agent requested
1121
+ if (args.agent) {
1122
+ const agent = agentMap[args.agent];
1123
+ if (!agent) return json({ error: "agent not found" });
1124
+ return json({ agent: args.agent, ...agent });
1125
+ }
1126
+
1127
+ return json({
1128
+ agents: Object.entries(agentMap).map(([id, info]) => ({
1129
+ id,
1130
+ ...info,
1131
+ })),
1132
+ in_progress_tasks: inProgressTasks.length,
1133
+ });
1134
+ },
1135
+ }),
1136
+
1003
1137
  bd_status: tool({
1004
1138
  description: "Workspace overview. Shows agents, tasks, locks.",
1005
1139
  args: {
@@ -1038,10 +1172,22 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
1038
1172
 
1039
1173
  bd_sync: tool({
1040
1174
  description: "Sync with git. Pull/push changes.",
1041
- args: {},
1042
- async execute() {
1175
+ args: {
1176
+ reason: tool.schema
1177
+ .string()
1178
+ .optional()
1179
+ .describe("Audit trail reason for sync"),
1180
+ },
1181
+ async execute(args, context) {
1043
1182
  const result = await bdSync();
1044
- return json({ ok: 1, output: result.output });
1183
+ // Log sync with context for audit trail
1184
+ const syncAgent = context?.agent || state.agentId;
1185
+ return json({
1186
+ ok: 1,
1187
+ output: result.output,
1188
+ by: syncAgent,
1189
+ reason: args.reason,
1190
+ });
1045
1191
  },
1046
1192
  }),
1047
1193
 
@@ -1249,6 +1395,25 @@ export const BeadsCorePlugin: Plugin = async ({ $, directory }) => {
1249
1395
  if (event.type === "session.idle" && state.currentTask) {
1250
1396
  await bdSync();
1251
1397
  }
1398
+
1399
+ // Cleanup expired locks on compaction
1400
+ if (event.type === "session.compacted") {
1401
+ await cleanupExpiredLocks();
1402
+ }
1403
+
1404
+ // Log errors to audit trail
1405
+ if (event.type === "session.error" && state.currentTask) {
1406
+ await appendMessage({
1407
+ id: `err-${Date.now().toString(36)}`,
1408
+ from: state.agentId,
1409
+ to: "all",
1410
+ subj: `Session error on task ${state.currentTask}`,
1411
+ body: `Error occurred during task execution`,
1412
+ importance: "high",
1413
+ at: Date.now(),
1414
+ read: false,
1415
+ });
1416
+ }
1252
1417
  },
1253
1418
  };
1254
1419
  };
@@ -340,6 +340,21 @@ bd_msg({
340
340
  bd_inbox({ unread: true, n: 10 });
341
341
  ```
342
342
 
343
+ ### Acknowledge Messages
344
+
345
+ ```typescript
346
+ bd_ack({ ids: ["msg-abc", "msg-def"] }); // Mark as read
347
+ ```
348
+
349
+ ## Agent Coordination
350
+
351
+ ### Who's Working on What
352
+
353
+ ```typescript
354
+ bd_whois(); // All agents with their files and tasks
355
+ bd_whois({ agent: "build-abc" }); // Specific agent lookup
356
+ ```
357
+
343
358
  ## Status and Analysis
344
359
 
345
360
  ### Workspace Overview