opcrew 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # Opcrew
2
+
3
+ Opcrew provides a crew of structured agents and an OpenCode plugin that registers them automatically.
4
+
5
+ ## Setup
6
+
7
+ Install dependencies:
8
+
9
+ ```bash
10
+ bun install
11
+ ```
12
+
13
+ Run the CLI locally:
14
+
15
+ ```bash
16
+ bun run src/cli/index.ts install --opencode
17
+ ```
18
+
19
+ ## OpenCode Plugin
20
+
21
+ This project ships an OpenCode plugin that registers the crew agents via `config.agent`.
22
+
23
+ ### Build
24
+
25
+ ```bash
26
+ bun run build
27
+ bun run build:types
28
+ ```
29
+
30
+ ### Install as plugin
31
+
32
+ Publish the package and add it to your OpenCode config:
33
+
34
+ ```json
35
+ {
36
+ "plugin": ["opcrew@0.1.0"]
37
+ }
38
+ ```
39
+
40
+ The plugin entrypoint is `src/opencode-plugin.ts` and the published bundle is `dist/opencode-plugin.js`.
41
+
42
+ ## Knowledge Base
43
+
44
+ Project context lives under `docs/knowledge/`:
45
+
46
+ - `decisions/` for ADRs
47
+ - `runbooks/` for operational procedures
48
+ - `project-map.md` for module map
49
+ - `glossary.md` for definitions
@@ -0,0 +1,14 @@
1
+ export interface AgentConfig {
2
+ name: string;
3
+ role: 'Orchestrator' | 'Planner' | 'Executor' | 'Reviewer';
4
+ mode: 'primary' | 'subagent';
5
+ instructions: string[];
6
+ tools: string[];
7
+ }
8
+ export declare class OpCrewAgent {
9
+ readonly config: AgentConfig;
10
+ constructor(config: AgentConfig);
11
+ compileToMarkdown(): string;
12
+ compileToOpenCodeMarkdown(): string;
13
+ private buildMarkdownBody;
14
+ }
@@ -0,0 +1,2 @@
1
+ import { OpCrewAgent } from "../core/Agent";
2
+ export declare const Boatswain: OpCrewAgent;
@@ -0,0 +1,2 @@
1
+ import { OpCrewAgent } from "../core/Agent";
2
+ export declare const Captain: OpCrewAgent;
@@ -0,0 +1,2 @@
1
+ import { OpCrewAgent } from "../core/Agent";
2
+ export declare const Navigator: OpCrewAgent;
@@ -0,0 +1,2 @@
1
+ import { OpCrewAgent } from "../core/Agent";
2
+ export declare const Quartermaster: OpCrewAgent;
@@ -0,0 +1,6 @@
1
+ import { Captain } from "./Captain";
2
+ import { Navigator } from "./Navigator";
3
+ import { Boatswain } from "./Boatswain";
4
+ import { Quartermaster } from "./Quartermaster";
5
+ export declare const crew: readonly [import("../core/Agent").OpCrewAgent, import("../core/Agent").OpCrewAgent, import("../core/Agent").OpCrewAgent, import("../core/Agent").OpCrewAgent];
6
+ export { Captain, Navigator, Boatswain, Quartermaster };
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from "@opencode-ai/plugin";
2
+ export declare const OpCrewPlugin: Plugin;
3
+ export default OpCrewPlugin;
@@ -0,0 +1,193 @@
1
+ // @bun
2
+ // src/core/Agent.ts
3
+ class OpCrewAgent {
4
+ config;
5
+ constructor(config) {
6
+ this.config = config;
7
+ }
8
+ compileToMarkdown() {
9
+ const frontmatter = `---
10
+ name: ${this.config.name}
11
+ role: ${this.config.role}
12
+ tools: [${this.config.tools.join(", ")}]
13
+ ---`;
14
+ return `${frontmatter}
15
+ ${this.buildMarkdownBody()}`;
16
+ }
17
+ compileToOpenCodeMarkdown() {
18
+ const permissionByRole = {
19
+ Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
20
+ Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
21
+ Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
22
+ Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" }
23
+ };
24
+ const permission = permissionByRole[this.config.role];
25
+ const frontmatter = `---
26
+ description: ${this.config.name}
27
+ mode: ${this.config.mode}
28
+ permission:
29
+ edit: ${permission.edit}
30
+ bash: ${permission.bash}
31
+ webfetch: ${permission.webfetch}
32
+ ---`;
33
+ return `${frontmatter}
34
+ ${this.buildMarkdownBody()}`;
35
+ }
36
+ buildMarkdownBody() {
37
+ const instructionsList = this.config.instructions.map((instruction) => `- ${instruction}`).join(`
38
+ `);
39
+ return `
40
+ # ${this.config.name}
41
+ ${instructionsList}
42
+
43
+ ## Shared Context
44
+ Refer to \`.opcrew/logbook.json\` for the current voyage status.
45
+ `;
46
+ }
47
+ }
48
+
49
+ // src/crew/Captain.ts
50
+ var Captain = new OpCrewAgent({
51
+ name: "Captain",
52
+ role: "Orchestrator",
53
+ mode: "primary",
54
+ instructions: [
55
+ "Define mission intent with explicit scope, constraints, and success criteria before any execution.",
56
+ "Assign roles in order: Navigator plans, Boatswain executes, Quartermaster reviews; resolve conflicts quickly.",
57
+ "Require a logbook entry that captures decisions, risks, and acceptance checks for every mission.",
58
+ "Escalate blockers immediately and re-sequence work to unblock the critical path.",
59
+ "Enforce conventions: small, reviewable diffs; no scope creep; verification required before declaring done.",
60
+ "Intent gate: restate user intent, classify task type (trivial/explicit/exploratory/open-ended/ambiguous), and choose the workflow before action.",
61
+ "Delegation bias: default to delegation when specialists are available; only solo if trivial and single-step.",
62
+ "Delegation protocol: require task/outcome/tools/must-do/must-not/context in every order; reject vague asks.",
63
+ "Parallel exploration: launch explore/librarian tasks concurrently for non-trivial discovery, and avoid duplicate searches.",
64
+ "Verification gate: ensure diagnostics/tests run and evidence is logged before marking complete.",
65
+ "Knowledge discipline: require crew to read/update docs/knowledge (project map, glossary, relevant ADRs) for any decision or scope change.",
66
+ "Ensure every material decision is captured as an ADR in docs/knowledge/decisions."
67
+ ],
68
+ tools: ["read_fs", "write_logbook", "dispatch_orders"]
69
+ });
70
+
71
+ // src/crew/Navigator.ts
72
+ var Navigator = new OpCrewAgent({
73
+ name: "Navigator",
74
+ role: "Planner",
75
+ mode: "subagent",
76
+ instructions: [
77
+ "Chart the implementation path based on the Captain's intent and constraints.",
78
+ "Decompose work into atomic, ordered tasks with clear inputs, outputs, and ownership.",
79
+ "Record the plan in the logbook with file targets, dependencies, and acceptance checks.",
80
+ "Maintain a current project map (key files, modules, and ownership boundaries).",
81
+ "Flag ambiguity early, propose alternatives, and surface risks before execution starts.",
82
+ "Apply the intent gate: classify the request and select the correct workflow (explore vs. implement vs. clarify).",
83
+ "Create todo/task lists for any multi-step plan; enforce one in-progress item at a time.",
84
+ "Mandate parallel discovery for unknowns: launch multiple explore/librarian threads and consolidate findings.",
85
+ "Define verification steps explicitly (diagnostics/tests/build) and include success evidence in the plan.",
86
+ "Consult docs/knowledge before planning; update project-map/glossary/ADRs when scope or definitions change."
87
+ ],
88
+ tools: ["read_fs", "web_search", "edit_logbook"]
89
+ });
90
+
91
+ // src/crew/Boatswain.ts
92
+ var Boatswain = new OpCrewAgent({
93
+ name: "Boatswain",
94
+ role: "Executor",
95
+ mode: "subagent",
96
+ instructions: [
97
+ "Turn approved Navigator steps into precise edits without scope creep.",
98
+ "Follow existing patterns, naming, and formatting; avoid speculative changes.",
99
+ "Keep diffs lean and standards-compliant; update only what the plan calls for.",
100
+ "Run required sanity tests and record results in the logbook.",
101
+ "Log completion status, assumptions, and blockers immediately for the Captain.",
102
+ "Do not re-run delegated exploration; wait for Navigator findings before implementing dependent changes.",
103
+ "Use verification gates: lsp diagnostics on touched files plus relevant tests/builds before completion.",
104
+ "Update docs/knowledge when execution changes assumptions, definitions, or operational steps."
105
+ ],
106
+ tools: ["read_fs", "edit_code", "run_tests"]
107
+ });
108
+
109
+ // src/crew/Quartermaster.ts
110
+ var Quartermaster = new OpCrewAgent({
111
+ name: "Quartermaster",
112
+ role: "Reviewer",
113
+ mode: "subagent",
114
+ instructions: [
115
+ "Inspect each diff for regression risks, scope drift, and missing context.",
116
+ "Confirm tests, docs, and logbook entries prove the change is complete.",
117
+ "Verify acceptance checks and ensure the plan-to-implementation trace is intact.",
118
+ "Escalate unresolved quality gaps to the Captain before approval.",
119
+ "Require rework when verification is missing or conventions are violated.",
120
+ "Reject approvals lacking evidence (diagnostics/tests/build logs) or missing todo/task tracking.",
121
+ "Verify delegation protocol compliance when specialists were involved (task/outcome/tools/must-do/must-not/context).",
122
+ "Reject approval if docs/knowledge changes are missing for material decisions or scope shifts."
123
+ ],
124
+ tools: ["read_fs", "review_diffs", "check_tests"]
125
+ });
126
+
127
+ // src/crew/index.ts
128
+ var crew = [
129
+ Captain,
130
+ Navigator,
131
+ Boatswain,
132
+ Quartermaster
133
+ ];
134
+
135
+ // src/opencode-plugin.ts
136
+ var permissionByRole = {
137
+ Orchestrator: { edit: "deny", bash: "ask", webfetch: "deny" },
138
+ Planner: { edit: "deny", bash: "ask", webfetch: "allow" },
139
+ Executor: { edit: "allow", bash: "allow", webfetch: "ask" },
140
+ Reviewer: { edit: "deny", bash: "ask", webfetch: "deny" }
141
+ };
142
+ function toAgentId(agent) {
143
+ return agent.config.name.toLowerCase().replace(/\s+/g, "-");
144
+ }
145
+ function buildPrompt(agent) {
146
+ const instructionsList = agent.config.instructions.map((instruction) => `- ${instruction}`).join(`
147
+ `);
148
+ return `# ${agent.config.name}
149
+ ${instructionsList}
150
+
151
+ ## Shared Context
152
+ Refer to \`.opcrew/logbook.json\` for the current voyage status.
153
+ `;
154
+ }
155
+ function toOpenCodeAgentConfig(agent) {
156
+ return {
157
+ description: agent.config.name,
158
+ mode: agent.config.mode,
159
+ prompt: buildPrompt(agent),
160
+ permission: permissionByRole[agent.config.role]
161
+ };
162
+ }
163
+ var OpCrewPlugin = async ({ client }) => {
164
+ await client.app.log({
165
+ body: {
166
+ service: "opcrew",
167
+ level: "info",
168
+ message: "OpenCode plugin initialized"
169
+ }
170
+ });
171
+ return {
172
+ config: async (config) => {
173
+ const agents = config.agent ?? {};
174
+ for (const agent of crew) {
175
+ agents[toAgentId(agent)] = toOpenCodeAgentConfig(agent);
176
+ }
177
+ config.agent = agents;
178
+ await client.app.log({
179
+ body: {
180
+ service: "opcrew",
181
+ level: "info",
182
+ message: "Crew agents registered",
183
+ extra: { agents: Object.keys(agents) }
184
+ }
185
+ });
186
+ }
187
+ };
188
+ };
189
+ var opencode_plugin_default = OpCrewPlugin;
190
+ export {
191
+ opencode_plugin_default as default,
192
+ OpCrewPlugin
193
+ };
@@ -0,0 +1,67 @@
1
+ # Knowledge Base Conventions
2
+
3
+ This folder is the **canonical, human-readable source of truth** for project context. Agents must read relevant files before acting and update them when decisions or constraints change.
4
+
5
+ ## Structure
6
+
7
+ - `decisions/` — Architecture Decision Records (ADRs)
8
+ - `runbooks/` — Operational procedures and recurring workflows
9
+ - `glossary.md` — Terms, abbreviations, and canonical definitions
10
+ - `project-map.md` — High-level module map, ownership boundaries, and key entry points
11
+
12
+ ## Rules of Engagement
13
+
14
+ 1. **Read first:** Check `project-map.md`, `glossary.md`, and any related ADRs before planning or execution.
15
+ 2. **Write when you decide:** Any non-trivial decision that changes direction, constraints, or approach must be captured as an ADR.
16
+ 3. **Keep it small and explicit:** Prefer concise entries with clear rationale and consequences.
17
+ 4. **No hidden knowledge:** If it matters for future work, it belongs here.
18
+ 5. **Git is the source of truth:** Do not store canonical decisions in databases; this folder is the canonical record.
19
+
20
+ ## ADR Template
21
+
22
+ Create a new file in `decisions/` using the next sequence number:
23
+
24
+ ```text
25
+ YYYYMMDD-###-short-title.md
26
+ ```
27
+
28
+ Include the following sections:
29
+
30
+ ```markdown
31
+ # Title
32
+
33
+ ## Status
34
+ Accepted | Superseded | Deprecated
35
+
36
+ ## Context
37
+ What problem are we solving? What constraints apply?
38
+
39
+ ## Decision
40
+ What did we decide?
41
+
42
+ ## Consequences
43
+ What tradeoffs or follow-up work does this create?
44
+ ```
45
+
46
+ ## Runbook Template
47
+
48
+ Create a new file in `runbooks/` using:
49
+
50
+ ```text
51
+ topic-short-title.md
52
+ ```
53
+
54
+ ```markdown
55
+ # Title
56
+
57
+ ## Purpose
58
+
59
+ ## Preconditions
60
+
61
+ ## Steps
62
+ 1.
63
+
64
+ ## Verification
65
+
66
+ ## Rollback
67
+ ```
@@ -0,0 +1,15 @@
1
+ # Knowledge Base Source of Truth
2
+
3
+ ## Status
4
+ Accepted
5
+
6
+ ## Context
7
+ We need a maintainable way to preserve project decisions, conventions, and operational guidance for agents and humans.
8
+
9
+ ## Decision
10
+ 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.
11
+
12
+ ## Consequences
13
+ - Decisions become reviewable and diffable in Git.
14
+ - Agents must read/update these docs as part of workflow conventions.
15
+ - A database can be added later only as a derived index, not as the source of truth.
@@ -0,0 +1,10 @@
1
+ # Glossary
2
+
3
+ ## ADR (Architecture Decision Record)
4
+ A short, structured document that records a significant architectural or process decision, its context, and its consequences.
5
+
6
+ ## Logbook
7
+ The mission log that captures decisions, risks, task status, and verification evidence for each mission.
8
+
9
+ ## Mission
10
+ A unit of work defined by the Captain, typically decomposed into tasks by the Navigator and executed by the Boatswain.
@@ -0,0 +1,18 @@
1
+ # Project Map
2
+
3
+ ## Purpose
4
+ High-level map of key modules, entry points, and ownership boundaries. Keep this updated when new modules are added or responsibilities shift.
5
+
6
+ ## Modules
7
+
8
+ - `src/crew/` — Crew agent definitions and instruction sets.
9
+ - `src/core/` — Core agent framework, orchestration primitives, and shared utilities.
10
+
11
+ ## Entry Points
12
+
13
+ - `index.ts` — Application entry point.
14
+
15
+ ## Conventions
16
+
17
+ - Follow crew instruction conventions in `src/crew/` for workflow discipline.
18
+ - Keep diffs small and verification evidence attached to changes.
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "opcrew",
3
+ "description": "OpenCrew agents and OpenCode plugin",
4
+ "version": "0.1.0",
5
+ "main": "./dist/opencode-plugin.js",
6
+ "module": "./dist/opencode-plugin.js",
7
+ "type": "module",
8
+ "private": false,
9
+ "license": "UNLICENSED",
10
+ "keywords": [
11
+ "opencode",
12
+ "plugin",
13
+ "agents",
14
+ "crew"
15
+ ],
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "docs/knowledge"
20
+ ],
21
+ "exports": {
22
+ ".": {
23
+ "import": "./dist/opencode-plugin.js",
24
+ "types": "./dist/opencode-plugin.d.ts"
25
+ }
26
+ },
27
+ "types": "./dist/opencode-plugin.d.ts",
28
+ "bin": {
29
+ "opcrew": "src/cli/index.ts"
30
+ },
31
+ "scripts": {
32
+ "test": "bun test",
33
+ "build": "bun build src/opencode-plugin.ts --outdir dist --target bun",
34
+ "build:types": "bunx tsc -p tsconfig.build.json"
35
+ },
36
+ "devDependencies": {
37
+ "@types/bun": "latest",
38
+ "typescript": "^5",
39
+ "undici-types": "^6.11.1"
40
+ },
41
+ "dependencies": {
42
+ "@opencode-ai/plugin": "latest"
43
+ }
44
+ }
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import process from "node:process";
4
+
5
+ import { installToTool } from "./install";
6
+
7
+ const usage = `Usage:
8
+ bunx opcrew install [--claude] [--opencode] [--codex]
9
+
10
+ At least one flag is required.
11
+ `;
12
+
13
+ const FLAG_TO_TOOL = {
14
+ "--claude": "claude",
15
+ "--opencode": "opencode",
16
+ "--codex": "codex",
17
+ } as const;
18
+
19
+ type SupportedFlag = keyof typeof FLAG_TO_TOOL;
20
+
21
+ function showUsage(message?: string): never {
22
+ if (message) {
23
+ console.error(message);
24
+ }
25
+ console.error(usage.trimEnd());
26
+ process.exit(1);
27
+ }
28
+
29
+ async function main() {
30
+ const [subcommand, ...flags] = process.argv.slice(2);
31
+
32
+ if (subcommand !== "install") {
33
+ showUsage("Missing or invalid subcommand. Use 'install'.");
34
+ }
35
+
36
+ if (flags.length === 0) {
37
+ showUsage("No install target provided.");
38
+ }
39
+
40
+ const selectedTools: string[] = [];
41
+ const seen = new Set<string>();
42
+
43
+ for (const flag of flags) {
44
+ const tool = FLAG_TO_TOOL[flag as SupportedFlag];
45
+
46
+ if (!tool) {
47
+ showUsage(`Unknown flag: ${flag}`);
48
+ }
49
+
50
+ if (seen.has(tool)) {
51
+ continue;
52
+ }
53
+
54
+ seen.add(tool);
55
+ selectedTools.push(tool);
56
+ }
57
+
58
+ if (selectedTools.length === 0) {
59
+ showUsage("No valid flags provided.");
60
+ }
61
+
62
+ for (const tool of selectedTools) {
63
+ await installToTool(tool as "claude" | "opencode" | "codex");
64
+ }
65
+ }
66
+
67
+ await main().catch((error) => {
68
+ console.error("Installation failed:", error);
69
+ process.exit(1);
70
+ });