@tudeorangbiasa/sdd-multiagent-opencode 0.3.1 → 0.4.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/.opencode/commands/sdd-construct.md +8 -16
- package/.opencode/plugins/sdd-auto-reasoning.js +16 -20
- package/.opencode/plugins/sdd-model-router.js +72 -30
- package/.opencode/plugins/sdd-register.js +10 -51
- package/GUIDE.md +1 -1
- package/README.md +55 -30
- package/bin/sdd-opencode.js +87 -39
- package/package.json +2 -1
- package/sdd-multiagent-opencode.json +50 -0
- package/vendor/opencode-agent-rules/opencode-agent-rules.json +8 -0
- package/vendor/opencode-agent-rules/opencode.json +1 -7
- package/.sdd/templates/model-profile-template.json +0 -31
- package/.sdd/templates/reasoning-profile-template.json +0 -23
|
@@ -177,10 +177,10 @@ Ask:
|
|
|
177
177
|
|
|
178
178
|
> Explainer: SDD routes different agents to different models. Paid models get planning and orchestration roles. Free models get implementation and exploration roles. This section configures that routing.
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
Read `~/.config/opencode/sdd-multiagent-opencode.json` and summarize the current global routing. If the file is missing or still uses defaults, ask:
|
|
181
181
|
1. **Do you have a paid model subscription?** (OpenAI Plus, OpenCode Go, OpenCode Zen, or direct API keys)
|
|
182
182
|
2. **If yes, which provider?** This determines which agents get routed to paid models.
|
|
183
|
-
3. **If no,
|
|
183
|
+
3. **If no, keep the free-model defaults.** Implementation will still work but planning may be slower.
|
|
184
184
|
|
|
185
185
|
### Section D — Issue Tracker (ALL types)
|
|
186
186
|
|
|
@@ -293,18 +293,13 @@ If Phase 1 used the sniff test (no subagent spawned), write the stack profile no
|
|
|
293
293
|
|
|
294
294
|
This ensures `.sdd/stack-profile.json` always exists after `/sdd-construct`, regardless of whether a subagent was used.
|
|
295
295
|
|
|
296
|
-
### 3.2
|
|
296
|
+
### 3.2 Global SDD config
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
- If user has paid subscription → route orchestrator and planner to paid model
|
|
300
|
-
- If user has no paid subscription → use free model defaults
|
|
301
|
-
- Keep explorer, implementer, verifier, reviewer on free models
|
|
298
|
+
Do not create per-project model or reasoning profiles. SDD runtime configuration lives in `~/.config/opencode/sdd-multiagent-opencode.json`.
|
|
302
299
|
|
|
303
|
-
|
|
300
|
+
If the global config is missing, report it and suggest creating it. Do not write outside the project unless the user explicitly asks.
|
|
304
301
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
### 3.4 `CONTEXT.md` (at repo root)
|
|
302
|
+
### 3.3 `CONTEXT.md` (at repo root)
|
|
308
303
|
|
|
309
304
|
Create the domain glossary. Format:
|
|
310
305
|
|
|
@@ -627,8 +622,7 @@ Before reporting completion, verify:
|
|
|
627
622
|
### Universal checks (ALL project types):
|
|
628
623
|
- [ ] `.sdd/stack-profile.json` exists (written by explorer or by planner after sniff test)
|
|
629
624
|
- [ ] `.sdd/project-profile.json` exists and has non-null values for detected stack
|
|
630
|
-
- [ ]
|
|
631
|
-
- [ ] `.sdd/reasoning-profile.json` exists
|
|
625
|
+
- [ ] `~/.config/opencode/sdd-multiagent-opencode.json` exists or missing global config was reported
|
|
632
626
|
- [ ] `CONTEXT.md` exists at repo root (even if empty tables)
|
|
633
627
|
- [ ] `docs/adr/0001-project-initialization.md` exists
|
|
634
628
|
- [ ] `AGENTS.md` or `CLAUDE.md` has `## Agent skills` block
|
|
@@ -657,7 +651,7 @@ Before final output, verify:
|
|
|
657
651
|
- [ ] Grilling questions were asked one at a time (not dumped all at once)
|
|
658
652
|
- [ ] CONTEXT.md contains domain terms from the grilling session, not generic placeholders
|
|
659
653
|
- [ ] ADR documents actual decisions made during the session
|
|
660
|
-
- [ ]
|
|
654
|
+
- [ ] Global model routing reflects user's subscription status, or missing global config was reported
|
|
661
655
|
- [ ] No file paths or code snippets in CONTEXT.md
|
|
662
656
|
- [ ] Type-specific guardrails match classified project type
|
|
663
657
|
- [ ] No DESIGN.md generated for non-UI projects (backend, library, cli)
|
|
@@ -675,8 +669,6 @@ changed: SDD project initialized
|
|
|
675
669
|
Artifacts created:
|
|
676
670
|
- `.sdd/stack-profile.json` — raw stack detection results (from explorer or sniff test)
|
|
677
671
|
- `.sdd/project-profile.json` — stack detection results
|
|
678
|
-
- `.sdd/model-profile.json` — model routing configuration
|
|
679
|
-
- `.sdd/reasoning-profile.json` — reasoning effort per agent
|
|
680
672
|
- `CONTEXT.md` — domain glossary
|
|
681
673
|
- `docs/adr/0001-project-initialization.md` — initialization decisions
|
|
682
674
|
- `docs/agents/issue-tracker.md` — issue tracker configuration
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
3
|
|
|
5
|
-
const pluginDir = path.dirname(fileURLToPath(import.meta.url));
|
|
6
4
|
const LEVELS = new Set(["low", "medium", "high"]);
|
|
7
5
|
const pendingOverrides = new Map();
|
|
8
6
|
const recentCommands = new Map();
|
|
7
|
+
const globalConfigPath = path.join(
|
|
8
|
+
process.env.HOME || process.env.USERPROFILE || "",
|
|
9
|
+
".config",
|
|
10
|
+
"opencode",
|
|
11
|
+
"sdd-multiagent-opencode.json"
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const DEFAULT_REASONING = {
|
|
15
|
+
default: "low",
|
|
16
|
+
applyProviderOptions: true,
|
|
17
|
+
resetToolOverrideAfterNextRequest: true,
|
|
18
|
+
agents: {},
|
|
19
|
+
commands: {},
|
|
20
|
+
};
|
|
9
21
|
|
|
10
22
|
function readJson(filePath) {
|
|
11
23
|
if (!fs.existsSync(filePath)) return null;
|
|
@@ -18,24 +30,8 @@ function readJson(filePath) {
|
|
|
18
30
|
}
|
|
19
31
|
|
|
20
32
|
function readProfile() {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
path.join(pluginDir, "..", "..", ".sdd", "reasoning-profile.json"),
|
|
24
|
-
path.join(pluginDir, "..", ".sdd", "reasoning-profile.json"),
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
for (const candidate of candidates) {
|
|
28
|
-
const profile = readJson(candidate);
|
|
29
|
-
if (profile) return profile;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
default: "low",
|
|
34
|
-
applyProviderOptions: true,
|
|
35
|
-
resetToolOverrideAfterNextRequest: true,
|
|
36
|
-
agents: {},
|
|
37
|
-
commands: {},
|
|
38
|
-
};
|
|
33
|
+
const pluginConfig = readJson(globalConfigPath);
|
|
34
|
+
return pluginConfig?.reasoning ?? DEFAULT_REASONING;
|
|
39
35
|
}
|
|
40
36
|
|
|
41
37
|
function normalizeLevel(level, fallback = "low") {
|
|
@@ -1,57 +1,99 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
3
|
+
|
|
4
|
+
const globalConfigPath = path.join(
|
|
5
|
+
process.env.HOME || process.env.USERPROFILE || "",
|
|
6
|
+
".config",
|
|
7
|
+
"opencode",
|
|
8
|
+
"sdd-multiagent-opencode.json"
|
|
9
|
+
);
|
|
10
|
+
const DEFAULT_PLUGIN_CONFIG = {
|
|
11
|
+
model: "openai/gpt-5.5",
|
|
12
|
+
small_model: "opencode/deepseek-v4-flash-free",
|
|
13
|
+
agent: {
|
|
14
|
+
"sdd-orchestrator": { model: "openai/gpt-5.5" },
|
|
15
|
+
"sdd-planner": { model: "openai/gpt-5.5" },
|
|
16
|
+
"sdd-explorer": { model: "opencode/deepseek-v4-flash-free" },
|
|
17
|
+
"sdd-implementer": { model: "opencode/deepseek-v4-flash-free" },
|
|
18
|
+
"sdd-verifier": { model: "opencode/qwen3.6-plus-free" },
|
|
19
|
+
"sdd-reviewer": { model: "opencode/minimax-m2.5-free" },
|
|
20
|
+
"sdd-quick": { model: "opencode/qwen3.6-plus-free" },
|
|
21
|
+
},
|
|
22
|
+
reasoning: {
|
|
23
|
+
default: "low",
|
|
24
|
+
applyProviderOptions: true,
|
|
25
|
+
resetToolOverrideAfterNextRequest: true,
|
|
26
|
+
agents: {
|
|
27
|
+
general: "medium",
|
|
28
|
+
plan: "high",
|
|
29
|
+
"sdd-orchestrator": "high",
|
|
30
|
+
"sdd-planner": "high",
|
|
31
|
+
"sdd-explorer": "low",
|
|
32
|
+
"sdd-implementer": "medium",
|
|
33
|
+
"sdd-verifier": "medium",
|
|
34
|
+
"sdd-reviewer": "medium",
|
|
35
|
+
"sdd-quick": "low",
|
|
36
|
+
},
|
|
37
|
+
commands: {
|
|
38
|
+
"sdd-explore": "medium",
|
|
39
|
+
"sdd-propose": "high",
|
|
40
|
+
"sdd-apply": "medium",
|
|
41
|
+
"sdd-ship": "medium",
|
|
42
|
+
"sdd-quick": "low",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function ensureConfigFile() {
|
|
48
|
+
if (fs.existsSync(globalConfigPath)) return;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
fs.mkdirSync(path.dirname(globalConfigPath), { recursive: true });
|
|
52
|
+
fs.writeFileSync(globalConfigPath, `${JSON.stringify(DEFAULT_PLUGIN_CONFIG, null, 2)}\n`);
|
|
53
|
+
} catch {
|
|
54
|
+
// If the global config cannot be seeded, continue with OpenCode's existing config.
|
|
24
55
|
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readConfig() {
|
|
59
|
+
ensureConfigFile();
|
|
60
|
+
if (!fs.existsSync(globalConfigPath)) return null;
|
|
25
61
|
|
|
26
|
-
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(fs.readFileSync(globalConfigPath, "utf-8"));
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
27
67
|
}
|
|
28
68
|
|
|
29
69
|
export default async () => {
|
|
30
70
|
return {
|
|
31
71
|
config: (cfg) => {
|
|
32
|
-
const
|
|
33
|
-
if (!
|
|
72
|
+
const pluginConfig = readConfig();
|
|
73
|
+
if (!pluginConfig) {
|
|
34
74
|
return;
|
|
35
75
|
}
|
|
36
76
|
|
|
37
|
-
if (
|
|
38
|
-
cfg.model =
|
|
77
|
+
if (pluginConfig.model) {
|
|
78
|
+
cfg.model = pluginConfig.model;
|
|
39
79
|
}
|
|
40
80
|
|
|
41
|
-
if (
|
|
42
|
-
cfg.small_model =
|
|
81
|
+
if (pluginConfig.small_model) {
|
|
82
|
+
cfg.small_model = pluginConfig.small_model;
|
|
43
83
|
}
|
|
44
84
|
|
|
45
85
|
if (!cfg.agent) {
|
|
46
86
|
cfg.agent = {};
|
|
47
87
|
}
|
|
48
88
|
|
|
49
|
-
for (const [agentName,
|
|
89
|
+
for (const [agentName, agentConfig] of Object.entries(pluginConfig.agent ?? {})) {
|
|
90
|
+
if (!agentConfig?.model) continue;
|
|
91
|
+
|
|
50
92
|
if (!cfg.agent[agentName]) {
|
|
51
93
|
cfg.agent[agentName] = {};
|
|
52
94
|
}
|
|
53
95
|
|
|
54
|
-
cfg.agent[agentName].model = model;
|
|
96
|
+
cfg.agent[agentName].model = agentConfig.model;
|
|
55
97
|
}
|
|
56
98
|
},
|
|
57
99
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import sddAutoReasoning from "./sdd-auto-reasoning.js";
|
|
5
|
+
import sddModelRouter from "./sdd-model-router.js";
|
|
4
6
|
|
|
5
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
8
|
const __dirname = path.dirname(__filename);
|
|
@@ -478,7 +480,7 @@ After presenting findings, walk the user through decisions one at a time. Do not
|
|
|
478
480
|
3. Team size: solo, small team (2-5), or large team (5+)?
|
|
479
481
|
|
|
480
482
|
### Section C — Model Budget (ALL types)
|
|
481
|
-
|
|
483
|
+
Explain that SDD model and reasoning routing are configured globally in ~/.config/opencode/sdd-multiagent-opencode.json. Ask about paid model subscriptions only if the global config is missing or obviously still using defaults.
|
|
482
484
|
|
|
483
485
|
### Section D — Issue Tracker (ALL types)
|
|
484
486
|
Options: GitHub, GitLab, Local markdown, Other.
|
|
@@ -495,7 +497,7 @@ Options: GitHub, GitLab, Local markdown, Other.
|
|
|
495
497
|
|
|
496
498
|
## Phase 3: Scaffold Artifacts
|
|
497
499
|
|
|
498
|
-
Generate: .sdd/project-profile.json, .sdd/stack-profile.json,
|
|
500
|
+
Generate: .sdd/project-profile.json, .sdd/stack-profile.json, CONTEXT.md, docs/adr/0001-project-initialization.md, type-specific artifacts, docs/agents/issue-tracker.md, and update AGENTS.md with agent skills block. Do not create per-project model or reasoning profiles.
|
|
499
501
|
|
|
500
502
|
## Phase 4: Verification
|
|
501
503
|
|
|
@@ -511,7 +513,7 @@ End with:
|
|
|
511
513
|
changed: SDD project initialized
|
|
512
514
|
|
|
513
515
|
Artifacts created:
|
|
514
|
-
- .sdd/stack-profile.json, .sdd/project-profile.json
|
|
516
|
+
- .sdd/stack-profile.json, .sdd/project-profile.json
|
|
515
517
|
- CONTEXT.md, docs/adr/0001-project-initialization.md, docs/agents/issue-tracker.md
|
|
516
518
|
- AGENTS.md (agent skills block)
|
|
517
519
|
- <type-specific artifacts>
|
|
@@ -802,8 +804,12 @@ suggestion: Run /sdd-propose "<request>" for full workflow.`,
|
|
|
802
804
|
// ─── Plugin Export ───────────────────────────────────────────────────────────
|
|
803
805
|
|
|
804
806
|
export default async ({ client, project, directory, $ }) => {
|
|
807
|
+
const modelRouterHooks = await sddModelRouter({ client, project, directory, $ });
|
|
808
|
+
const autoReasoningHooks = await sddAutoReasoning({ client, project, directory, $ });
|
|
809
|
+
|
|
805
810
|
return {
|
|
806
811
|
agent: AGENTS,
|
|
812
|
+
...autoReasoningHooks,
|
|
807
813
|
|
|
808
814
|
config(cfg) {
|
|
809
815
|
// Register SDD skills path
|
|
@@ -835,54 +841,7 @@ export default async ({ client, project, directory, $ }) => {
|
|
|
835
841
|
cfg.permission.skill["sdd-*"] = "allow";
|
|
836
842
|
}
|
|
837
843
|
|
|
838
|
-
|
|
839
|
-
// Load sdd-model-router
|
|
840
|
-
try {
|
|
841
|
-
const modelRouterPath = path.join(__dirname, "sdd-model-router.js");
|
|
842
|
-
if (fs.existsSync(modelRouterPath)) {
|
|
843
|
-
import(modelRouterPath).then(async (mod) => {
|
|
844
|
-
const pluginFn = mod.default;
|
|
845
|
-
if (pluginFn) {
|
|
846
|
-
const result = await pluginFn({ client, project, directory, $ });
|
|
847
|
-
if (result.config) {
|
|
848
|
-
result.config(cfg);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
});
|
|
852
|
-
}
|
|
853
|
-
} catch {
|
|
854
|
-
// sdd-model-router not available, skip
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// Load sdd-auto-reasoning
|
|
858
|
-
try {
|
|
859
|
-
const reasoningPath = path.join(__dirname, "sdd-auto-reasoning.js");
|
|
860
|
-
if (fs.existsSync(reasoningPath)) {
|
|
861
|
-
import(reasoningPath).then(async (mod) => {
|
|
862
|
-
const pluginFn = mod.default;
|
|
863
|
-
if (pluginFn) {
|
|
864
|
-
const result = await pluginFn({ client, project, directory, $ });
|
|
865
|
-
// Merge all hooks from auto-reasoning
|
|
866
|
-
for (const [hookName, hookFn] of Object.entries(result)) {
|
|
867
|
-
if (hookName !== "config" && typeof hookFn === "function") {
|
|
868
|
-
// Chain hook — call existing then new
|
|
869
|
-
const existing = cfg[hookName];
|
|
870
|
-
if (typeof existing === "function") {
|
|
871
|
-
cfg[hookName] = async (...args) => {
|
|
872
|
-
await existing(...args);
|
|
873
|
-
await hookFn(...args);
|
|
874
|
-
};
|
|
875
|
-
} else {
|
|
876
|
-
cfg[hookName] = hookFn;
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
} catch {
|
|
884
|
-
// sdd-auto-reasoning not available, skip
|
|
885
|
-
}
|
|
844
|
+
modelRouterHooks.config?.(cfg);
|
|
886
845
|
},
|
|
887
846
|
};
|
|
888
847
|
};
|
package/GUIDE.md
CHANGED
|
@@ -48,7 +48,7 @@ Run this once at the start of a project to set up the "spine" — stack detectio
|
|
|
48
48
|
- Section F: Type-specific guardrails (conditional)
|
|
49
49
|
|
|
50
50
|
3. **Phase 3: Scaffold Artifacts**
|
|
51
|
-
- `.sdd/project-profile.json`,
|
|
51
|
+
- `.sdd/project-profile.json`, plus global runtime config in `~/.config/opencode/sdd-multiagent-opencode.json`
|
|
52
52
|
- `CONTEXT.md` (domain glossary)
|
|
53
53
|
- `docs/adr/0001-project-initialization.md`
|
|
54
54
|
- Type-specific artifacts (conditional):
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ external UI skills # impeccable, taste, nothing-design, etc.
|
|
|
41
41
|
| **sdd-reviewer** | configurable | Code review (security, performance, spec compliance) |
|
|
42
42
|
| **sdd-quick** | configurable | Small cosmetic/config edits (~200 tokens via CLI wrapper) |
|
|
43
43
|
|
|
44
|
-
**All models are configurable** via
|
|
44
|
+
**All models are configurable** via `~/.config/opencode/sdd-multiagent-opencode.json`. Edit this file to change which model each agent uses. See [Model Settings](#model-settings) below.
|
|
45
45
|
|
|
46
46
|
## Quick Start
|
|
47
47
|
|
|
@@ -64,7 +64,7 @@ To pin a specific version:
|
|
|
64
64
|
```json
|
|
65
65
|
{
|
|
66
66
|
"plugin": [
|
|
67
|
-
"@tudeorangbiasa/sdd-multiagent-opencode@0.
|
|
67
|
+
"@tudeorangbiasa/sdd-multiagent-opencode@0.4.0"
|
|
68
68
|
]
|
|
69
69
|
}
|
|
70
70
|
```
|
|
@@ -116,7 +116,11 @@ Most work starts with `/sdd-propose`, then `/sdd-apply`, then `/sdd-ship`. Use `
|
|
|
116
116
|
|
|
117
117
|
## Model Settings
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
SDD model and reasoning routing are configured in one global plugin config:
|
|
120
|
+
|
|
121
|
+
`~/.config/opencode/sdd-multiagent-opencode.json`
|
|
122
|
+
|
|
123
|
+
Edit this file to change which model each SDD agent uses. This package does not read per-project model or reasoning profile files at runtime.
|
|
120
124
|
|
|
121
125
|
**⚠️ Requirement:** SDD works best with at least **ONE paid/subscription model** for orchestrator and planner. These roles need strong reasoning + multimodal capabilities that free models lack.
|
|
122
126
|
|
|
@@ -223,22 +227,43 @@ Models available at no cost via OpenCode Zen. Run `opencode models opencode | gr
|
|
|
223
227
|
- `groq/llama-3.3-70b-versatile` — Llama 3.3 70B via Groq
|
|
224
228
|
- `openrouter/deepseek-r1-free` — DeepSeek R1 via OpenRouter (free)
|
|
225
229
|
|
|
226
|
-
### Default
|
|
230
|
+
### Default Config
|
|
227
231
|
|
|
228
232
|
Recommended starting configuration (orchestrator/planner use OpenAI GPT 5.5, others use free):
|
|
229
233
|
|
|
230
234
|
```json
|
|
231
235
|
{
|
|
232
|
-
"
|
|
233
|
-
"
|
|
234
|
-
"
|
|
235
|
-
"sdd-orchestrator": "openai/gpt-5.5",
|
|
236
|
-
"sdd-planner": "openai/gpt-5.5",
|
|
237
|
-
"sdd-explorer": "opencode/deepseek-v4-flash-free",
|
|
238
|
-
"sdd-implementer": "opencode/deepseek-v4-flash-free",
|
|
239
|
-
"sdd-verifier": "opencode/qwen3.6-plus-free",
|
|
240
|
-
"sdd-reviewer": "opencode/minimax-m2.5-free",
|
|
241
|
-
"sdd-quick": "opencode/qwen3.6-plus-free"
|
|
236
|
+
"model": "openai/gpt-5.5",
|
|
237
|
+
"small_model": "opencode/deepseek-v4-flash-free",
|
|
238
|
+
"agent": {
|
|
239
|
+
"sdd-orchestrator": { "model": "openai/gpt-5.5" },
|
|
240
|
+
"sdd-planner": { "model": "openai/gpt-5.5" },
|
|
241
|
+
"sdd-explorer": { "model": "opencode/deepseek-v4-flash-free" },
|
|
242
|
+
"sdd-implementer": { "model": "opencode/deepseek-v4-flash-free" },
|
|
243
|
+
"sdd-verifier": { "model": "opencode/qwen3.6-plus-free" },
|
|
244
|
+
"sdd-reviewer": { "model": "opencode/minimax-m2.5-free" },
|
|
245
|
+
"sdd-quick": { "model": "opencode/qwen3.6-plus-free" }
|
|
246
|
+
},
|
|
247
|
+
"reasoning": {
|
|
248
|
+
"default": "low",
|
|
249
|
+
"applyProviderOptions": true,
|
|
250
|
+
"resetToolOverrideAfterNextRequest": true,
|
|
251
|
+
"agents": {
|
|
252
|
+
"sdd-orchestrator": "high",
|
|
253
|
+
"sdd-planner": "high",
|
|
254
|
+
"sdd-explorer": "low",
|
|
255
|
+
"sdd-implementer": "medium",
|
|
256
|
+
"sdd-verifier": "medium",
|
|
257
|
+
"sdd-reviewer": "medium",
|
|
258
|
+
"sdd-quick": "low"
|
|
259
|
+
},
|
|
260
|
+
"commands": {
|
|
261
|
+
"sdd-explore": "medium",
|
|
262
|
+
"sdd-propose": "high",
|
|
263
|
+
"sdd-apply": "medium",
|
|
264
|
+
"sdd-ship": "medium",
|
|
265
|
+
"sdd-quick": "low"
|
|
266
|
+
}
|
|
242
267
|
}
|
|
243
268
|
}
|
|
244
269
|
```
|
|
@@ -247,16 +272,16 @@ Recommended starting configuration (orchestrator/planner use OpenAI GPT 5.5, oth
|
|
|
247
272
|
|
|
248
273
|
```json
|
|
249
274
|
{
|
|
250
|
-
"
|
|
251
|
-
"
|
|
252
|
-
"
|
|
253
|
-
"sdd-orchestrator": "opencode-go/deepseek-v4-pro",
|
|
254
|
-
"sdd-planner": "opencode-go/deepseek-v4-pro",
|
|
255
|
-
"sdd-explorer": "opencode/deepseek-v4-flash-free",
|
|
256
|
-
"sdd-implementer": "opencode/deepseek-v4-flash-free",
|
|
257
|
-
"sdd-verifier": "opencode-go/kimi-k2.6",
|
|
258
|
-
"sdd-reviewer": "opencode/minimax-m2.5-free",
|
|
259
|
-
"sdd-quick": "opencode-go/qwen3.6-plus"
|
|
275
|
+
"model": "opencode-go/deepseek-v4-pro",
|
|
276
|
+
"small_model": "opencode/deepseek-v4-flash-free",
|
|
277
|
+
"agent": {
|
|
278
|
+
"sdd-orchestrator": { "model": "opencode-go/deepseek-v4-pro" },
|
|
279
|
+
"sdd-planner": { "model": "opencode-go/deepseek-v4-pro" },
|
|
280
|
+
"sdd-explorer": { "model": "opencode/deepseek-v4-flash-free" },
|
|
281
|
+
"sdd-implementer": { "model": "opencode/deepseek-v4-flash-free" },
|
|
282
|
+
"sdd-verifier": { "model": "opencode-go/kimi-k2.6" },
|
|
283
|
+
"sdd-reviewer": { "model": "opencode/minimax-m2.5-free" },
|
|
284
|
+
"sdd-quick": { "model": "opencode-go/qwen3.6-plus" }
|
|
260
285
|
}
|
|
261
286
|
}
|
|
262
287
|
```
|
|
@@ -270,13 +295,13 @@ Recommended starting configuration (orchestrator/planner use OpenAI GPT 5.5, oth
|
|
|
270
295
|
- **Reviewer** → MiniMax M2.5 free: structured code review output
|
|
271
296
|
- **Quick** → Qwen3.6 Plus free: minimal prompt for small cosmetic/config edits (~200 tokens)
|
|
272
297
|
|
|
273
|
-
`.opencode/plugins/sdd-model-router.js` reads
|
|
298
|
+
`.opencode/plugins/sdd-model-router.js` reads `~/.config/opencode/sdd-multiagent-opencode.json` at OpenCode startup and applies the model settings. **Restart OpenCode after editing it.**
|
|
274
299
|
|
|
275
|
-
**Important:** Do NOT set models in `opencode.json
|
|
300
|
+
**Important:** Do NOT set SDD agent models in `opencode.json`. All SDD model routing goes through `~/.config/opencode/sdd-multiagent-opencode.json`.
|
|
276
301
|
|
|
277
302
|
### Auto Reasoning
|
|
278
303
|
|
|
279
|
-
The
|
|
304
|
+
The plugin installs `.opencode/plugins/sdd-auto-reasoning.js` and reads the `reasoning` section from `~/.config/opencode/sdd-multiagent-opencode.json`.
|
|
280
305
|
|
|
281
306
|
The plugin reverse-engineers the behavior of `@howaboua/pi-auto-reasoning-tool` for OpenCode:
|
|
282
307
|
- sets reasoning effort automatically per agent and command
|
|
@@ -298,7 +323,7 @@ Default routing:
|
|
|
298
323
|
}
|
|
299
324
|
```
|
|
300
325
|
|
|
301
|
-
Restart OpenCode after editing
|
|
326
|
+
Restart OpenCode after editing `~/.config/opencode/sdd-multiagent-opencode.json`.
|
|
302
327
|
|
|
303
328
|
### Manual Install
|
|
304
329
|
|
|
@@ -380,8 +405,6 @@ For small cosmetic fixes:
|
|
|
380
405
|
.sdd/
|
|
381
406
|
├── config.json # Project configuration
|
|
382
407
|
├── project-profile.json # Stack and skill routing config
|
|
383
|
-
├── model-profile.json # Model routing per agent
|
|
384
|
-
├── reasoning-profile.json # Reasoning effort per agent/command
|
|
385
408
|
└── templates/ # Document templates
|
|
386
409
|
├── proposal-template.md
|
|
387
410
|
├── spec-template.md
|
|
@@ -407,6 +430,8 @@ specs/
|
|
|
407
430
|
└── QUICKFIX_LOG_ARCHIVE.md # Archived ledger entries
|
|
408
431
|
```
|
|
409
432
|
|
|
433
|
+
Global runtime config lives at `~/.config/opencode/sdd-multiagent-opencode.json`.
|
|
434
|
+
|
|
410
435
|
## Workflows
|
|
411
436
|
|
|
412
437
|
### New Project Setup
|
package/bin/sdd-opencode.js
CHANGED
|
@@ -122,6 +122,64 @@ function parseJsonc(filePath) {
|
|
|
122
122
|
return JSON.parse(stripped);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
function readJsonSafe(filePath) {
|
|
126
|
+
if (!fs.existsSync(filePath)) return null;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getNativeAuthPath() {
|
|
136
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
137
|
+
const xdgDataHome = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
|
|
138
|
+
return path.join(xdgDataHome, "opencode", "auth.json");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getProviderId(model) {
|
|
142
|
+
if (typeof model !== "string") return null;
|
|
143
|
+
const separator = model.indexOf("/");
|
|
144
|
+
if (separator <= 0) return null;
|
|
145
|
+
return model.slice(0, separator);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getProviderEnvNames(providerId) {
|
|
149
|
+
const explicit = {
|
|
150
|
+
openai: ["OPENAI_API_KEY"],
|
|
151
|
+
anthropic: ["ANTHROPIC_API_KEY"],
|
|
152
|
+
google: ["GOOGLE_API_KEY", "GEMINI_API_KEY"],
|
|
153
|
+
opencode: ["OPENCODE_API_KEY", "OPENCODE_ZEN_API_KEY"],
|
|
154
|
+
openrouter: ["OPENROUTER_API_KEY"],
|
|
155
|
+
groq: ["GROQ_API_KEY"],
|
|
156
|
+
deepseek: ["DEEPSEEK_API_KEY"],
|
|
157
|
+
minimax: ["MINIMAX_API_KEY"],
|
|
158
|
+
moonshot: ["MOONSHOT_API_KEY"],
|
|
159
|
+
zai: ["ZAI_API_KEY"],
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
if (explicit[providerId]) return explicit[providerId];
|
|
163
|
+
|
|
164
|
+
return [`${providerId.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_API_KEY`];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function describeProviderConfig(providerId, opencodeConfig, nativeAuth) {
|
|
168
|
+
const auth = nativeAuth?.[providerId];
|
|
169
|
+
if (auth?.type === "oauth") return "configured via OpenCode native oauth";
|
|
170
|
+
if (auth?.type === "api") return "configured via OpenCode native api auth";
|
|
171
|
+
if (auth) return "configured via OpenCode native auth";
|
|
172
|
+
|
|
173
|
+
const providerConfig = opencodeConfig?.provider?.[providerId];
|
|
174
|
+
if (providerConfig?.options?.apiKey) return "configured via opencode.json provider apiKey";
|
|
175
|
+
if (providerConfig) return "configured via opencode.json provider";
|
|
176
|
+
|
|
177
|
+
const envName = getProviderEnvNames(providerId).find((name) => !!process.env[name]);
|
|
178
|
+
if (envName) return `configured via ${envName}`;
|
|
179
|
+
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
|
|
125
183
|
// ─── Backup ──────────────────────────────────────────────────────────────────
|
|
126
184
|
|
|
127
185
|
function createBackup(filePath) {
|
|
@@ -177,7 +235,7 @@ function parseArgs(argv) {
|
|
|
177
235
|
// ─── Usage ───────────────────────────────────────────────────────────────────
|
|
178
236
|
|
|
179
237
|
function usage() {
|
|
180
|
-
console.log(`SDD Multi-Agent OpenCode Installer v0.
|
|
238
|
+
console.log(`SDD Multi-Agent OpenCode Installer v0.4.0
|
|
181
239
|
|
|
182
240
|
Usage:
|
|
183
241
|
sdd-opencode init [flags] Install SDD workflow into current project
|
|
@@ -331,8 +389,6 @@ function installSdd(ctx) {
|
|
|
331
389
|
|
|
332
390
|
const profileTemplates = [
|
|
333
391
|
{ dest: "project-profile.json", template: "project-profile-template.json", populate: true },
|
|
334
|
-
{ dest: "model-profile.json", template: "model-profile-template.json", populate: false },
|
|
335
|
-
{ dest: "reasoning-profile.json", template: "reasoning-profile-template.json", populate: false },
|
|
336
392
|
];
|
|
337
393
|
|
|
338
394
|
for (const { dest, template, populate } of profileTemplates) {
|
|
@@ -392,16 +448,6 @@ function patchOpencodeJson(ctx) {
|
|
|
392
448
|
|
|
393
449
|
if (!targetConfig.agent) targetConfig.agent = {};
|
|
394
450
|
|
|
395
|
-
// Patch compaction from vendor rules
|
|
396
|
-
const vendorRulesJson = path.join(packageRoot, "vendor/opencode-agent-rules/opencode.json");
|
|
397
|
-
if (fs.existsSync(vendorRulesJson)) {
|
|
398
|
-
const rulesConfig = JSON.parse(fs.readFileSync(vendorRulesJson, "utf-8"));
|
|
399
|
-
if (rulesConfig.agent?.compaction && !targetConfig.agent.compaction) {
|
|
400
|
-
targetConfig.agent.compaction = rulesConfig.agent.compaction;
|
|
401
|
-
ctx.installed.push("opencode.json (compaction patch)");
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
451
|
// Patch plugins
|
|
406
452
|
const pkgJsonPath = path.join(packageRoot, "opencode.json");
|
|
407
453
|
if (fs.existsSync(pkgJsonPath)) {
|
|
@@ -467,7 +513,7 @@ async function runInit(args) {
|
|
|
467
513
|
dryRunFiles: [],
|
|
468
514
|
};
|
|
469
515
|
|
|
470
|
-
console.log("\nSDD Multi-Agent OpenCode Installer v0.
|
|
516
|
+
console.log("\nSDD Multi-Agent OpenCode Installer v0.4.0\n");
|
|
471
517
|
console.log(`Target: ${targetRoot}`);
|
|
472
518
|
if (ctx.dryRun) console.log("Mode: DRY RUN (no files will be written)\n");
|
|
473
519
|
|
|
@@ -503,8 +549,8 @@ async function runInit(args) {
|
|
|
503
549
|
|
|
504
550
|
console.log("\nNext steps:");
|
|
505
551
|
console.log(" 1. Edit .sdd/project-profile.json with your stack");
|
|
506
|
-
console.log(" 2.
|
|
507
|
-
console.log(" 3.
|
|
552
|
+
console.log(" 2. Configure models in ~/.config/opencode/sdd-multiagent-opencode.json");
|
|
553
|
+
console.log(" 3. Run: /sdd-propose \"your first feature\"");
|
|
508
554
|
}
|
|
509
555
|
}
|
|
510
556
|
|
|
@@ -605,42 +651,44 @@ async function runDoctor(args) {
|
|
|
605
651
|
const cmdCount = fs.existsSync(commandsDir) ? fs.readdirSync(commandsDir).filter((f) => f.endsWith(".md")).length : 0;
|
|
606
652
|
report("L1", "commands available", cmdCount >= expectedCommands ? "pass" : "warn", `${cmdCount}/${expectedCommands} command files`);
|
|
607
653
|
|
|
608
|
-
// L2:
|
|
609
|
-
console.log("\nL2:
|
|
654
|
+
// L2: OpenCode provider configuration
|
|
655
|
+
console.log("\nL2: OpenCode Providers");
|
|
610
656
|
|
|
611
|
-
const
|
|
612
|
-
const
|
|
657
|
+
const sddConfigPath = path.join(globalConfigDir, "sdd-multiagent-opencode.json");
|
|
658
|
+
const sddConfig = readJsonSafe(sddConfigPath);
|
|
659
|
+
const globalOpencodeConfig = parseJsonc(path.join(globalConfigDir, "opencode.json"));
|
|
660
|
+
const nativeAuth = readJsonSafe(getNativeAuthPath());
|
|
613
661
|
|
|
614
|
-
if (
|
|
662
|
+
if (sddConfig) {
|
|
615
663
|
const models = new Set();
|
|
616
|
-
if (
|
|
617
|
-
if (
|
|
618
|
-
|
|
664
|
+
if (sddConfig.model) models.add(sddConfig.model);
|
|
665
|
+
if (sddConfig.small_model) models.add(sddConfig.small_model);
|
|
666
|
+
if (sddConfig.agent) {
|
|
667
|
+
for (const agentConfig of Object.values(sddConfig.agent)) {
|
|
668
|
+
if (agentConfig?.model) models.add(agentConfig.model);
|
|
669
|
+
}
|
|
619
670
|
}
|
|
620
671
|
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
const hasKey = !!process.env[name];
|
|
632
|
-
report("L2", `${name}`, hasKey ? "pass" : "warn", hasKey ? "set" : "not set — models requiring this provider were detected");
|
|
633
|
-
}
|
|
672
|
+
const providerIds = new Set([...models].map(getProviderId).filter(Boolean));
|
|
673
|
+
|
|
674
|
+
for (const providerId of providerIds) {
|
|
675
|
+
const configuredBy = describeProviderConfig(providerId, globalOpencodeConfig, nativeAuth);
|
|
676
|
+
report(
|
|
677
|
+
"L2",
|
|
678
|
+
`provider ${providerId}`,
|
|
679
|
+
configuredBy ? "pass" : "warn",
|
|
680
|
+
configuredBy ?? "model uses this provider but no native auth, opencode.json provider, or env key was found"
|
|
681
|
+
);
|
|
634
682
|
}
|
|
635
683
|
} else {
|
|
636
|
-
report("L2", "
|
|
684
|
+
report("L2", "sdd-multiagent-opencode.json", "warn", "not found in ~/.config/opencode — using built-in defaults");
|
|
637
685
|
}
|
|
638
686
|
|
|
639
687
|
// L3: Liveness probe (--deep only)
|
|
640
688
|
if (args.flags.deep) {
|
|
641
689
|
console.log("\nL3: Liveness Probe");
|
|
642
690
|
|
|
643
|
-
const primaryModel =
|
|
691
|
+
const primaryModel = sddConfig?.model || process.env.DEFAULT_MODEL || "unknown";
|
|
644
692
|
report("L3", "model endpoint", "warn", `would probe ${primaryModel} — liveness requires valid API credentials and network access`);
|
|
645
693
|
report("L3", "note", "warn", "full liveness probe requires HTTP client — run manually with curl or your provider's dashboard");
|
|
646
694
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tudeorangbiasa/sdd-multiagent-opencode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Spec-Driven Development workflow kit for OpenCode with 5 core commands, multi-agent support, CLI wrappers, and configurable model routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": ".opencode/plugins/sdd-register.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"vendor",
|
|
16
16
|
"README.md",
|
|
17
17
|
"GUIDE.md",
|
|
18
|
+
"sdd-multiagent-opencode.json",
|
|
18
19
|
"opencode.json"
|
|
19
20
|
],
|
|
20
21
|
"scripts": {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"model": "openai/gpt-5.5",
|
|
3
|
+
"small_model": "opencode/deepseek-v4-flash-free",
|
|
4
|
+
"agent": {
|
|
5
|
+
"sdd-orchestrator": {
|
|
6
|
+
"model": "openai/gpt-5.5"
|
|
7
|
+
},
|
|
8
|
+
"sdd-planner": {
|
|
9
|
+
"model": "openai/gpt-5.5"
|
|
10
|
+
},
|
|
11
|
+
"sdd-explorer": {
|
|
12
|
+
"model": "opencode/deepseek-v4-flash-free"
|
|
13
|
+
},
|
|
14
|
+
"sdd-implementer": {
|
|
15
|
+
"model": "opencode/deepseek-v4-flash-free"
|
|
16
|
+
},
|
|
17
|
+
"sdd-verifier": {
|
|
18
|
+
"model": "opencode/qwen3.6-plus-free"
|
|
19
|
+
},
|
|
20
|
+
"sdd-reviewer": {
|
|
21
|
+
"model": "opencode/minimax-m2.5-free"
|
|
22
|
+
},
|
|
23
|
+
"sdd-quick": {
|
|
24
|
+
"model": "opencode/qwen3.6-plus-free"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"reasoning": {
|
|
28
|
+
"default": "low",
|
|
29
|
+
"applyProviderOptions": true,
|
|
30
|
+
"resetToolOverrideAfterNextRequest": true,
|
|
31
|
+
"agents": {
|
|
32
|
+
"general": "medium",
|
|
33
|
+
"plan": "high",
|
|
34
|
+
"sdd-orchestrator": "high",
|
|
35
|
+
"sdd-planner": "high",
|
|
36
|
+
"sdd-explorer": "low",
|
|
37
|
+
"sdd-implementer": "medium",
|
|
38
|
+
"sdd-verifier": "medium",
|
|
39
|
+
"sdd-reviewer": "medium",
|
|
40
|
+
"sdd-quick": "low"
|
|
41
|
+
},
|
|
42
|
+
"commands": {
|
|
43
|
+
"sdd-explore": "medium",
|
|
44
|
+
"sdd-propose": "high",
|
|
45
|
+
"sdd-apply": "medium",
|
|
46
|
+
"sdd-ship": "medium",
|
|
47
|
+
"sdd-quick": "low"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_info": {
|
|
3
|
-
"description": "Model routing configuration. Edit this file to change which model each agent uses. Restart OpenCode after editing.",
|
|
4
|
-
"requirement": "SDD requires at least ONE paid/subscription model for orchestrator and planner. These roles need strong reasoning that free models cannot provide.",
|
|
5
|
-
"subscription_options": {
|
|
6
|
-
"openai_plus": "GPT 5.5 with reasoning and multimodal",
|
|
7
|
-
"opencode_go": "$10/month — includes DeepSeek V4 Pro, GLM 5.1, Kimi K2.6, MiniMax M2.7",
|
|
8
|
-
"opencode_zen": "Pay-per-token, zero markup — access to Claude Opus 4.7, GPT 5.5, Gemini 3.1 Pro"
|
|
9
|
-
},
|
|
10
|
-
"recommendations": {
|
|
11
|
-
"orchestrator": "PAID: GPT 5.5 (OpenAI) or DeepSeek V4 Pro (Go) — needs strong reasoning for DAG coordination",
|
|
12
|
-
"planner": "PAID: GPT 5.5 (OpenAI), Claude Opus 4.7, or DeepSeek V4 Pro (Go) — needs maximum reasoning for architecture",
|
|
13
|
-
"explorer": "FREE: DeepSeek v4 Flash — fast readonly exploration, token-efficient",
|
|
14
|
-
"implementer": "FREE: DeepSeek v4 Flash — code generation, high token usage",
|
|
15
|
-
"verifier": "FREE: Qwen3.6 Plus — multimodal for Chrome DevTools screenshots",
|
|
16
|
-
"reviewer": "FREE: MiniMax M2.5 — structured code review output",
|
|
17
|
-
"quick": "FREE: Qwen3.6 Plus or DeepSeek v4 Flash — minimal prompt for small edits"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
"defaultPrimary": "openai/gpt-5.5",
|
|
21
|
-
"small": "opencode/deepseek-v4-flash-free",
|
|
22
|
-
"agents": {
|
|
23
|
-
"sdd-orchestrator": "openai/gpt-5.5",
|
|
24
|
-
"sdd-planner": "openai/gpt-5.5",
|
|
25
|
-
"sdd-explorer": "opencode/deepseek-v4-flash-free",
|
|
26
|
-
"sdd-implementer": "opencode/deepseek-v4-flash-free",
|
|
27
|
-
"sdd-verifier": "opencode/qwen3.6-plus-free",
|
|
28
|
-
"sdd-reviewer": "opencode/minimax-m2.5-free",
|
|
29
|
-
"sdd-quick": "opencode/qwen3.6-plus-free"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"default": "low",
|
|
3
|
-
"applyProviderOptions": true,
|
|
4
|
-
"resetToolOverrideAfterNextRequest": true,
|
|
5
|
-
"agents": {
|
|
6
|
-
"general": "medium",
|
|
7
|
-
"plan": "high",
|
|
8
|
-
"sdd-orchestrator": "high",
|
|
9
|
-
"sdd-planner": "high",
|
|
10
|
-
"sdd-explorer": "low",
|
|
11
|
-
"sdd-implementer": "medium",
|
|
12
|
-
"sdd-verifier": "medium",
|
|
13
|
-
"sdd-reviewer": "medium",
|
|
14
|
-
"sdd-quick": "low"
|
|
15
|
-
},
|
|
16
|
-
"commands": {
|
|
17
|
-
"sdd-explore": "medium",
|
|
18
|
-
"sdd-propose": "high",
|
|
19
|
-
"sdd-apply": "medium",
|
|
20
|
-
"sdd-ship": "medium",
|
|
21
|
-
"sdd-quick": "low"
|
|
22
|
-
}
|
|
23
|
-
}
|