opcrew 0.1.4 → 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,8 +5,8 @@
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
12
  read: "Read",
@@ -20,7 +20,7 @@ var CLAUDE_TOOLS = {
20
20
  delegate: "Agent",
21
21
  todo: "TodoWrite",
22
22
  test: "Bash",
23
- logbook: "Edit",
23
+ logbook: "",
24
24
  skill: "Skill"
25
25
  };
26
26
  var OPENCODE_TOOLS = {
@@ -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,8 +69,24 @@ 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");
74
90
  const lowerName = this.config.name.toLowerCase();
75
91
  const frontmatter = `---
76
92
  name: ${lowerName}
@@ -85,7 +101,7 @@ ${this.buildMarkdownBody()}`;
85
101
  Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
86
102
  Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
87
103
  Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
88
- Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" },
104
+ Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
89
105
  Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
90
106
  };
91
107
  const permission = permissionByRole[this.config.role];
@@ -101,7 +117,7 @@ permission:
101
117
  ${this.buildMarkdownBody()}`;
102
118
  }
103
119
  compileToCodexMarkdown() {
104
- const translatedTools = translateTools(this.config.tools, "codex");
120
+ const translatedTools = translateTools(this.getAllowedTools(), "codex");
105
121
  const frontmatter = `---
106
122
  name: ${this.config.name}
107
123
  role: ${this.config.role}
@@ -130,21 +146,22 @@ var Captain = new OpCrewAgent({
130
146
  role: "Orchestrator",
131
147
  mode: "primary",
132
148
  instructions: [
149
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
133
150
  "You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
134
- "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.",
135
152
  "Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
136
- "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.",
137
154
  "Escalate blockers immediately and re-sequence work to unblock the critical path.",
138
155
  "Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
139
156
  "Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
140
157
  "Delegation mandate: ALWAYS delegate work to specialists using the task tool. Never perform file edits, code changes, or direct execution yourself.",
141
158
  "Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
142
- "Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
143
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.",
144
161
  "Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
145
162
  "Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
146
163
  ],
147
- tools: ["read", "logbook", "delegate"]
164
+ tools: ["read", "logbook", "delegate", "skill"]
148
165
  });
149
166
 
150
167
  // src/crew/Navigator.ts
@@ -154,19 +171,26 @@ var Navigator = new OpCrewAgent({
154
171
  role: "Planner",
155
172
  mode: "subagent",
156
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.",
157
175
  "Chart the implementation path based on the Captain's intent and constraints.",
158
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.",
159
182
  "Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
160
183
  "Maintain a current project map (key files, modules, and ownership boundaries).",
161
184
  "Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
162
185
  "Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
163
186
  "Create and manage todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
164
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.",
165
189
  "Delegate external research to Scout when you need information from outside the project: libraries, APIs, best practices, or documentation.",
166
190
  "Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
167
191
  "Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
168
192
  ],
169
- tools: ["read", "websearch", "logbook", "todo"]
193
+ tools: ["read", "websearch", "logbook", "todo", "skill"]
170
194
  });
171
195
 
172
196
  // src/crew/Boatswain.ts
@@ -176,17 +200,20 @@ var Boatswain = new OpCrewAgent({
176
200
  role: "Executor",
177
201
  mode: "subagent",
178
202
  instructions: [
179
- "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.",
180
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.",
181
208
  "Keep diffs lean and standards-compliant; update only what the plan calls for.",
182
- "Run required sanity tests and record results in the logbook.",
183
- "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.",
184
210
  "Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
185
- "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.",
186
212
  "Update docs/knowledge when execution changes assumptions, definitions, or operational steps.",
187
- "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."
188
215
  ],
189
- tools: ["read", "edit", "test", "todo"]
216
+ tools: ["read", "edit", "write", "test", "todo", "glob", "grep", "skill"]
190
217
  });
191
218
 
192
219
  // src/crew/Quartermaster.ts
@@ -196,16 +223,20 @@ var Quartermaster = new OpCrewAgent({
196
223
  role: "Reviewer",
197
224
  mode: "subagent",
198
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.",
199
227
  "Inspect each diff for regression risks, scope drift, and missing context.",
200
- "Confirm tests, docs, and logbook entries prove the change is complete.",
201
- "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.",
202
232
  "Escalate unresolved quality gaps to the Captain before approval.",
203
233
  "Require rework when verification is missing or conventions are violated.",
204
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.",
205
236
  "Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
206
237
  "Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
207
238
  ],
208
- tools: ["read", "grep", "execute", "write"]
239
+ tools: ["read", "grep", "execute", "write", "skill"]
209
240
  });
210
241
 
211
242
  // src/crew/Scout.ts
@@ -215,18 +246,22 @@ var Scout = new OpCrewAgent({
215
246
  role: "Researcher",
216
247
  mode: "subagent",
217
248
  instructions: [
249
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
218
250
  "You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
219
251
  "Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
220
252
  "Never modify project files - your job is to gather intelligence, not execute changes.",
221
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.'",
222
255
  "When researching libraries or frameworks, include: version info, installation methods, key APIs, and gotchas.",
223
256
  "Compare alternatives when relevant: pros/cons, trade-offs, and recommendations with rationale.",
224
257
  "Flag deprecated or outdated information; always verify against official sources when possible.",
225
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.",
226
260
  "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."
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."
228
263
  ],
229
- tools: ["websearch", "webfetch", "read"]
264
+ tools: ["websearch", "webfetch", "read", "skill"]
230
265
  });
231
266
 
232
267
  // src/crew/index.ts
@@ -238,10 +273,66 @@ var crew = [
238
273
  Scout
239
274
  ];
240
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
+
241
330
  // src/cli/install.ts
242
- var CLAUDE_DIR = path.join(".claude", "agents");
243
- var OPENCODE_DIR = path.join(".opencode", "agents");
244
- 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");
245
336
  async function ensureDir(targetDir) {
246
337
  await mkdir(targetDir, { recursive: true });
247
338
  }
@@ -250,26 +341,67 @@ async function installToTool(tool) {
250
341
  await installForCodex();
251
342
  return;
252
343
  }
253
- const targetDir = tool === "claude" ? CLAUDE_DIR : OPENCODE_DIR;
254
- 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);
255
347
  for (const agent of crew) {
256
348
  const filename = `${agent.config.name.toLowerCase()}.md`;
257
- const filePath = path.join(targetDir, filename);
349
+ const filePath = path2.join(agentsDir, filename);
258
350
  const content = tool === "opencode" ? agent.compileToOpenCodeMarkdown() : agent.compileToMarkdown();
259
351
  await writeFile(filePath, content);
260
- 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}`);
261
368
  }
262
369
  }
263
370
  async function installForCodex() {
264
- const codexDir = path.dirname(CODEX_FILE);
371
+ const codexDir = path2.dirname(CODEX_FILE);
265
372
  await ensureDir(codexDir);
266
- const compiled = crew.map((agent) => agent.compileToCodexMarkdown()).join(`
373
+ const agentsContent = crew.map((agent) => agent.compileToCodexMarkdown()).join(`
374
+
375
+ ---
376
+
377
+ `);
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(`
267
394
 
268
395
  ---
269
396
 
270
397
  `);
271
- await writeFile(CODEX_FILE, compiled);
398
+ }
399
+ const fullContent = agentsContent + skillsContent;
400
+ await writeFile(CODEX_FILE, fullContent);
272
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
+ }
273
405
  }
274
406
 
275
407
  // src/cli/index.ts
@@ -26,7 +26,7 @@ var CLAUDE_TOOLS = {
26
26
  delegate: "Agent",
27
27
  todo: "TodoWrite",
28
28
  test: "Bash",
29
- logbook: "Edit",
29
+ logbook: "",
30
30
  skill: "Skill"
31
31
  };
32
32
  var OPENCODE_TOOLS = {
@@ -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,8 +75,24 @@ 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");
80
96
  const lowerName = this.config.name.toLowerCase();
81
97
  const frontmatter = `---
82
98
  name: ${lowerName}
@@ -91,7 +107,7 @@ ${this.buildMarkdownBody()}`;
91
107
  Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
92
108
  Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
93
109
  Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
94
- Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" },
110
+ Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
95
111
  Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
96
112
  };
97
113
  const permission = permissionByRole[this.config.role];
@@ -107,7 +123,7 @@ permission:
107
123
  ${this.buildMarkdownBody()}`;
108
124
  }
109
125
  compileToCodexMarkdown() {
110
- const translatedTools = translateTools(this.config.tools, "codex");
126
+ const translatedTools = translateTools(this.getAllowedTools(), "codex");
111
127
  const frontmatter = `---
112
128
  name: ${this.config.name}
113
129
  role: ${this.config.role}
@@ -136,21 +152,22 @@ var Captain = new OpCrewAgent({
136
152
  role: "Orchestrator",
137
153
  mode: "primary",
138
154
  instructions: [
155
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: read, logbook, delegate, skill. Using any other tool is a violation.",
139
156
  "You are the orchestrator - you NEVER execute work directly. Your role is to coordinate, delegate, and verify.",
140
- "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.",
141
158
  "Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
142
- "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.",
143
160
  "Escalate blockers immediately and re-sequence work to unblock the critical path.",
144
161
  "Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
145
162
  "Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
146
163
  "Delegation mandate: ALWAYS delegate work to specialists using the task tool. Never perform file edits, code changes, or direct execution yourself.",
147
164
  "Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
148
- "Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
149
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.",
150
167
  "Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
151
168
  "Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
152
169
  ],
153
- tools: ["read", "logbook", "delegate"]
170
+ tools: ["read", "logbook", "delegate", "skill"]
154
171
  });
155
172
 
156
173
  // src/crew/Navigator.ts
@@ -160,19 +177,26 @@ var Navigator = new OpCrewAgent({
160
177
  role: "Planner",
161
178
  mode: "subagent",
162
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.",
163
181
  "Chart the implementation path based on the Captain's intent and constraints.",
164
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.",
165
188
  "Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
166
189
  "Maintain a current project map (key files, modules, and ownership boundaries).",
167
190
  "Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
168
191
  "Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
169
192
  "Create and manage todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
170
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.",
171
195
  "Delegate external research to Scout when you need information from outside the project: libraries, APIs, best practices, or documentation.",
172
196
  "Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
173
197
  "Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
174
198
  ],
175
- tools: ["read", "websearch", "logbook", "todo"]
199
+ tools: ["read", "websearch", "logbook", "todo", "skill"]
176
200
  });
177
201
 
178
202
  // src/crew/Boatswain.ts
@@ -182,17 +206,20 @@ var Boatswain = new OpCrewAgent({
182
206
  role: "Executor",
183
207
  mode: "subagent",
184
208
  instructions: [
185
- "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.",
186
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.",
187
214
  "Keep diffs lean and standards-compliant; update only what the plan calls for.",
188
- "Run required sanity tests and record results in the logbook.",
189
- "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.",
190
216
  "Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
191
- "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.",
192
218
  "Update docs/knowledge when execution changes assumptions, definitions, or operational steps.",
193
- "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."
194
221
  ],
195
- tools: ["read", "edit", "test", "todo"]
222
+ tools: ["read", "edit", "write", "test", "todo", "glob", "grep", "skill"]
196
223
  });
197
224
 
198
225
  // src/crew/Quartermaster.ts
@@ -202,16 +229,20 @@ var Quartermaster = new OpCrewAgent({
202
229
  role: "Reviewer",
203
230
  mode: "subagent",
204
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.",
205
233
  "Inspect each diff for regression risks, scope drift, and missing context.",
206
- "Confirm tests, docs, and logbook entries prove the change is complete.",
207
- "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.",
208
238
  "Escalate unresolved quality gaps to the Captain before approval.",
209
239
  "Require rework when verification is missing or conventions are violated.",
210
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.",
211
242
  "Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
212
243
  "Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
213
244
  ],
214
- tools: ["read", "grep", "execute", "write"]
245
+ tools: ["read", "grep", "execute", "write", "skill"]
215
246
  });
216
247
 
217
248
  // src/crew/Scout.ts
@@ -221,18 +252,22 @@ var Scout = new OpCrewAgent({
221
252
  role: "Researcher",
222
253
  mode: "subagent",
223
254
  instructions: [
255
+ "TOOL BOUNDARY: You are ONLY permitted to use these tools: websearch, webfetch, read, skill. Using any other tool is a violation.",
224
256
  "You are the crew's eyes to the outside world - research and gather information when summoned by Captain or Navigator.",
225
257
  "Focus exclusively on external research: web searches, documentation lookup, API references, and best practices.",
226
258
  "Never modify project files - your job is to gather intelligence, not execute changes.",
227
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.'",
228
261
  "When researching libraries or frameworks, include: version info, installation methods, key APIs, and gotchas.",
229
262
  "Compare alternatives when relevant: pros/cons, trade-offs, and recommendations with rationale.",
230
263
  "Flag deprecated or outdated information; always verify against official sources when possible.",
231
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.",
232
266
  "If research reveals the task is more complex than expected, escalate to Navigator for replanning.",
233
- "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."
234
269
  ],
235
- tools: ["websearch", "webfetch", "read"]
270
+ tools: ["websearch", "webfetch", "read", "skill"]
236
271
  });
237
272
 
238
273
  // src/crew/index.ts
@@ -12686,65 +12721,128 @@ The logbook tracks:
12686
12721
  });
12687
12722
 
12688
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;
12689
12740
  var permissionByRole = {
12690
12741
  Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
12691
12742
  Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
12692
12743
  Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
12693
- Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" },
12744
+ Reviewer: { edit: "deny", bash: "allow", webfetch: "deny" },
12694
12745
  Researcher: { edit: "deny", bash: "deny", webfetch: "allow" }
12695
12746
  };
12696
12747
  function toAgentId(agent) {
12697
12748
  return agent.config.name.toLowerCase().replace(/\s+/g, "-");
12698
12749
  }
12699
- function buildPrompt(agent) {
12750
+ function buildPrompt(agent, availableTools) {
12700
12751
  const instructionsList = agent.config.instructions.map((instruction) => `- ${instruction}`).join(`
12701
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)"}`;
12702
12758
  return `# ${agent.config.name}
12759
+
12760
+ ${toolBoundariesSection}
12761
+
12703
12762
  ${instructionsList}
12704
12763
 
12705
12764
  ## Shared Context
12706
12765
  Refer to \`.opcrew/logbook.json\` for the current voyage status.
12707
12766
  `;
12708
12767
  }
12709
- 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
+ }
12710
12775
  return {
12711
12776
  description: agent.config.name,
12712
12777
  mode: agent.config.mode,
12713
- prompt: buildPrompt(agent),
12778
+ prompt: buildPrompt(agent, availableTools),
12714
12779
  permission: permissionByRole[agent.config.role]
12715
12780
  };
12716
12781
  }
12717
- var OpCrewPlugin = async ({ client }) => {
12718
- await client.app.log({
12719
- body: {
12720
- service: "opcrew",
12721
- level: "info",
12722
- message: "OpenCode plugin initialized"
12723
- }
12724
- });
12725
- return {
12726
- config: async (config2) => {
12727
- const agents = config2.agent ?? {};
12728
- for (const agent of crew) {
12729
- agents[toAgentId(agent)] = toOpenCodeAgentConfig(agent);
12730
- }
12731
- config2.agent = agents;
12732
- await client.app.log({
12733
- body: {
12734
- service: "opcrew",
12735
- level: "info",
12736
- message: "Crew agents registered",
12737
- extra: { agents: Object.keys(agents) }
12738
- }
12739
- });
12740
- },
12741
- tool: {
12742
- edit_logbook: editLogbookTool
12743
- }
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
+ };
12744
12838
  };
12745
- };
12839
+ }
12840
+ var OpCrewPlugin = createOpCrewPlugin();
12746
12841
  var opencode_plugin_default = OpCrewPlugin;
12747
12842
  export {
12748
12843
  opencode_plugin_default as default,
12749
- OpCrewPlugin
12844
+ createOpCrewPlugin,
12845
+ OpCrewPlugin,
12846
+ DEFAULT_CANONICAL_TOOLS,
12847
+ ALL_AVAILABLE_TOOLS
12750
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.4",
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"