opcrew 0.1.3 → 0.1.5

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/dist/cli.js CHANGED
@@ -5,23 +5,23 @@
5
5
  import process from "process";
6
6
 
7
7
  // src/cli/install.ts
8
- import { mkdir, writeFile } from "fs/promises";
9
- import path from "path";
8
+ import { mkdir, writeFile, cp, rm } from "fs/promises";
9
+ import path2 from "path";
10
10
  // src/core/tools/translations.ts
11
11
  var CLAUDE_TOOLS = {
12
- read: "read_fs",
13
- write: "edit_code",
14
- edit: "edit_code",
15
- glob: "bash",
16
- grep: "bash",
17
- execute: "bash",
18
- websearch: "web_search",
19
- webfetch: "web_fetch",
20
- delegate: "task",
21
- todo: "todowrite",
22
- test: "run_tests",
23
- logbook: "edit_logbook",
24
- skill: "skill"
12
+ read: "Read",
13
+ write: "Write",
14
+ edit: "Edit",
15
+ glob: "Glob",
16
+ grep: "Grep",
17
+ execute: "Bash",
18
+ websearch: "WebSearch",
19
+ webfetch: "WebFetch",
20
+ delegate: "Agent",
21
+ todo: "TodoWrite",
22
+ test: "Bash",
23
+ logbook: "",
24
+ skill: "Skill"
25
25
  };
26
26
  var OPENCODE_TOOLS = {
27
27
  read: "read",
@@ -61,7 +61,7 @@ function translateTools(canonicalTools, platform) {
61
61
  };
62
62
  const translationMap = maps[platform];
63
63
  const translated = canonicalTools.map((tool) => translationMap[tool]);
64
- return [...new Set(translated)];
64
+ return [...new Set(translated)].filter((tool) => tool !== "");
65
65
  }
66
66
  // src/core/Agent.ts
67
67
  class OpCrewAgent {
@@ -69,11 +69,28 @@ class OpCrewAgent {
69
69
  constructor(config) {
70
70
  this.config = config;
71
71
  }
72
+ getAllowedTools() {
73
+ return this.config.allowedTools ?? this.config.tools ?? [];
74
+ }
75
+ hasTool(tool) {
76
+ return this.getAllowedTools().includes(tool);
77
+ }
78
+ validateToolUsage(tool) {
79
+ if (!this.hasTool(tool)) {
80
+ const allowedList = this.getAllowedTools().join(", ") || "(none)";
81
+ throw new Error(`Tool '${tool}' is not allowed for agent '${this.config.name}'. ` + `Allowed tools: [${allowedList}]`);
82
+ }
83
+ }
84
+ getForbiddenTools(allAvailableTools) {
85
+ const allowedSet = new Set(this.getAllowedTools());
86
+ return allAvailableTools.filter((tool) => !allowedSet.has(tool));
87
+ }
72
88
  compileToMarkdown() {
73
- const translatedTools = translateTools(this.config.tools, "claude");
89
+ const translatedTools = translateTools(this.getAllowedTools(), "claude");
90
+ const lowerName = this.config.name.toLowerCase();
74
91
  const frontmatter = `---
75
- name: ${this.config.name}
76
- role: ${this.config.role}
92
+ name: ${lowerName}
93
+ description: ${this.config.description}
77
94
  tools: [${translatedTools.join(", ")}]
78
95
  ---`;
79
96
  return `${frontmatter}
@@ -84,7 +101,7 @@ ${this.buildMarkdownBody()}`;
84
101
  Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
85
102
  Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
86
103
  Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
87
- Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" },
104
+ Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
88
105
  Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
89
106
  };
90
107
  const permission = permissionByRole[this.config.role];
@@ -100,7 +117,7 @@ permission:
100
117
  ${this.buildMarkdownBody()}`;
101
118
  }
102
119
  compileToCodexMarkdown() {
103
- const translatedTools = translateTools(this.config.tools, "codex");
120
+ const translatedTools = translateTools(this.getAllowedTools(), "codex");
104
121
  const frontmatter = `---
105
122
  name: ${this.config.name}
106
123
  role: ${this.config.role}
@@ -125,102 +142,126 @@ Refer to \`.opcrew/logbook.json\` for the current voyage status.
125
142
  // src/crew/Captain.ts
126
143
  var Captain = new OpCrewAgent({
127
144
  name: "Captain",
145
+ description: "Orchestrator agent that coordinates work delegation and verification. Use for complex multi-step tasks requiring coordination between specialists.",
128
146
  role: "Orchestrator",
129
147
  mode: "primary",
130
148
  instructions: [
149
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
131
150
  "You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
132
- "Define mission intent with explicit scope, constraints, and success criteria before any execution.",
151
+ "Workstream Fan-out: divide missions into independent Workstreams (e.g., Logic, Testing, Documentation) to enable parallel specialists.",
133
152
  "Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
134
- "Require a logbook entry that captures decisions, risks, and acceptance checks for every mission.",
153
+ "Collision Prevention: ensure no two Boatswains are assigned the same file or symbol in parallel. Launch workstreams only if they are logically decoupled.",
135
154
  "Escalate blockers immediately and re-sequence work to unblock the critical path.",
136
155
  "Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
137
156
  "Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
138
157
  "Delegation mandate: ALWAYS delegate work to specialists using the task tool. Never perform file edits, code changes, or direct execution yourself.",
139
158
  "Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
140
- "Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
141
159
  "Verification gate: delegate verification to Quartermaster; ensure diagnostics/tests run and evidence is logged before marking complete.",
160
+ "Conflict Resolution: if specialists disagree on implementation, make the final call based on project documentation.",
142
161
  "Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
143
162
  "Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
144
163
  ],
145
- tools: ["read", "logbook", "delegate"]
164
+ tools: ["read", "logbook", "delegate", "skill"]
146
165
  });
147
166
 
148
167
  // src/crew/Navigator.ts
149
168
  var Navigator = new OpCrewAgent({
150
169
  name: "Navigator",
170
+ description: "Planning specialist that decomposes work into atomic tasks with clear inputs, outputs, and ownership. Use when you need to chart an implementation path or create a structured plan.",
151
171
  role: "Planner",
152
172
  mode: "subagent",
153
173
  instructions: [
174
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, websearch, logbook, todo, skill. Using any other tool is a violation.",
154
175
  "Chart the implementation path based on the Captain's intent and constraints.",
155
176
  "Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
177
+ "Workstream Decomposition: break the plan into atomic, parallel tracks. Define File Ownership (e.g., Boatswain-A owns src/, Boatswain-B owns tests/).",
178
+ "Survey the Stack: identify the project's native build system (BUILD_CMD), test runner (TEST_CMD), and style guide immediately.",
179
+ "Documentation Maintenance: plan for updates to docs/project-map.md and docs/glossary.md; assign these to a specific workstream.",
180
+ "Dependency Graphing: flag Blocking Tasks where one workstream depends on the output of another; sequence these to avoid idle agents.",
181
+ "Execution Manifest: for every task, specify Target File, Affected Symbols, Invariants, and the exact Verification Command.",
156
182
  "Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
157
183
  "Maintain a current project map (key files, modules, and ownership boundaries).",
158
184
  "Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
159
185
  "Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
160
186
  "Create and manage todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
161
187
  "Mandate parallel discovery for unknowns: launch multiple explore/librarian threads and consolidate findings.",
188
+ "Discovery Primitives: use language-agnostic tools (grep, find, tree) to map dependencies before proposing edits.",
162
189
  "Delegate external research to Scout when you need information from outside the project: libraries, APIs, best practices, or documentation.",
163
190
  "Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
164
191
  "Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
165
192
  ],
166
- tools: ["read", "websearch", "logbook", "todo"]
193
+ tools: ["read", "websearch", "logbook", "todo", "skill"]
167
194
  });
168
195
 
169
196
  // src/crew/Boatswain.ts
170
197
  var Boatswain = new OpCrewAgent({
171
198
  name: "Boatswain",
199
+ description: "Execution specialist that implements approved plans with precise edits. Use when you need to make code changes, run tests, or execute implementation steps.",
172
200
  role: "Executor",
173
201
  mode: "subagent",
174
202
  instructions: [
175
- "Turn approved Navigator steps into precise edits without scope creep.",
203
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, edit, write, test, todo, glob, grep, skill. Using any other tool is a violation.",
204
+ "Scope Guarding: ONLY touch files assigned to your Workstream ID. If you must edit a file owned by another agent, escalate to Captain for a plan revision.",
176
205
  "Follow existing patterns, naming, and formatting; avoid speculative changes.",
206
+ "Context Anchoring: before editing, read the surrounding code to match indentation, casing, and comment styles. Maintain the project's local laws.",
207
+ "Parallel Execution: implement the Navigator's Manifest exactly. Update code, tests, and documentation (docs/project-map.md or docs/glossary.md) as assigned.",
177
208
  "Keep diffs lean and standards-compliant; update only what the plan calls for.",
178
- "Run required sanity tests and record results in the logbook.",
179
- "Log completion status, assumptions, and blockers immediately for the Captain.",
209
+ "Atomic Verification: run the assigned TEST_CMD for your scope. Record stdout/stderr logs in the logbook immediately.",
180
210
  "Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
181
- "Use verification gates: lsp diagnostics on touched files plus relevant tests/builds before completion.",
211
+ "LSP/Compiler Check: use native diagnostics to ensure no syntax errors were introduced in touched files.",
182
212
  "Update docs/knowledge when execution changes assumptions, definitions, or operational steps.",
183
- "Update todo task status immediately upon completion of each task."
213
+ "Update todo task status immediately upon completion of each task.",
214
+ "Status Discipline: update your specific task status in logbook.json as you work; do not wait for other workstreams to finish."
184
215
  ],
185
- tools: ["read", "edit", "test", "todo"]
216
+ tools: ["read", "edit", "write", "test", "todo", "glob", "grep", "skill"]
186
217
  });
187
218
 
188
219
  // src/crew/Quartermaster.ts
189
220
  var Quartermaster = new OpCrewAgent({
190
221
  name: "Quartermaster",
222
+ description: "Quality assurance specialist that reviews diffs, verifies tests pass, and ensures conventions are followed. Use proactively after code changes to verify quality.",
191
223
  role: "Reviewer",
192
224
  mode: "subagent",
193
225
  instructions: [
226
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, grep, execute, write, skill. Using any other tool is a violation.",
194
227
  "Inspect each diff for regression risks, scope drift, and missing context.",
195
- "Confirm tests, docs, and logbook entries prove the change is complete.",
196
- "Verify acceptance checks and ensure the plan-to-implementation trace is intact.",
228
+ "Integration Audit: once all parallel Boatswains report Complete, verify the combined diff for logic conflicts or signature mismatches.",
229
+ "Documentation Gate: REJECT approval if code changed but docs/project-map.md or docs/glossary.md were not updated to reflect the new state.",
230
+ "Evidence Verification: ensure every workstream provided terminal logs proving their respective tests or build commands passed.",
231
+ "Traceability: confirm the final implementation matches the Navigator's original Invariants.",
197
232
  "Escalate unresolved quality gaps to the Captain before approval.",
198
233
  "Require rework when verification is missing or conventions are violated.",
199
234
  "Reject approvals lacking evidence (diagnostics/tests/build logs) or missing todo/task tracking.",
235
+ "Regression Check: require a full project TEST_CMD run (if available) to ensure integrated workstreams didn't break the system.",
200
236
  "Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
201
237
  "Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
202
238
  ],
203
- tools: ["read", "grep", "execute", "write"]
239
+ tools: ["read", "grep", "execute", "write", "skill"]
204
240
  });
205
241
 
206
242
  // src/crew/Scout.ts
207
243
  var Scout = new OpCrewAgent({
208
244
  name: "Scout",
245
+ description: "Research specialist for external information gathering - web searches, documentation lookup, API references, and best practices. Use when you need information from outside the project.",
209
246
  role: "Researcher",
210
247
  mode: "subagent",
211
248
  instructions: [
249
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
212
250
  "You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
213
251
  "Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
214
252
  "Never modify project files - your job is to gather intelligence, not execute changes.",
215
253
  "Provide concise, actionable findings with clear sources and citations.",
254
+ "Rosetta Stone Summaries: when researching a new language, explain concepts via analogy - 'This is the [Go] equivalent of [Python's] Decorators.'",
216
255
  "When researching libraries or frameworks, include: version info, installation methods, key APIs, and gotchas.",
217
256
  "Compare alternatives when relevant: pros/cons, trade-offs, and recommendations with rationale.",
218
257
  "Flag deprecated or outdated information; always verify against official sources when possible.",
219
258
  "Summarize findings in a structured format: problem, findings, recommendations, sources.",
259
+ "Glossary Contribution: propose new terms or external definitions for the Boatswain to add to docs/glossary.md.",
220
260
  "If research reveals the task is more complex than expected, escalate to Navigator for replanning.",
221
- "Cache useful references in docs/knowledge for future crew reference."
261
+ "Environment Discovery: research specific error messages or build tool quirks if the Boatswain hits a blocker.",
262
+ "Knowledge Caching: store research summaries in docs/research/ for future crew reference."
222
263
  ],
223
- tools: ["websearch", "webfetch", "read"]
264
+ tools: ["websearch", "webfetch", "read", "skill"]
224
265
  });
225
266
 
226
267
  // src/crew/index.ts
@@ -232,10 +273,66 @@ var crew = [
232
273
  Scout
233
274
  ];
234
275
 
276
+ // src/skills.ts
277
+ import { readdir, readFile } from "fs/promises";
278
+ import path from "path";
279
+ import { fileURLToPath } from "url";
280
+ var __dirname2 = path.dirname(fileURLToPath(import.meta.url));
281
+ async function loadSkills() {
282
+ const skillsDir = path.join(__dirname2, "skills");
283
+ try {
284
+ const entries = await readdir(skillsDir, { withFileTypes: true });
285
+ const skills = [];
286
+ for (const entry of entries) {
287
+ if (!entry.isDirectory())
288
+ continue;
289
+ const skillPath = path.join(skillsDir, entry.name);
290
+ const skillMdPath = path.join(skillPath, "SKILL.md");
291
+ try {
292
+ const content = await readFile(skillMdPath, "utf-8");
293
+ const { name, description } = parseSkillFrontmatter(content);
294
+ skills.push({
295
+ name: name || entry.name,
296
+ description: description || "",
297
+ sourcePath: skillPath
298
+ });
299
+ } catch {
300
+ console.warn(`Warning: No SKILL.md found in ${skillPath}`);
301
+ }
302
+ }
303
+ return skills;
304
+ } catch {
305
+ return [];
306
+ }
307
+ }
308
+ function parseSkillFrontmatter(content) {
309
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
310
+ if (!frontmatterMatch) {
311
+ return {};
312
+ }
313
+ const frontmatter = frontmatterMatch[1];
314
+ const result = {};
315
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
316
+ if (nameMatch) {
317
+ result.name = nameMatch[1].trim();
318
+ }
319
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
320
+ if (descMatch) {
321
+ result.description = descMatch[1].trim();
322
+ }
323
+ return result;
324
+ }
325
+ async function getSkillContent(skillName) {
326
+ const skillMdPath = path.join(__dirname2, "skills", skillName, "SKILL.md");
327
+ return readFile(skillMdPath, "utf-8");
328
+ }
329
+
235
330
  // src/cli/install.ts
236
- var CLAUDE_DIR = path.join(".claude", "agents");
237
- var OPENCODE_DIR = path.join(".opencode", "agents");
238
- var CODEX_FILE = path.join(".codex", "instructions.md");
331
+ var CLAUDE_AGENTS_DIR = path2.join(".claude", "agents");
332
+ var CLAUDE_SKILLS_DIR = path2.join(".claude", "skills");
333
+ var OPENCODE_AGENTS_DIR = path2.join(".opencode", "agents");
334
+ var OPENCODE_SKILLS_DIR = path2.join(".opencode", "skills");
335
+ var CODEX_FILE = path2.join(".codex", "instructions.md");
239
336
  async function ensureDir(targetDir) {
240
337
  await mkdir(targetDir, { recursive: true });
241
338
  }
@@ -244,26 +341,67 @@ async function installToTool(tool) {
244
341
  await installForCodex();
245
342
  return;
246
343
  }
247
- const targetDir = tool === "claude" ? CLAUDE_DIR : OPENCODE_DIR;
248
- await ensureDir(targetDir);
344
+ const agentsDir = tool === "claude" ? CLAUDE_AGENTS_DIR : OPENCODE_AGENTS_DIR;
345
+ const skillsDir = tool === "claude" ? CLAUDE_SKILLS_DIR : OPENCODE_SKILLS_DIR;
346
+ await ensureDir(agentsDir);
249
347
  for (const agent of crew) {
250
348
  const filename = `${agent.config.name.toLowerCase()}.md`;
251
- const filePath = path.join(targetDir, filename);
349
+ const filePath = path2.join(agentsDir, filename);
252
350
  const content = tool === "opencode" ? agent.compileToOpenCodeMarkdown() : agent.compileToMarkdown();
253
351
  await writeFile(filePath, content);
254
- console.log(`Synced ${agent.config.name} to ${targetDir}`);
352
+ console.log(`Synced ${agent.config.name} to ${agentsDir}`);
353
+ }
354
+ await installSkills(skillsDir, tool);
355
+ }
356
+ async function installSkills(targetDir, tool) {
357
+ const skills = await loadSkills();
358
+ if (skills.length === 0) {
359
+ console.log("No skills found to install.");
360
+ return;
361
+ }
362
+ await ensureDir(targetDir);
363
+ for (const skill of skills) {
364
+ const skillDestDir = path2.join(targetDir, skill.name);
365
+ await rm(skillDestDir, { recursive: true, force: true });
366
+ await cp(skill.sourcePath, skillDestDir, { recursive: true });
367
+ console.log(`Synced skill ${skill.name} to ${targetDir}`);
255
368
  }
256
369
  }
257
370
  async function installForCodex() {
258
- const codexDir = path.dirname(CODEX_FILE);
371
+ const codexDir = path2.dirname(CODEX_FILE);
259
372
  await ensureDir(codexDir);
260
- const compiled = crew.map((agent) => agent.compileToCodexMarkdown()).join(`
373
+ const agentsContent = crew.map((agent) => agent.compileToCodexMarkdown()).join(`
261
374
 
262
375
  ---
263
376
 
264
377
  `);
265
- await writeFile(CODEX_FILE, compiled);
378
+ const skills = await loadSkills();
379
+ let skillsContent = "";
380
+ if (skills.length > 0) {
381
+ const skillContents = await Promise.all(skills.map(async (skill) => {
382
+ const content = await getSkillContent(skill.name);
383
+ return `## Skill: ${skill.name}
384
+
385
+ ${content}`;
386
+ }));
387
+ skillsContent = `
388
+
389
+ ---
390
+
391
+ # Skills
392
+
393
+ ` + skillContents.join(`
394
+
395
+ ---
396
+
397
+ `);
398
+ }
399
+ const fullContent = agentsContent + skillsContent;
400
+ await writeFile(CODEX_FILE, fullContent);
266
401
  console.log(`Synced Codex instructions to ${CODEX_FILE}`);
402
+ if (skills.length > 0) {
403
+ console.log(`Synced ${skills.length} skill(s) to Codex instructions`);
404
+ }
267
405
  }
268
406
 
269
407
  // src/cli/index.ts
@@ -15,19 +15,19 @@ var __export = (target, all) => {
15
15
  };
16
16
  // src/core/tools/translations.ts
17
17
  var CLAUDE_TOOLS = {
18
- read: "read_fs",
19
- write: "edit_code",
20
- edit: "edit_code",
21
- glob: "bash",
22
- grep: "bash",
23
- execute: "bash",
24
- websearch: "web_search",
25
- webfetch: "web_fetch",
26
- delegate: "task",
27
- todo: "todowrite",
28
- test: "run_tests",
29
- logbook: "edit_logbook",
30
- skill: "skill"
18
+ read: "Read",
19
+ write: "Write",
20
+ edit: "Edit",
21
+ glob: "Glob",
22
+ grep: "Grep",
23
+ execute: "Bash",
24
+ websearch: "WebSearch",
25
+ webfetch: "WebFetch",
26
+ delegate: "Agent",
27
+ todo: "TodoWrite",
28
+ test: "Bash",
29
+ logbook: "",
30
+ skill: "Skill"
31
31
  };
32
32
  var OPENCODE_TOOLS = {
33
33
  read: "read",
@@ -67,7 +67,7 @@ function translateTools(canonicalTools, platform) {
67
67
  };
68
68
  const translationMap = maps[platform];
69
69
  const translated = canonicalTools.map((tool) => translationMap[tool]);
70
- return [...new Set(translated)];
70
+ return [...new Set(translated)].filter((tool) => tool !== "");
71
71
  }
72
72
  // src/core/Agent.ts
73
73
  class OpCrewAgent {
@@ -75,11 +75,28 @@ class OpCrewAgent {
75
75
  constructor(config) {
76
76
  this.config = config;
77
77
  }
78
+ getAllowedTools() {
79
+ return this.config.allowedTools ?? this.config.tools ?? [];
80
+ }
81
+ hasTool(tool) {
82
+ return this.getAllowedTools().includes(tool);
83
+ }
84
+ validateToolUsage(tool) {
85
+ if (!this.hasTool(tool)) {
86
+ const allowedList = this.getAllowedTools().join(", ") || "(none)";
87
+ throw new Error(`Tool '${tool}' is not allowed for agent '${this.config.name}'. ` + `Allowed tools: [${allowedList}]`);
88
+ }
89
+ }
90
+ getForbiddenTools(allAvailableTools) {
91
+ const allowedSet = new Set(this.getAllowedTools());
92
+ return allAvailableTools.filter((tool) => !allowedSet.has(tool));
93
+ }
78
94
  compileToMarkdown() {
79
- const translatedTools = translateTools(this.config.tools, "claude");
95
+ const translatedTools = translateTools(this.getAllowedTools(), "claude");
96
+ const lowerName = this.config.name.toLowerCase();
80
97
  const frontmatter = `---
81
- name: ${this.config.name}
82
- role: ${this.config.role}
98
+ name: ${lowerName}
99
+ description: ${this.config.description}
83
100
  tools: [${translatedTools.join(", ")}]
84
101
  ---`;
85
102
  return `${frontmatter}
@@ -90,7 +107,7 @@ ${this.buildMarkdownBody()}`;
90
107
  Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
91
108
  Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
92
109
  Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
93
- Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" },
110
+ Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
94
111
  Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
95
112
  };
96
113
  const permission = permissionByRole[this.config.role];
@@ -106,7 +123,7 @@ permission:
106
123
  ${this.buildMarkdownBody()}`;
107
124
  }
108
125
  compileToCodexMarkdown() {
109
- const translatedTools = translateTools(this.config.tools, "codex");
126
+ const translatedTools = translateTools(this.getAllowedTools(), "codex");
110
127
  const frontmatter = `---
111
128
  name: ${this.config.name}
112
129
  role: ${this.config.role}
@@ -131,102 +148,126 @@ Refer to \`.opcrew/logbook.json\` for the current voyage status.
131
148
  // src/crew/Captain.ts
132
149
  var Captain = new OpCrewAgent({
133
150
  name: "Captain",
151
+ description: "Orchestrator agent that coordinates work delegation and verification. Use for complex multi-step tasks requiring coordination between specialists.",
134
152
  role: "Orchestrator",
135
153
  mode: "primary",
136
154
  instructions: [
155
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
137
156
  "You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
138
- "Define mission intent with explicit scope, constraints, and success criteria before any execution.",
157
+ "Workstream Fan-out: divide missions into independent Workstreams (e.g., Logic, Testing, Documentation) to enable parallel specialists.",
139
158
  "Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
140
- "Require a logbook entry that captures decisions, risks, and acceptance checks for every mission.",
159
+ "Collision Prevention: ensure no two Boatswains are assigned the same file or symbol in parallel. Launch workstreams only if they are logically decoupled.",
141
160
  "Escalate blockers immediately and re-sequence work to unblock the critical path.",
142
161
  "Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
143
162
  "Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
144
163
  "Delegation mandate: ALWAYS delegate work to specialists using the task tool. Never perform file edits, code changes, or direct execution yourself.",
145
164
  "Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
146
- "Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
147
165
  "Verification gate: delegate verification to Quartermaster; ensure diagnostics/tests run and evidence is logged before marking complete.",
166
+ "Conflict Resolution: if specialists disagree on implementation, make the final call based on project documentation.",
148
167
  "Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
149
168
  "Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
150
169
  ],
151
- tools: ["read", "logbook", "delegate"]
170
+ tools: ["read", "logbook", "delegate", "skill"]
152
171
  });
153
172
 
154
173
  // src/crew/Navigator.ts
155
174
  var Navigator = new OpCrewAgent({
156
175
  name: "Navigator",
176
+ description: "Planning specialist that decomposes work into atomic tasks with clear inputs, outputs, and ownership. Use when you need to chart an implementation path or create a structured plan.",
157
177
  role: "Planner",
158
178
  mode: "subagent",
159
179
  instructions: [
180
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, websearch, logbook, todo, skill. Using any other tool is a violation.",
160
181
  "Chart the implementation path based on the Captain's intent and constraints.",
161
182
  "Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
183
+ "Workstream Decomposition: break the plan into atomic, parallel tracks. Define File Ownership (e.g., Boatswain-A owns src/, Boatswain-B owns tests/).",
184
+ "Survey the Stack: identify the project's native build system (BUILD_CMD), test runner (TEST_CMD), and style guide immediately.",
185
+ "Documentation Maintenance: plan for updates to docs/project-map.md and docs/glossary.md; assign these to a specific workstream.",
186
+ "Dependency Graphing: flag Blocking Tasks where one workstream depends on the output of another; sequence these to avoid idle agents.",
187
+ "Execution Manifest: for every task, specify Target File, Affected Symbols, Invariants, and the exact Verification Command.",
162
188
  "Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
163
189
  "Maintain a current project map (key files, modules, and ownership boundaries).",
164
190
  "Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
165
191
  "Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
166
192
  "Create and manage todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
167
193
  "Mandate parallel discovery for unknowns: launch multiple explore/librarian threads and consolidate findings.",
194
+ "Discovery Primitives: use language-agnostic tools (grep, find, tree) to map dependencies before proposing edits.",
168
195
  "Delegate external research to Scout when you need information from outside the project: libraries, APIs, best practices, or documentation.",
169
196
  "Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
170
197
  "Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
171
198
  ],
172
- tools: ["read", "websearch", "logbook", "todo"]
199
+ tools: ["read", "websearch", "logbook", "todo", "skill"]
173
200
  });
174
201
 
175
202
  // src/crew/Boatswain.ts
176
203
  var Boatswain = new OpCrewAgent({
177
204
  name: "Boatswain",
205
+ description: "Execution specialist that implements approved plans with precise edits. Use when you need to make code changes, run tests, or execute implementation steps.",
178
206
  role: "Executor",
179
207
  mode: "subagent",
180
208
  instructions: [
181
- "Turn approved Navigator steps into precise edits without scope creep.",
209
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, edit, write, test, todo, glob, grep, skill. Using any other tool is a violation.",
210
+ "Scope Guarding: ONLY touch files assigned to your Workstream ID. If you must edit a file owned by another agent, escalate to Captain for a plan revision.",
182
211
  "Follow existing patterns, naming, and formatting; avoid speculative changes.",
212
+ "Context Anchoring: before editing, read the surrounding code to match indentation, casing, and comment styles. Maintain the project's local laws.",
213
+ "Parallel Execution: implement the Navigator's Manifest exactly. Update code, tests, and documentation (docs/project-map.md or docs/glossary.md) as assigned.",
183
214
  "Keep diffs lean and standards-compliant; update only what the plan calls for.",
184
- "Run required sanity tests and record results in the logbook.",
185
- "Log completion status, assumptions, and blockers immediately for the Captain.",
215
+ "Atomic Verification: run the assigned TEST_CMD for your scope. Record stdout/stderr logs in the logbook immediately.",
186
216
  "Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
187
- "Use verification gates: lsp diagnostics on touched files plus relevant tests/builds before completion.",
217
+ "LSP/Compiler Check: use native diagnostics to ensure no syntax errors were introduced in touched files.",
188
218
  "Update docs/knowledge when execution changes assumptions, definitions, or operational steps.",
189
- "Update todo task status immediately upon completion of each task."
219
+ "Update todo task status immediately upon completion of each task.",
220
+ "Status Discipline: update your specific task status in logbook.json as you work; do not wait for other workstreams to finish."
190
221
  ],
191
- tools: ["read", "edit", "test", "todo"]
222
+ tools: ["read", "edit", "write", "test", "todo", "glob", "grep", "skill"]
192
223
  });
193
224
 
194
225
  // src/crew/Quartermaster.ts
195
226
  var Quartermaster = new OpCrewAgent({
196
227
  name: "Quartermaster",
228
+ description: "Quality assurance specialist that reviews diffs, verifies tests pass, and ensures conventions are followed. Use proactively after code changes to verify quality.",
197
229
  role: "Reviewer",
198
230
  mode: "subagent",
199
231
  instructions: [
232
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, grep, execute, write, skill. Using any other tool is a violation.",
200
233
  "Inspect each diff for regression risks, scope drift, and missing context.",
201
- "Confirm tests, docs, and logbook entries prove the change is complete.",
202
- "Verify acceptance checks and ensure the plan-to-implementation trace is intact.",
234
+ "Integration Audit: once all parallel Boatswains report Complete, verify the combined diff for logic conflicts or signature mismatches.",
235
+ "Documentation Gate: REJECT approval if code changed but docs/project-map.md or docs/glossary.md were not updated to reflect the new state.",
236
+ "Evidence Verification: ensure every workstream provided terminal logs proving their respective tests or build commands passed.",
237
+ "Traceability: confirm the final implementation matches the Navigator's original Invariants.",
203
238
  "Escalate unresolved quality gaps to the Captain before approval.",
204
239
  "Require rework when verification is missing or conventions are violated.",
205
240
  "Reject approvals lacking evidence (diagnostics/tests/build logs) or missing todo/task tracking.",
241
+ "Regression Check: require a full project TEST_CMD run (if available) to ensure integrated workstreams didn't break the system.",
206
242
  "Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
207
243
  "Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
208
244
  ],
209
- tools: ["read", "grep", "execute", "write"]
245
+ tools: ["read", "grep", "execute", "write", "skill"]
210
246
  });
211
247
 
212
248
  // src/crew/Scout.ts
213
249
  var Scout = new OpCrewAgent({
214
250
  name: "Scout",
251
+ description: "Research specialist for external information gathering - web searches, documentation lookup, API references, and best practices. Use when you need information from outside the project.",
215
252
  role: "Researcher",
216
253
  mode: "subagent",
217
254
  instructions: [
255
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
218
256
  "You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
219
257
  "Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
220
258
  "Never modify project files - your job is to gather intelligence, not execute changes.",
221
259
  "Provide concise, actionable findings with clear sources and citations.",
260
+ "Rosetta Stone Summaries: when researching a new language, explain concepts via analogy - 'This is the [Go] equivalent of [Python's] Decorators.'",
222
261
  "When researching libraries or frameworks, include: version info, installation methods, key APIs, and gotchas.",
223
262
  "Compare alternatives when relevant: pros/cons, trade-offs, and recommendations with rationale.",
224
263
  "Flag deprecated or outdated information; always verify against official sources when possible.",
225
264
  "Summarize findings in a structured format: problem, findings, recommendations, sources.",
265
+ "Glossary Contribution: propose new terms or external definitions for the Boatswain to add to docs/glossary.md.",
226
266
  "If research reveals the task is more complex than expected, escalate to Navigator for replanning.",
227
- "Cache useful references in docs/knowledge for future crew reference."
267
+ "Environment Discovery: research specific error messages or build tool quirks if the Boatswain hits a blocker.",
268
+ "Knowledge Caching: store research summaries in docs/research/ for future crew reference."
228
269
  ],
229
- tools: ["websearch", "webfetch", "read"]
270
+ tools: ["websearch", "webfetch", "read", "skill"]
230
271
  });
231
272
 
232
273
  // src/crew/index.ts
@@ -12680,65 +12721,128 @@ The logbook tracks:
12680
12721
  });
12681
12722
 
12682
12723
  // src/opencode-plugin.ts
12724
+ var DEFAULT_CANONICAL_TOOLS = [
12725
+ "read",
12726
+ "write",
12727
+ "edit",
12728
+ "glob",
12729
+ "grep",
12730
+ "execute",
12731
+ "websearch",
12732
+ "webfetch",
12733
+ "delegate",
12734
+ "todo",
12735
+ "test",
12736
+ "logbook",
12737
+ "skill"
12738
+ ];
12739
+ var ALL_AVAILABLE_TOOLS = DEFAULT_CANONICAL_TOOLS;
12683
12740
  var permissionByRole = {
12684
12741
  Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
12685
12742
  Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
12686
12743
  Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
12687
- Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" },
12744
+ Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
12688
12745
  Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
12689
12746
  };
12690
12747
  function toAgentId(agent) {
12691
12748
  return agent.config.name.toLowerCase().replace(/\s+/g, "-");
12692
12749
  }
12693
- function buildPrompt(agent) {
12750
+ function buildPrompt(agent, availableTools) {
12694
12751
  const instructionsList = agent.config.instructions.map((instruction) => `- ${instruction}`).join(`
12695
12752
  `);
12753
+ const allowedTools = agent.getAllowedTools();
12754
+ const forbiddenTools = agent.getForbiddenTools(availableTools);
12755
+ const toolBoundariesSection = `## TOOL BOUNDARIES
12756
+ - **Allowed:** ${allowedTools.length > 0 ? allowedTools.join(", ") : "(none)"}
12757
+ - **Forbidden:** ${forbiddenTools.length > 0 ? forbiddenTools.join(", ") : "(none)"}`;
12696
12758
  return `# ${agent.config.name}
12759
+
12760
+ ${toolBoundariesSection}
12761
+
12697
12762
  ${instructionsList}
12698
12763
 
12699
12764
  ## Shared Context
12700
12765
  Refer to \`.opcrew/logbook.json\` for the current voyage status.
12701
12766
  `;
12702
12767
  }
12703
- function toOpenCodeAgentConfig(agent) {
12768
+ function toOpenCodeAgentConfig(agent, availableTools) {
12769
+ const allowedTools = agent.getAllowedTools();
12770
+ const validTools = allowedTools.every((tool3) => availableTools.includes(tool3));
12771
+ if (!validTools) {
12772
+ const invalidTools = allowedTools.filter((tool3) => !availableTools.includes(tool3));
12773
+ throw new Error(`Agent '${agent.config.name}' has invalid tools in allowlist: [${invalidTools.join(", ")}]. ` + `Valid tools: [${availableTools.join(", ")}]`);
12774
+ }
12704
12775
  return {
12705
12776
  description: agent.config.name,
12706
12777
  mode: agent.config.mode,
12707
- prompt: buildPrompt(agent),
12778
+ prompt: buildPrompt(agent, availableTools),
12708
12779
  permission: permissionByRole[agent.config.role]
12709
12780
  };
12710
12781
  }
12711
- var OpCrewPlugin = async ({ client }) => {
12712
- await client.app.log({
12713
- body: {
12714
- service: "opcrew",
12715
- level: "info",
12716
- message: "OpenCode plugin initialized"
12717
- }
12718
- });
12719
- return {
12720
- config: async (config2) => {
12721
- const agents = config2.agent ?? {};
12722
- for (const agent of crew) {
12723
- agents[toAgentId(agent)] = toOpenCodeAgentConfig(agent);
12724
- }
12725
- config2.agent = agents;
12726
- await client.app.log({
12727
- body: {
12728
- service: "opcrew",
12729
- level: "info",
12730
- message: "Crew agents registered",
12731
- extra: { agents: Object.keys(agents) }
12732
- }
12733
- });
12734
- },
12735
- tool: {
12736
- edit_logbook: editLogbookTool
12737
- }
12782
+ function createOpCrewPlugin(options = {}) {
12783
+ const {
12784
+ tools: customTools = {},
12785
+ skills,
12786
+ availableTools = DEFAULT_CANONICAL_TOOLS,
12787
+ includeDefaultTools = true,
12788
+ crew: customCrew = crew
12789
+ } = options;
12790
+ const defaultTools = includeDefaultTools ? { edit_logbook: editLogbookTool } : {};
12791
+ const mergedTools = {
12792
+ ...defaultTools,
12793
+ ...customTools
12794
+ };
12795
+ const _skills = skills;
12796
+ return async ({ client }) => {
12797
+ await client.app.log({
12798
+ body: {
12799
+ service: "opcrew",
12800
+ level: "info",
12801
+ message: "OpenCode plugin initialized"
12802
+ }
12803
+ });
12804
+ return {
12805
+ config: async (config2) => {
12806
+ const agents = config2.agent ?? {};
12807
+ agents["build"] = { ...agents["build"], disable: true };
12808
+ for (const agent of customCrew) {
12809
+ const agentId = toAgentId(agent);
12810
+ const allowedTools = agent.getAllowedTools();
12811
+ const forbiddenTools = agent.getForbiddenTools(availableTools);
12812
+ await client.app.log({
12813
+ body: {
12814
+ service: "opcrew",
12815
+ level: "info",
12816
+ message: `Registering agent '${agent.config.name}' with tool boundaries`,
12817
+ extra: {
12818
+ agentId,
12819
+ allowedTools,
12820
+ forbiddenTools
12821
+ }
12822
+ }
12823
+ });
12824
+ agents[agentId] = toOpenCodeAgentConfig(agent, availableTools);
12825
+ }
12826
+ config2.agent = agents;
12827
+ await client.app.log({
12828
+ body: {
12829
+ service: "opcrew",
12830
+ level: "info",
12831
+ message: "Crew agents registered",
12832
+ extra: { agents: Object.keys(agents) }
12833
+ }
12834
+ });
12835
+ },
12836
+ tool: mergedTools
12837
+ };
12738
12838
  };
12739
- };
12839
+ }
12840
+ var OpCrewPlugin = createOpCrewPlugin();
12740
12841
  var opencode_plugin_default = OpCrewPlugin;
12741
12842
  export {
12742
12843
  opencode_plugin_default as default,
12743
- OpCrewPlugin
12844
+ createOpCrewPlugin,
12845
+ OpCrewPlugin,
12846
+ DEFAULT_CANONICAL_TOOLS,
12847
+ ALL_AVAILABLE_TOOLS
12744
12848
  };
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: write-adr
3
+ description: Guides the crew to write Architecture Decision Records (ADRs). Use when making material decisions that should be documented, when asked to create an ADR, or when a decision with long-term impact is made.
4
+ ---
5
+
6
+ # Write ADR Skill
7
+
8
+ This skill guides the OpCrew to write well-structured Architecture Decision Records (ADRs) following the project's conventions.
9
+
10
+ ## When to Use This Skill
11
+
12
+ Use this skill when:
13
+ - Making a material decision that affects the project's architecture, conventions, or workflows
14
+ - A decision has long-term impact and should be preserved for future reference
15
+ - Explicitly asked to create or write an ADR
16
+ - Changing a previous architectural decision
17
+ - Introducing new patterns, tools, or approaches that others should follow
18
+
19
+ ## What is an ADR?
20
+
21
+ An Architecture Decision Record (ADR) captures a significant architectural decision along with its context and consequences. ADRs:
22
+
23
+ - Create a decision log that's reviewable in Git
24
+ - Help future team members understand *why* decisions were made
25
+ - Prevent "why did we do this?" questions months later
26
+ - Make decisions explicit and traceable
27
+
28
+ ## ADR Structure
29
+
30
+ OpCrew ADRs use four sections:
31
+
32
+ ### 1. Status
33
+ The current state of the decision:
34
+ - **Proposed** - Under discussion, not yet finalized
35
+ - **Accepted** - Approved and in effect
36
+ - **Deprecated** - Still in effect but should be avoided for new work
37
+ - **Superseded** - Replaced by a newer ADR (link to it)
38
+
39
+ ### 2. Context
40
+ What is the issue or situation motivating this decision?
41
+ - Describe the problem or opportunity
42
+ - Include relevant constraints and requirements
43
+ - Explain why a decision is needed now
44
+
45
+ ### 3. Decision
46
+ What is the change being made or proposed?
47
+ - State the decision clearly and concisely
48
+ - Be specific about what is being done
49
+ - Include any alternatives considered (briefly)
50
+
51
+ ### 4. Consequences
52
+ What becomes easier or more difficult because of this change?
53
+ - List positive outcomes
54
+ - Acknowledge trade-offs and limitations
55
+ - Note any follow-up actions required
56
+
57
+ ## Filename Convention
58
+
59
+ ADRs are stored in `docs/knowledge/decisions/` with this format:
60
+
61
+ ```
62
+ YYYYMMDD-NNN-slug.md
63
+ ```
64
+
65
+ - `YYYYMMDD` - Date the ADR is created
66
+ - `NNN` - Sequential number (001, 002, 003...)
67
+ - `slug` - Short kebab-case description
68
+
69
+ **Examples:**
70
+ - `20260328-001-knowledge-base-source-of-truth.md`
71
+ - `20260329-002-agent-configuration-standard.md`
72
+
73
+ ## Step-by-Step Workflow
74
+
75
+ 1. **Identify the decision** - Is this a material decision worth documenting?
76
+ 2. **Check existing ADRs** - Look in `docs/knowledge/decisions/` for related decisions
77
+ 3. **Determine the next sequence number** - Look at existing files and increment
78
+ 4. **Create the file** - Use the template and filename convention
79
+ 5. **Write the ADR** - Fill in all four sections with clear, concise content
80
+ 6. **Review** - Ensure the ADR captures the full context and rationale
81
+ 7. **Commit** - Include the ADR in your commit with related changes
82
+
83
+ ## Example ADR
84
+
85
+ ```markdown
86
+ # Knowledge Base Source of Truth
87
+
88
+ ## Status
89
+ Accepted
90
+
91
+ ## Context
92
+ We need a maintainable way to preserve project decisions, conventions, and operational guidance for agents and humans.
93
+
94
+ ## Decision
95
+ Use the filesystem as the canonical knowledge base in `docs/knowledge/`. Keep decisions as ADRs, project map and glossary as living docs, and runbooks for operational procedures.
96
+
97
+ ## Consequences
98
+ - Decisions become reviewable and diffable in Git.
99
+ - Agents must read/update these docs as part of workflow conventions.
100
+ - A database can be added later only as a derived index, not as the source of truth.
101
+ ```
102
+
103
+ ## Tips for Good ADRs
104
+
105
+ - **Be concise** - ADRs should be readable in 2-3 minutes
106
+ - **Focus on why** - The context and rationale matter more than the details
107
+ - **Write for the future** - Assume the reader doesn't have your current context
108
+ - **Include trade-offs** - Every decision has downsides; acknowledge them
109
+ - **Link related ADRs** - If this supersedes or relates to another ADR, mention it
110
+ - **Keep it current** - Update status if the decision changes
111
+
112
+ ## Template Location
113
+
114
+ Use the template at `templates/adr-template.md` as a starting point.
@@ -0,0 +1,13 @@
1
+ # [Title]
2
+
3
+ ## Status
4
+ [Proposed | Accepted | Deprecated | Superseded]
5
+
6
+ ## Context
7
+ [What is the issue that we're seeing that is motivating this decision or change?]
8
+
9
+ ## Decision
10
+ [What is the change that we're proposing and/or doing?]
11
+
12
+ ## Consequences
13
+ [What becomes easier or more difficult to do because of this change?]
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: write-adr
3
+ description: Guides the crew to write Architecture Decision Records (ADRs). Use when making material decisions that should be documented, when asked to create an ADR, or when a decision with long-term impact is made.
4
+ ---
5
+
6
+ # Write ADR Skill
7
+
8
+ This skill guides the OpCrew to write well-structured Architecture Decision Records (ADRs) following the project's conventions.
9
+
10
+ ## When to Use This Skill
11
+
12
+ Use this skill when:
13
+ - Making a material decision that affects the project's architecture, conventions, or workflows
14
+ - A decision has long-term impact and should be preserved for future reference
15
+ - Explicitly asked to create or write an ADR
16
+ - Changing a previous architectural decision
17
+ - Introducing new patterns, tools, or approaches that others should follow
18
+
19
+ ## What is an ADR?
20
+
21
+ An Architecture Decision Record (ADR) captures a significant architectural decision along with its context and consequences. ADRs:
22
+
23
+ - Create a decision log that's reviewable in Git
24
+ - Help future team members understand *why* decisions were made
25
+ - Prevent "why did we do this?" questions months later
26
+ - Make decisions explicit and traceable
27
+
28
+ ## ADR Structure
29
+
30
+ OpCrew ADRs use four sections:
31
+
32
+ ### 1. Status
33
+ The current state of the decision:
34
+ - **Proposed** - Under discussion, not yet finalized
35
+ - **Accepted** - Approved and in effect
36
+ - **Deprecated** - Still in effect but should be avoided for new work
37
+ - **Superseded** - Replaced by a newer ADR (link to it)
38
+
39
+ ### 2. Context
40
+ What is the issue or situation motivating this decision?
41
+ - Describe the problem or opportunity
42
+ - Include relevant constraints and requirements
43
+ - Explain why a decision is needed now
44
+
45
+ ### 3. Decision
46
+ What is the change being made or proposed?
47
+ - State the decision clearly and concisely
48
+ - Be specific about what is being done
49
+ - Include any alternatives considered (briefly)
50
+
51
+ ### 4. Consequences
52
+ What becomes easier or more difficult because of this change?
53
+ - List positive outcomes
54
+ - Acknowledge trade-offs and limitations
55
+ - Note any follow-up actions required
56
+
57
+ ## Filename Convention
58
+
59
+ ADRs are stored in `docs/knowledge/decisions/` with this format:
60
+
61
+ ```
62
+ YYYYMMDD-NNN-slug.md
63
+ ```
64
+
65
+ - `YYYYMMDD` - Date the ADR is created
66
+ - `NNN` - Sequential number (001, 002, 003...)
67
+ - `slug` - Short kebab-case description
68
+
69
+ **Examples:**
70
+ - `20260328-001-knowledge-base-source-of-truth.md`
71
+ - `20260329-002-agent-configuration-standard.md`
72
+
73
+ ## Step-by-Step Workflow
74
+
75
+ 1. **Identify the decision** - Is this a material decision worth documenting?
76
+ 2. **Check existing ADRs** - Look in `docs/knowledge/decisions/` for related decisions
77
+ 3. **Determine the next sequence number** - Look at existing files and increment
78
+ 4. **Create the file** - Use the template and filename convention
79
+ 5. **Write the ADR** - Fill in all four sections with clear, concise content
80
+ 6. **Review** - Ensure the ADR captures the full context and rationale
81
+ 7. **Commit** - Include the ADR in your commit with related changes
82
+
83
+ ## Example ADR
84
+
85
+ ```markdown
86
+ # Knowledge Base Source of Truth
87
+
88
+ ## Status
89
+ Accepted
90
+
91
+ ## Context
92
+ We need a maintainable way to preserve project decisions, conventions, and operational guidance for agents and humans.
93
+
94
+ ## Decision
95
+ Use the filesystem as the canonical knowledge base in `docs/knowledge/`. Keep decisions as ADRs, project map and glossary as living docs, and runbooks for operational procedures.
96
+
97
+ ## Consequences
98
+ - Decisions become reviewable and diffable in Git.
99
+ - Agents must read/update these docs as part of workflow conventions.
100
+ - A database can be added later only as a derived index, not as the source of truth.
101
+ ```
102
+
103
+ ## Tips for Good ADRs
104
+
105
+ - **Be concise** - ADRs should be readable in 2-3 minutes
106
+ - **Focus on why** - The context and rationale matter more than the details
107
+ - **Write for the future** - Assume the reader doesn't have your current context
108
+ - **Include trade-offs** - Every decision has downsides; acknowledge them
109
+ - **Link related ADRs** - If this supersedes or relates to another ADR, mention it
110
+ - **Keep it current** - Update status if the decision changes
111
+
112
+ ## Template Location
113
+
114
+ Use the template at `templates/adr-template.md` as a starting point.
@@ -0,0 +1,13 @@
1
+ # [Title]
2
+
3
+ ## Status
4
+ [Proposed | Accepted | Deprecated | Superseded]
5
+
6
+ ## Context
7
+ [What is the issue that we're seeing that is motivating this decision or change?]
8
+
9
+ ## Decision
10
+ [What is the change that we're proposing and/or doing?]
11
+
12
+ ## Consequences
13
+ [What becomes easier or more difficult to do because of this change?]
@@ -0,0 +1,51 @@
1
+ # Strict Agent Tool Boundaries
2
+
3
+ ## Status
4
+ Accepted
5
+
6
+ ## Context
7
+ OpenCrew agents currently have tool assignments defined declaratively in their configuration, but these assignments are NOT technically enforced. The existing permission system only covers three operations (edit, bash, webfetch) at the platform level, while tool assignments like `read`, `write`, `delegate`, `logbook`, etc. are purely instructional.
8
+
9
+ This creates several problems:
10
+ 1. **Role confusion**: Captain could theoretically use tools meant for Boatswain (like `edit`)
11
+ 2. **Accountability gaps**: No verification that agents stay within their designated scope
12
+ 3. **Debugging difficulty**: When something goes wrong, it's unclear which agent overstepped
13
+ 4. **Security risk**: An agent could access tools it shouldn't have access to
14
+
15
+ The principle "Captain never writes code - that's Boatswain's job" is currently enforced only through instructions, not technical barriers.
16
+
17
+ ## Decision
18
+ Implement strict technical enforcement of agent tool boundaries through:
19
+
20
+ 1. **Tool Allowlist per Agent**: Each agent definition will include an explicit `allowedTools` array that is validated at runtime
21
+ 2. **Plugin-Level Enforcement**: The OpenCode plugin will filter available tools based on the agent's allowlist before registration
22
+ 3. **Instruction Injection**: Agent instructions will be auto-generated with explicit "ALLOWED TOOLS" and "FORBIDDEN TOOLS" sections
23
+ 4. **Runtime Validation**: A guard function will validate tool usage before each invocation
24
+
25
+ Agent tool boundaries:
26
+ - **Captain (Orchestrator)**: read, logbook, delegate, skill
27
+ - **Navigator (Planner)**: read, websearch, logbook, todo, skill
28
+ - **Boatswain (Executor)**: read, edit, write, test, todo, glob, grep, skill
29
+ - **Quartermaster (Reviewer)**: read, grep, execute, write, skill
30
+ - **Scout (Researcher)**: websearch, webfetch, read, skill
31
+
32
+ ## Consequences
33
+
34
+ **Benefits:**
35
+ - Clear separation of concerns - each agent has a defined operational scope
36
+ - Easier debugging - tool usage violations are caught immediately
37
+ - Better security - no accidental or intentional tool misuse
38
+ - Self-documenting - agent capabilities are explicit in code
39
+ - Improved trust - users can rely on agents staying in their lane
40
+
41
+ **Trade-offs:**
42
+ - More rigid system - changing tool access requires code changes
43
+ - Potential friction - if an agent legitimately needs a new tool, must update config
44
+ - Implementation overhead - validation logic adds complexity
45
+
46
+ **Follow-up Actions:**
47
+ - Update Agent.ts with tool enforcement methods
48
+ - Add allowedTools array to each agent definition
49
+ - Create guard functions in src/core/guards.ts
50
+ - Update opencode-plugin.ts to filter tools at registration
51
+ - Write tests for boundary enforcement
@@ -0,0 +1,83 @@
1
+ # Plugin Factory Pattern for Configuration
2
+
3
+ ## Status
4
+ Accepted
5
+
6
+ ## Context
7
+ The OpenCrew plugin (`src/opencode-plugin.ts`) previously hardcoded all configuration:
8
+ - Tools (`edit_logbook`) were imported and registered directly
9
+ - `ALL_AVAILABLE_TOOLS` was defined inline
10
+ - The crew of agents was imported from a fixed location
11
+ - Skills were not configurable through the plugin
12
+
13
+ This made it difficult to:
14
+ 1. Add custom tools without modifying the plugin source
15
+ 2. Extend the available tools list for custom tool types
16
+ 3. Use a custom crew configuration
17
+ 4. Configure the plugin for different deployment scenarios
18
+
19
+ The `Plugin` type from `@opencode-ai/plugin` is a function signature `(input: PluginInput) => Promise<Hooks>`, which doesn't accept custom configuration parameters directly.
20
+
21
+ ## Decision
22
+ Implement a **Factory Pattern** for the OpCrew plugin:
23
+
24
+ 1. **`OpCrewPluginOptions` interface** - Configuration object with:
25
+ - `tools?: Record<string, ToolDefinition>` - Custom tools to register
26
+ - `skills?: SkillConfig[]` - Skills to make available
27
+ - `availableTools?: CanonicalTool[]` - Canonical tools for boundary enforcement
28
+ - `includeDefaultTools?: boolean` - Whether to include default tools (default: true)
29
+ - `crew?: OpCrewAgent[]` - Custom crew of agents
30
+
31
+ 2. **`createOpCrewPlugin(options)` factory function** - Creates a configured Plugin instance
32
+
33
+ 3. **`DEFAULT_CANONICAL_TOOLS` export** - The default list for extension
34
+
35
+ 4. **Backwards compatibility** - Default export `OpCrewPlugin` uses default options
36
+
37
+ ### Usage Examples
38
+
39
+ **Default (backwards compatible):**
40
+ ```typescript
41
+ import { OpCrewPlugin } from 'opcrew';
42
+ export default OpCrewPlugin;
43
+ ```
44
+
45
+ **With custom tools:**
46
+ ```typescript
47
+ import { createOpCrewPlugin } from 'opcrew';
48
+ import { myTool } from './my-tool';
49
+
50
+ export default createOpCrewPlugin({
51
+ tools: { my_tool: myTool },
52
+ });
53
+ ```
54
+
55
+ **Full customization:**
56
+ ```typescript
57
+ import { createOpCrewPlugin, DEFAULT_CANONICAL_TOOLS } from 'opcrew';
58
+
59
+ export default createOpCrewPlugin({
60
+ tools: { custom_tool: myTool },
61
+ availableTools: [...DEFAULT_CANONICAL_TOOLS, 'custom_tool'],
62
+ includeDefaultTools: false,
63
+ crew: [customAgent],
64
+ });
65
+ ```
66
+
67
+ ## Consequences
68
+
69
+ **Benefits:**
70
+ - Extensibility: Users can add custom tools without forking
71
+ - Flexibility: Different configurations for different environments
72
+ - Testability: Easier to test with mock configurations
73
+ - Backwards compatible: Existing usage continues to work
74
+
75
+ **Trade-offs:**
76
+ - Slightly more complex API surface
77
+ - Need to document configuration options
78
+ - Type definitions must be exported for consumers
79
+
80
+ **Follow-up:**
81
+ - Document the configuration API in README
82
+ - Consider adding validation for configuration options
83
+ - Update package.json exports if needed
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opcrew",
3
3
  "description": "OpenCrew agents and OpenCode plugin",
4
- "version": "0.1.3",
4
+ "version": "0.1.5",
5
5
  "main": "./dist/opencode-plugin.js",
6
6
  "module": "./dist/opencode-plugin.js",
7
7
  "type": "module",
@@ -29,9 +29,10 @@
29
29
  "opcrew": "./dist/cli.js"
30
30
  },
31
31
  "scripts": {
32
- "build": "bun run build:plugin && bun run build:cli",
32
+ "build": "bun run build:plugin && bun run build:cli && bun run build:skills",
33
33
  "build:plugin": "bun build src/opencode-plugin.ts --outdir dist --target bun",
34
34
  "build:cli": "bun build src/cli/index.ts --outfile dist/cli.js --target bun",
35
+ "build:skills": "cp -r src/skills dist/skills",
35
36
  "prepack": "bun run build",
36
37
  "test": "bun test",
37
38
  "build:types": "bunx tsc -p tsconfig.build.json"