@wpro-eng/opencode-config 1.6.0 → 1.7.1
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 +39 -12
- package/agent/{gandalf.md → orchestrator.md} +6 -6
- package/command/diagnostics.md +3 -3
- package/dist/index.js +59 -12
- package/package.json +1 -1
- /package/agent/{galadriel.md → analyst.md} +0 -0
- /package/agent/{elrond.md → architect.md} +0 -0
- /package/agent/{samwise.md → deepwork.md} +0 -0
- /package/agent/{legolas.md → explorer.md} +0 -0
- /package/agent/{celebrimbor.md → implementer.md} +0 -0
- /package/agent/{treebeard.md → planner.md} +0 -0
- /package/agent/{radagast.md → researcher.md} +0 -0
- /package/agent/{aragorn.md → tdd.md} +0 -0
package/README.md
CHANGED
|
@@ -62,9 +62,36 @@ Create `~/.config/opencode/wpromote.json` or `~/.config/opencode/wpromote.jsonc`
|
|
|
62
62
|
|--------|------|---------|-------------|
|
|
63
63
|
| `disable` | `string[]` | `[]` | Assets to disable (see below) |
|
|
64
64
|
| `installMethod` | `"link"` \| `"copy"` | `"link"` | How to install skills/plugins/MCPs |
|
|
65
|
+
| `agentNames` | `"lotr"` \| `"descriptive"` | `"descriptive"` | Agent naming theme (see below) |
|
|
65
66
|
| `dryRun` | `boolean` | `false` | Preview changes without installing |
|
|
66
67
|
| `orchestration` | `object` | defaults | Runtime orchestration controls, limits, and fallback policy |
|
|
67
68
|
|
|
69
|
+
### Agent Name Themes
|
|
70
|
+
|
|
71
|
+
Agents can be displayed with either plain role-based names or Tolkien character names. Set `agentNames` in your config:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"agentNames": "lotr"
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Role | `"descriptive"` (default) | `"lotr"` |
|
|
80
|
+
|------|--------------------------|----------|
|
|
81
|
+
| Orchestrator | `orchestrator` | `gandalf` |
|
|
82
|
+
| Explorer | `explorer` | `legolas` |
|
|
83
|
+
| Researcher | `researcher` | `radagast` |
|
|
84
|
+
| Planner | `planner` | `treebeard` |
|
|
85
|
+
| Implementer | `implementer` | `celebrimbor` |
|
|
86
|
+
| Architect | `architect` | `elrond` |
|
|
87
|
+
| Analyst | `analyst` | `galadriel` |
|
|
88
|
+
| TDD | `tdd` | `aragorn` |
|
|
89
|
+
| Deep Work | `deepwork` | `samwise` |
|
|
90
|
+
|
|
91
|
+
The theme affects agent names everywhere: in the agent list, slash commands, delegation routing, and cross-references between agents. Agent markdown files use template variables (e.g. `{{explorer}}`) so cross-references resolve correctly regardless of theme.
|
|
92
|
+
|
|
93
|
+
When using the disable list, use the **themed name** (the name that appears after applying your chosen theme). For example, with `"descriptive"` theme, disable with `"agent:orchestrator"` instead of `"agent:gandalf"`.
|
|
94
|
+
|
|
68
95
|
### Orchestration Runtime Configuration
|
|
69
96
|
|
|
70
97
|
All fields below show their **defaults**. You only need to include fields you want to override.
|
|
@@ -251,26 +278,26 @@ EOF
|
|
|
251
278
|
|
|
252
279
|
### Agents (`agent/`)
|
|
253
280
|
|
|
254
|
-
Pre-configured agent definitions with model, temperature, and system prompts. There are two **primary** agents (you talk to them directly) and seven **subagents** (they run in the background, delegated by the primary agent).
|
|
281
|
+
Pre-configured agent definitions with model, temperature, and system prompts. There are two **primary** agents (you talk to them directly) and seven **subagents** (they run in the background, delegated by the primary agent). Names shown below use the default `"descriptive"` theme, with `"lotr"` names in parentheses.
|
|
255
282
|
|
|
256
283
|
#### Primary Agents
|
|
257
284
|
|
|
258
285
|
| Agent | Model | What it does |
|
|
259
286
|
|-------|-------|--------------|
|
|
260
|
-
| `gandalf` | Claude Opus 4 | The default orchestrator. Classifies your request, breaks it into tasks, delegates to the right subagents in parallel, and assembles the final result. Handles everything from quick fixes to multi-step projects. |
|
|
261
|
-
| `samwise` | Claude Opus 4 | A higher-rigor variant
|
|
287
|
+
| `orchestrator` (`gandalf`) | Claude Opus 4 | The default orchestrator. Classifies your request, breaks it into tasks, delegates to the right subagents in parallel, and assembles the final result. Handles everything from quick fixes to multi-step projects. |
|
|
288
|
+
| `deepwork` (`samwise`) | Claude Opus 4 | A higher-rigor variant for long-running complex work. Runs a sustained execution loop with tighter milestone verification, aggressive parallelism, and continuous health monitoring. Use when a task needs hours of autonomous work without hand-holding. |
|
|
262
289
|
|
|
263
290
|
#### Subagents
|
|
264
291
|
|
|
265
|
-
| Agent | Model | When
|
|
266
|
-
|
|
267
|
-
| `legolas` | Claude Sonnet 4.6 | "Where is X in the codebase?" | Searches the repo fast. Uses LSP, grep, glob, and git to find files, symbols, call paths, and code patterns. Returns structured results with absolute paths and a direct answer, not just a file list. Read-only by default. |
|
|
268
|
-
| `radagast` | GPT-5.2 | "How does library X work?" | Researches external docs, OSS repos, and the web. Classifies the question (conceptual, implementation, history, or comprehensive), fetches official sources, and returns evidence-backed recommendations with links. |
|
|
269
|
-
| `treebeard` | GPT-5.2 | "Is this plan solid?" | Reviews plans for ambiguity, risk, and executability before implementation starts. Surfaces hidden assumptions, produces concrete acceptance criteria, and gives a clear OKAY or REJECT verdict with at most 3 blocking issues. |
|
|
270
|
-
| `celebrimbor` | GPT-5.2 Codex | "Build this end-to-end." | The workhorse implementation agent. Operates like a senior staff engineer: explores context, plans edits, executes changes, runs tests, and iterates until done. Does not stop at partial progress or ask permission for normal engineering work. |
|
|
271
|
-
| `elrond` | GPT-5.2 | "What's the right architecture?" | Read-only strategic advisor. Analyzes codebases, evaluates tradeoffs, and returns a bottom-line recommendation with an action plan and effort estimate. Biases toward simplicity and existing patterns over speculative complexity. |
|
|
272
|
-
| `galadriel` | Gemini 3.1 Pro | "What's in this image/PDF?" | Multimodal analysis specialist. Handles PDFs, images, diagrams, and charts that other agents cannot process as plain text. Extracts targeted information and returns concise findings with confidence notes. |
|
|
273
|
-
| `aragorn` | GPT-5.2 Codex | "Write tests for this." | Strict TDD specialist following Red-Green-Refactor. Writes a failing test first, makes it pass with minimal code, then refactors under green. Produces a test plan, TDD log, execution results, and a quality scorecard. Never writes production code without a failing test. |
|
|
292
|
+
| Agent | Model | When called | What it does |
|
|
293
|
+
|-------|-------|-------------|--------------|
|
|
294
|
+
| `explorer` (`legolas`) | Claude Sonnet 4.6 | "Where is X in the codebase?" | Searches the repo fast. Uses LSP, grep, glob, and git to find files, symbols, call paths, and code patterns. Returns structured results with absolute paths and a direct answer, not just a file list. Read-only by default. |
|
|
295
|
+
| `researcher` (`radagast`) | GPT-5.2 | "How does library X work?" | Researches external docs, OSS repos, and the web. Classifies the question (conceptual, implementation, history, or comprehensive), fetches official sources, and returns evidence-backed recommendations with links. |
|
|
296
|
+
| `planner` (`treebeard`) | GPT-5.2 | "Is this plan solid?" | Reviews plans for ambiguity, risk, and executability before implementation starts. Surfaces hidden assumptions, produces concrete acceptance criteria, and gives a clear OKAY or REJECT verdict with at most 3 blocking issues. |
|
|
297
|
+
| `implementer` (`celebrimbor`) | GPT-5.2 Codex | "Build this end-to-end." | The workhorse implementation agent. Operates like a senior staff engineer: explores context, plans edits, executes changes, runs tests, and iterates until done. Does not stop at partial progress or ask permission for normal engineering work. |
|
|
298
|
+
| `architect` (`elrond`) | GPT-5.2 | "What's the right architecture?" | Read-only strategic advisor. Analyzes codebases, evaluates tradeoffs, and returns a bottom-line recommendation with an action plan and effort estimate. Biases toward simplicity and existing patterns over speculative complexity. |
|
|
299
|
+
| `analyst` (`galadriel`) | Gemini 3.1 Pro | "What's in this image/PDF?" | Multimodal analysis specialist. Handles PDFs, images, diagrams, and charts that other agents cannot process as plain text. Extracts targeted information and returns concise findings with confidence notes. |
|
|
300
|
+
| `tdd` (`aragorn`) | GPT-5.2 Codex | "Write tests for this." | Strict TDD specialist following Red-Green-Refactor. Writes a failing test first, makes it pass with minimal code, then refactors under green. Produces a test plan, TDD log, execution results, and a quality scorecard. Never writes production code without a failing test. |
|
|
274
301
|
|
|
275
302
|
### Commands (`command/`)
|
|
276
303
|
|
|
@@ -25,12 +25,12 @@ Orchestration workflow:
|
|
|
25
25
|
|
|
26
26
|
Delegation routing:
|
|
27
27
|
|
|
28
|
-
- `
|
|
29
|
-
- `
|
|
30
|
-
- `
|
|
31
|
-
- `
|
|
32
|
-
- `
|
|
33
|
-
- `
|
|
28
|
+
- `{{explorer}}` for internal codebase discovery.
|
|
29
|
+
- `{{researcher}}` for external docs and OSS references.
|
|
30
|
+
- `{{planner}}` for pre-planning analysis and plan review.
|
|
31
|
+
- `{{implementer}}` for end-to-end implementation execution.
|
|
32
|
+
- `{{architect}}` for architecture/security/performance tradeoff consultation.
|
|
33
|
+
- `{{analyst}}` for image/PDF/diagram interpretation.
|
|
34
34
|
|
|
35
35
|
Delegation prompt quality:
|
|
36
36
|
|
package/command/diagnostics.md
CHANGED
|
@@ -17,15 +17,15 @@ Instructions:
|
|
|
17
17
|
|
|
18
18
|
4. Spawn 4 subagent probes in parallel using the `task` tool. Each probe must be a trivial, fast, read-only task that proves the delegation pipeline works end-to-end. Do NOT run destructive or write operations.
|
|
19
19
|
|
|
20
|
-
**Probe A —
|
|
20
|
+
**Probe A — {{explorer}} (codebase exploration)**:
|
|
21
21
|
- Task: "List the top-level directories and count of files in this repo. Return the directory listing."
|
|
22
22
|
- Expected: completes with a directory listing.
|
|
23
23
|
|
|
24
|
-
**Probe B —
|
|
24
|
+
**Probe B — {{researcher}} (external research)**:
|
|
25
25
|
- Task: "What license does the tmux terminal multiplexer use? Search the web and return the license name (e.g. MIT, BSD, ISC, GPL)."
|
|
26
26
|
- Expected: completes with a license name (ISC).
|
|
27
27
|
|
|
28
|
-
**Probe C —
|
|
28
|
+
**Probe C — {{planner}} (planning)**:
|
|
29
29
|
- Task: "Review this single-sentence plan and identify one risk: 'We will migrate all configs to YAML next sprint.' Return your risk assessment in 2-3 sentences."
|
|
30
30
|
- Expected: completes with a short risk assessment.
|
|
31
31
|
|
package/dist/index.js
CHANGED
|
@@ -8346,6 +8346,7 @@ function logWarn(message) {
|
|
|
8346
8346
|
var UserConfigSchema = exports_external.object({
|
|
8347
8347
|
disable: exports_external.array(exports_external.string()).default([]),
|
|
8348
8348
|
installMethod: exports_external.enum(["link", "copy"]).default("link"),
|
|
8349
|
+
agentNames: exports_external.enum(["lotr", "descriptive"]).default("descriptive"),
|
|
8349
8350
|
dryRun: exports_external.boolean().default(false),
|
|
8350
8351
|
orchestration: exports_external.object({
|
|
8351
8352
|
providerMode: exports_external.enum(["copilot", "native"]).default("copilot"),
|
|
@@ -8396,6 +8397,7 @@ var UserConfigSchema = exports_external.object({
|
|
|
8396
8397
|
var DEFAULT_CONFIG = {
|
|
8397
8398
|
disable: [],
|
|
8398
8399
|
installMethod: "link",
|
|
8400
|
+
agentNames: "descriptive",
|
|
8399
8401
|
dryRun: false,
|
|
8400
8402
|
orchestration: {
|
|
8401
8403
|
providerMode: "copilot",
|
|
@@ -8610,16 +8612,50 @@ function discoverInstructions(repoPath) {
|
|
|
8610
8612
|
return instructions;
|
|
8611
8613
|
}
|
|
8612
8614
|
|
|
8615
|
+
// src/agent-names.ts
|
|
8616
|
+
var AGENT_NAME_TABLE = [
|
|
8617
|
+
{ canonical: "orchestrator", role: "orchestrator", themed: { lotr: "gandalf", descriptive: "orchestrator" } },
|
|
8618
|
+
{ canonical: "explorer", role: "explorer", themed: { lotr: "legolas", descriptive: "explorer" } },
|
|
8619
|
+
{ canonical: "researcher", role: "researcher", themed: { lotr: "radagast", descriptive: "researcher" } },
|
|
8620
|
+
{ canonical: "planner", role: "planner", themed: { lotr: "treebeard", descriptive: "planner" } },
|
|
8621
|
+
{ canonical: "implementer", role: "implementer", themed: { lotr: "celebrimbor", descriptive: "implementer" } },
|
|
8622
|
+
{ canonical: "architect", role: "architect", themed: { lotr: "elrond", descriptive: "architect" } },
|
|
8623
|
+
{ canonical: "analyst", role: "analyst", themed: { lotr: "galadriel", descriptive: "analyst" } },
|
|
8624
|
+
{ canonical: "tdd", role: "tdd", themed: { lotr: "aragorn", descriptive: "tdd" } },
|
|
8625
|
+
{ canonical: "deepwork", role: "deepwork", themed: { lotr: "samwise", descriptive: "deepwork" } }
|
|
8626
|
+
];
|
|
8627
|
+
var BY_CANONICAL = new Map(AGENT_NAME_TABLE.map((e) => [e.canonical, e]));
|
|
8628
|
+
function resolveAgentName(canonical, theme) {
|
|
8629
|
+
const entry = BY_CANONICAL.get(canonical);
|
|
8630
|
+
if (!entry)
|
|
8631
|
+
return canonical;
|
|
8632
|
+
return entry.themed[theme];
|
|
8633
|
+
}
|
|
8634
|
+
function buildTemplateVars(theme) {
|
|
8635
|
+
const vars = {};
|
|
8636
|
+
for (const entry of AGENT_NAME_TABLE) {
|
|
8637
|
+
vars[entry.role] = entry.themed[theme];
|
|
8638
|
+
}
|
|
8639
|
+
return vars;
|
|
8640
|
+
}
|
|
8641
|
+
function resolveTemplateVars(text, vars) {
|
|
8642
|
+
return text.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
8643
|
+
if (key in vars)
|
|
8644
|
+
return vars[key];
|
|
8645
|
+
return match;
|
|
8646
|
+
});
|
|
8647
|
+
}
|
|
8648
|
+
|
|
8613
8649
|
// src/assets.ts
|
|
8614
8650
|
var DISCOVERY_LIMITS = {
|
|
8615
8651
|
maxFiles: 100,
|
|
8616
8652
|
maxFileSize: 256 * 1024,
|
|
8617
8653
|
maxDepth: 10
|
|
8618
8654
|
};
|
|
8619
|
-
async function discoverAssets(packageRoot) {
|
|
8655
|
+
async function discoverAssets(packageRoot, theme = "descriptive") {
|
|
8620
8656
|
const skills = await discoverSkills(packageRoot);
|
|
8621
|
-
const agents = await discoverAgents(packageRoot);
|
|
8622
|
-
const commands = await discoverCommands(packageRoot);
|
|
8657
|
+
const agents = await discoverAgents(packageRoot, theme);
|
|
8658
|
+
const commands = await discoverCommands(packageRoot, theme);
|
|
8623
8659
|
const plugins = await discoverPlugins(packageRoot, REPO_SHORT_NAME);
|
|
8624
8660
|
const instructions = discoverInstructions(packageRoot);
|
|
8625
8661
|
const mcps = await discoverMcps(packageRoot);
|
|
@@ -8668,13 +8704,14 @@ async function discoverSkills(repoPath) {
|
|
|
8668
8704
|
findSkills(skillDir, 0);
|
|
8669
8705
|
return skills;
|
|
8670
8706
|
}
|
|
8671
|
-
async function discoverAgents(repoPath) {
|
|
8707
|
+
async function discoverAgents(repoPath, theme = "descriptive") {
|
|
8672
8708
|
const agents = [];
|
|
8673
8709
|
let filesProcessed = 0;
|
|
8674
8710
|
let warned = false;
|
|
8675
8711
|
const agentDir = path.join(repoPath, "agent");
|
|
8676
8712
|
if (!fs.existsSync(agentDir))
|
|
8677
8713
|
return agents;
|
|
8714
|
+
const templateVars = buildTemplateVars(theme);
|
|
8678
8715
|
const walk = (dir, depth) => {
|
|
8679
8716
|
if (depth > DISCOVERY_LIMITS.maxDepth) {
|
|
8680
8717
|
if (!warned) {
|
|
@@ -8708,7 +8745,7 @@ async function discoverAgents(repoPath) {
|
|
|
8708
8745
|
}
|
|
8709
8746
|
filesProcessed++;
|
|
8710
8747
|
const content = fs.readFileSync(fullPath, "utf-8");
|
|
8711
|
-
const parsed = parseAgentMarkdown(fullPath, content, agentDir);
|
|
8748
|
+
const parsed = parseAgentMarkdown(fullPath, content, agentDir, theme, templateVars);
|
|
8712
8749
|
if (parsed)
|
|
8713
8750
|
agents.push(parsed);
|
|
8714
8751
|
} catch (err) {
|
|
@@ -8720,7 +8757,7 @@ async function discoverAgents(repoPath) {
|
|
|
8720
8757
|
walk(agentDir, 0);
|
|
8721
8758
|
return agents;
|
|
8722
8759
|
}
|
|
8723
|
-
function parseAgentMarkdown(filePath, content, agentDir) {
|
|
8760
|
+
function parseAgentMarkdown(filePath, content, agentDir, theme, templateVars) {
|
|
8724
8761
|
let md;
|
|
8725
8762
|
try {
|
|
8726
8763
|
const yamlEngine = require_engines().yaml;
|
|
@@ -8754,15 +8791,21 @@ function parseAgentMarkdown(filePath, content, agentDir) {
|
|
|
8754
8791
|
logError(`Invalid agent config in ${filePath}: ${JSON.stringify(result.error.format())}`);
|
|
8755
8792
|
return null;
|
|
8756
8793
|
}
|
|
8757
|
-
|
|
8794
|
+
const themedName = resolveAgentName(agentName, theme);
|
|
8795
|
+
const resolvedConfig = { ...result.data };
|
|
8796
|
+
if (resolvedConfig.prompt) {
|
|
8797
|
+
resolvedConfig.prompt = resolveTemplateVars(resolvedConfig.prompt, templateVars);
|
|
8798
|
+
}
|
|
8799
|
+
return { name: themedName, path: filePath, config: resolvedConfig };
|
|
8758
8800
|
}
|
|
8759
|
-
async function discoverCommands(repoPath) {
|
|
8801
|
+
async function discoverCommands(repoPath, theme = "descriptive") {
|
|
8760
8802
|
const commands = [];
|
|
8761
8803
|
let filesProcessed = 0;
|
|
8762
8804
|
let warned = false;
|
|
8763
8805
|
const commandDir = path.join(repoPath, "command");
|
|
8764
8806
|
if (!fs.existsSync(commandDir))
|
|
8765
8807
|
return commands;
|
|
8808
|
+
const templateVars = buildTemplateVars(theme);
|
|
8766
8809
|
const walk = (dir, depth) => {
|
|
8767
8810
|
if (depth > DISCOVERY_LIMITS.maxDepth) {
|
|
8768
8811
|
if (!warned) {
|
|
@@ -8796,7 +8839,7 @@ async function discoverCommands(repoPath) {
|
|
|
8796
8839
|
}
|
|
8797
8840
|
filesProcessed++;
|
|
8798
8841
|
const content = fs.readFileSync(fullPath, "utf-8");
|
|
8799
|
-
const parsed = parseCommandMarkdown(fullPath, content, commandDir);
|
|
8842
|
+
const parsed = parseCommandMarkdown(fullPath, content, commandDir, templateVars);
|
|
8800
8843
|
if (parsed)
|
|
8801
8844
|
commands.push(parsed);
|
|
8802
8845
|
} catch (err) {
|
|
@@ -8808,7 +8851,7 @@ async function discoverCommands(repoPath) {
|
|
|
8808
8851
|
walk(commandDir, 0);
|
|
8809
8852
|
return commands;
|
|
8810
8853
|
}
|
|
8811
|
-
function parseCommandMarkdown(filePath, content, commandDir) {
|
|
8854
|
+
function parseCommandMarkdown(filePath, content, commandDir, templateVars) {
|
|
8812
8855
|
let md;
|
|
8813
8856
|
try {
|
|
8814
8857
|
const yamlEngine = require_engines().yaml;
|
|
@@ -8840,7 +8883,11 @@ function parseCommandMarkdown(filePath, content, commandDir) {
|
|
|
8840
8883
|
logError(`Invalid command config in ${filePath}: ${JSON.stringify(result.error.format())}`);
|
|
8841
8884
|
return null;
|
|
8842
8885
|
}
|
|
8843
|
-
|
|
8886
|
+
const resolvedConfig = { ...result.data };
|
|
8887
|
+
if (resolvedConfig.template) {
|
|
8888
|
+
resolvedConfig.template = resolveTemplateVars(resolvedConfig.template, templateVars);
|
|
8889
|
+
}
|
|
8890
|
+
return { name: commandName, path: filePath, config: resolvedConfig };
|
|
8844
8891
|
}
|
|
8845
8892
|
async function discoverPlugins(repoPath, repoShortName) {
|
|
8846
8893
|
const plugins = [];
|
|
@@ -10083,7 +10130,7 @@ var DEFAULT_OPENCODE_AGENTS_TO_DISABLE = ["build", "plan"];
|
|
|
10083
10130
|
async function performLoad(config) {
|
|
10084
10131
|
const disableMatcher = createDisableMatcher(config.disable);
|
|
10085
10132
|
log(config.dryRun ? "[DRY-RUN] Analyzing team configuration..." : "Loading team configuration...");
|
|
10086
|
-
const result = await discoverAssets(PACKAGE_ROOT);
|
|
10133
|
+
const result = await discoverAssets(PACKAGE_ROOT, config.agentNames);
|
|
10087
10134
|
if (!config.dryRun) {
|
|
10088
10135
|
const brokenUnmanagedLinks = findBrokenUnmanagedPluginLinks();
|
|
10089
10136
|
if (brokenUnmanagedLinks.length > 0) {
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|