@ikieaneh/opencode-kit 0.6.1 → 0.6.3
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/plugins/opencode-kit.js +101 -84
- package/package.json +9 -7
- package/src/init.sh +2 -2
- package/templates/opencode-kit.schema.json +1 -0
- package/templates/superpowers-contract.json +1 -0
- package/.claude-plugin/plugin.json +0 -23
- package/docs/examples/QUICKSTART.md +0 -123
- package/docs/examples/extension-skill-template.md +0 -108
- package/docs/examples/model-configs.md +0 -117
- package/docs/guides/contract-protocol.md +0 -67
- package/docs/guides/scoring-pipeline.md +0 -60
- package/docs/guides/troubleshooting.md +0 -78
- package/docs/images/logo.svg +0 -9
- package/docs/plans/2026-06-11-plugin-architecture.md +0 -55
- package/src/adr.sh +0 -152
- package/src/analytics.sh +0 -80
- package/src/diff.sh +0 -95
- package/src/doctor.sh +0 -160
- package/src/global-config.sh +0 -82
- package/src/new-skill.sh +0 -60
- package/src/platform.sh +0 -34
- package/src/postflight.py +0 -211
- package/src/postflight.sh +0 -82
- package/src/preflight.sh +0 -138
- package/src/status.sh +0 -113
- package/src/telemetry.sh +0 -67
- package/src/update.sh +0 -181
- package/src/verify.sh +0 -67
|
@@ -73,33 +73,38 @@ const resolveConfigPath = (projectDir, relPath) => {
|
|
|
73
73
|
|
|
74
74
|
// --- Auto-init contract.json if missing ---
|
|
75
75
|
const ensureContract = (projectDir) => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
fs.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
try {
|
|
77
|
+
const homeDir = os.homedir();
|
|
78
|
+
const globalDir = path.join(homeDir, '.config/opencode-kit');
|
|
79
|
+
const contractPath = path.join(projectDir, '.opencode', 'orchestration', 'contract.json');
|
|
80
|
+
|
|
81
|
+
// Already exists — nothing to do
|
|
82
|
+
if (fs.existsSync(contractPath)) return contractPath;
|
|
83
|
+
|
|
84
|
+
// Check global config first
|
|
85
|
+
const globalContract = path.join(globalDir, 'orchestration', 'contract.json');
|
|
86
|
+
if (fs.existsSync(globalContract)) {
|
|
87
|
+
fs.mkdirSync(path.dirname(contractPath), { recursive: true });
|
|
88
|
+
fs.copyFileSync(globalContract, contractPath);
|
|
89
|
+
log('info', `Auto-initialized contract from global config: ${contractPath}`);
|
|
90
|
+
return contractPath;
|
|
91
|
+
}
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
// Scaffold from plugin template
|
|
94
|
+
const templatePath = path.join(TEMPLATES_DIR, 'contract.json');
|
|
95
|
+
if (fs.existsSync(templatePath)) {
|
|
96
|
+
fs.mkdirSync(path.dirname(contractPath), { recursive: true });
|
|
97
|
+
fs.copyFileSync(templatePath, contractPath);
|
|
98
|
+
log('info', `Auto-initialized contract from plugin template: ${contractPath}`);
|
|
99
|
+
return contractPath;
|
|
100
|
+
}
|
|
100
101
|
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
log('warn', 'Could not auto-initialize contract — no template found');
|
|
103
|
+
return null;
|
|
104
|
+
} catch (err) {
|
|
105
|
+
log('error', `Failed to auto-init contract: ${err.message}`);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
103
108
|
};
|
|
104
109
|
|
|
105
110
|
// --- Load bootstrap content (cached) ---
|
|
@@ -160,86 +165,98 @@ export const OpencodeKitPlugin = async ({ client, directory }) => {
|
|
|
160
165
|
ensureContract(projectDir);
|
|
161
166
|
|
|
162
167
|
// Ensure global config directory exists
|
|
163
|
-
|
|
164
|
-
|
|
168
|
+
try {
|
|
169
|
+
fs.mkdirSync(path.join(globalConfigDir, 'orchestration'), { recursive: true });
|
|
170
|
+
fs.mkdirSync(path.join(globalConfigDir, 'rules'), { recursive: true });
|
|
171
|
+
} catch (err) {
|
|
172
|
+
log('warn', `Failed to create global config dirs: ${err.message}`);
|
|
173
|
+
}
|
|
165
174
|
|
|
166
175
|
return {
|
|
167
176
|
// Skill resolution order (first match wins):
|
|
168
177
|
// 1. .opencode/skills/<name>/ (user project — highest priority)
|
|
169
178
|
// 2. plugin skills/<name>/ (opencode-kit defaults — fallback)
|
|
170
179
|
config: async (config) => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
try {
|
|
181
|
+
config.skills = config.skills || {};
|
|
182
|
+
config.skills.paths = config.skills.paths || [];
|
|
183
|
+
|
|
184
|
+
// Detect if other plugins might conflict with opencode-kit's system prompt
|
|
185
|
+
if (config.plugins && Array.isArray(config.plugins)) {
|
|
186
|
+
const kitIndex = config.plugins.findIndex(p =>
|
|
187
|
+
typeof p === 'string' && p.includes('opencode-kit')
|
|
188
|
+
);
|
|
189
|
+
if (kitIndex > 0) {
|
|
190
|
+
const firstPlugin = config.plugins[0];
|
|
191
|
+
log('warn', `Plugin ordering conflict: opencode-kit should be FIRST, but found '${firstPlugin}' at position 0 and opencode-kit at position ${kitIndex}`);
|
|
192
|
+
}
|
|
182
193
|
}
|
|
183
|
-
}
|
|
184
194
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
// Register user project skills FIRST (higher priority)
|
|
196
|
+
const userSkillsDir = path.join(projectDir, '.opencode/skills');
|
|
197
|
+
if (fs.existsSync(userSkillsDir) && !config.skills.paths.includes(userSkillsDir)) {
|
|
198
|
+
config.skills.paths.push(userSkillsDir);
|
|
199
|
+
log('info', `Registered user skills: ${userSkillsDir}`);
|
|
200
|
+
}
|
|
191
201
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
202
|
+
// Register plugin skills SECOND (fallback)
|
|
203
|
+
if (!config.skills.paths.includes(SKILLS_DIR)) {
|
|
204
|
+
config.skills.paths.push(SKILLS_DIR);
|
|
205
|
+
log('info', `Registered plugin skills: ${SKILLS_DIR}`);
|
|
206
|
+
}
|
|
197
207
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
208
|
+
// Register global config skills path
|
|
209
|
+
if (!config.skills.paths.includes(globalConfigDir)) {
|
|
210
|
+
if (fs.existsSync(globalConfigDir)) {
|
|
211
|
+
config.skills.paths.push(globalConfigDir);
|
|
212
|
+
}
|
|
202
213
|
}
|
|
203
|
-
}
|
|
204
214
|
|
|
205
|
-
|
|
206
|
-
|
|
215
|
+
// Provide default contract key hint for agents
|
|
216
|
+
config.contractKey = contractKey;
|
|
217
|
+
} catch (err) {
|
|
218
|
+
log('error', `config hook failed: ${err.message}`);
|
|
219
|
+
}
|
|
207
220
|
},
|
|
208
221
|
|
|
209
222
|
'experimental.chat.messages.transform': async (_input, output) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
223
|
+
try {
|
|
224
|
+
const bootstrap = getBootstrapContent();
|
|
225
|
+
if (!bootstrap || !output.messages.length) return;
|
|
226
|
+
|
|
227
|
+
// Check contract for rule_overrides and inject them into bootstrap
|
|
228
|
+
const contractPath = path.join(projectDir, '.opencode', 'orchestration', 'contract.json');
|
|
229
|
+
let finalBootstrap = bootstrap;
|
|
230
|
+
if (fs.existsSync(contractPath)) {
|
|
231
|
+
try {
|
|
232
|
+
const contractRaw = fs.readFileSync(contractPath, 'utf8');
|
|
233
|
+
const contract = JSON.parse(contractRaw);
|
|
234
|
+
if (contract.validation && contract.validation.rule_overrides) {
|
|
235
|
+
const overrides = contract.validation.rule_overrides;
|
|
236
|
+
const overrideKeys = Object.keys(overrides);
|
|
237
|
+
if (overrideKeys.length > 0) {
|
|
238
|
+
const overrideText = overrideKeys
|
|
239
|
+
.map(id => ` - ${id}: action → ${overrides[id]}`)
|
|
240
|
+
.join('\n');
|
|
241
|
+
finalBootstrap = bootstrap + `\n## Rule Overrides (from contract)\n\nThe following rule severities have been overridden:\n${overrideText}\n`;
|
|
242
|
+
}
|
|
228
243
|
}
|
|
244
|
+
} catch (err) {
|
|
245
|
+
log('warn', `Failed to parse contract for rule_overrides: ${err.message}`);
|
|
229
246
|
}
|
|
230
|
-
} catch (err) {
|
|
231
|
-
log('warn', `Failed to parse contract for rule_overrides: ${err.message}`);
|
|
232
247
|
}
|
|
233
|
-
}
|
|
234
248
|
|
|
235
|
-
|
|
236
|
-
|
|
249
|
+
const firstUser = output.messages.find(m => m.info.role === 'user');
|
|
250
|
+
if (!firstUser || !firstUser.parts.length) return;
|
|
237
251
|
|
|
238
|
-
|
|
239
|
-
|
|
252
|
+
// Guard: skip if already injected
|
|
253
|
+
if (firstUser.parts.some(p => p.type === 'text' && p.text.includes('opencode-kit'))) return;
|
|
240
254
|
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
const ref = firstUser.parts[0];
|
|
256
|
+
firstUser.parts.unshift({ ...ref, type: 'text', text: finalBootstrap });
|
|
257
|
+
} catch (err) {
|
|
258
|
+
log('error', `messages.transform hook failed: ${err.message}`);
|
|
259
|
+
}
|
|
243
260
|
}
|
|
244
261
|
};
|
|
245
262
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikieaneh/opencode-kit",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "Standardized OpenCode orchestration framework — contract-based, rules-enforced, zero-touch agent workflow. Install as plugin.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RizkiRachman",
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
".opencode/plugins/",
|
|
19
|
-
".claude-plugin/",
|
|
20
|
-
"src/",
|
|
21
|
-
"rules/",
|
|
22
19
|
"templates/",
|
|
23
20
|
"skills/",
|
|
24
|
-
"
|
|
21
|
+
"rules/",
|
|
22
|
+
"src/cli.js",
|
|
23
|
+
"src/init.sh",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"README.md"
|
|
25
26
|
],
|
|
26
27
|
"publishConfig": {
|
|
27
28
|
"access": "public"
|
|
@@ -42,8 +43,9 @@
|
|
|
42
43
|
"url": "git+https://github.com/RizkiRachman/opencode-kit.git"
|
|
43
44
|
},
|
|
44
45
|
"scripts": {
|
|
45
|
-
"
|
|
46
|
-
"
|
|
46
|
+
"postinstall": "git config core.hooksPath .githooks 2>/dev/null || true",
|
|
47
|
+
"lint": "shellcheck src/*.sh rules/*.sh 2>/dev/null || true",
|
|
48
|
+
"format": "echo 'Formatting: not configured yet'"
|
|
47
49
|
},
|
|
48
50
|
"bugs": {
|
|
49
51
|
"url": "https://github.com/RizkiRachman/opencode-kit/issues"
|
package/src/init.sh
CHANGED
|
@@ -83,8 +83,8 @@ if [ -d ".opencode" ]; then
|
|
|
83
83
|
echo " ✅ Backed up to $BACKUP"
|
|
84
84
|
else
|
|
85
85
|
echo ""
|
|
86
|
-
echo -e "${YELLOW}⚠️ .opencode/ already exists. Use --force to
|
|
87
|
-
echo "
|
|
86
|
+
echo -e "${YELLOW}⚠️ .opencode/ already exists. Use --force to re-scaffold (backup + clean).${NC}"
|
|
87
|
+
echo " Skipping — existing .opencode/ preserved."
|
|
88
88
|
fi
|
|
89
89
|
fi
|
|
90
90
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
"title": "opencode-kit Plugin Config",
|
|
4
4
|
"description": "Configuration schema for @ikieaneh/opencode-kit plugin. Add to your opencode.json to enable orchestration agents.",
|
|
5
5
|
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
6
7
|
"properties": {
|
|
7
8
|
"plugin": {
|
|
8
9
|
"type": "array",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "opencode-kit",
|
|
3
|
-
"description": "Standardized orchestration framework — contract-based, rules-enforced, zero-touch agent workflow",
|
|
4
|
-
"version": "0.6.1",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Rizki Rachman",
|
|
7
|
-
"url": "https://github.com/RizkiRachman"
|
|
8
|
-
},
|
|
9
|
-
"homepage": "https://github.com/RizkiRachman/opencode-kit",
|
|
10
|
-
"repository": "https://github.com/RizkiRachman/opencode-kit",
|
|
11
|
-
"license": "MIT",
|
|
12
|
-
"keywords": [
|
|
13
|
-
"opencode",
|
|
14
|
-
"opencode-plugin",
|
|
15
|
-
"orchestration",
|
|
16
|
-
"workflow",
|
|
17
|
-
"agents",
|
|
18
|
-
"enforcement",
|
|
19
|
-
"contract",
|
|
20
|
-
"scoring",
|
|
21
|
-
"adr"
|
|
22
|
-
]
|
|
23
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# Quickstart: Using opencode-kit as a Plugin
|
|
2
|
-
|
|
3
|
-
This guide creates a new project from scratch with opencode-kit as an OpenCode plugin.
|
|
4
|
-
|
|
5
|
-
## Step 1: Create a project
|
|
6
|
-
|
|
7
|
-
```sh
|
|
8
|
-
mkdir my-agent-project
|
|
9
|
-
cd my-agent-project
|
|
10
|
-
git init
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Step 2: Install the plugin
|
|
14
|
-
|
|
15
|
-
```sh
|
|
16
|
-
npm install @ikieaneh/opencode-kit
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Step 3: Configure OpenCode
|
|
20
|
-
|
|
21
|
-
Create `opencode.json`:
|
|
22
|
-
|
|
23
|
-
```json
|
|
24
|
-
{
|
|
25
|
-
"model": "your-model",
|
|
26
|
-
"plugin": [
|
|
27
|
-
"@ikieaneh/opencode-kit",
|
|
28
|
-
"superpowers"
|
|
29
|
-
],
|
|
30
|
-
"agent": {
|
|
31
|
-
"orchestrator": {
|
|
32
|
-
"model": "your-model",
|
|
33
|
-
"skills": [
|
|
34
|
-
"orchestration-template",
|
|
35
|
-
"scoring-pipeline",
|
|
36
|
-
"verification-before-completion"
|
|
37
|
-
],
|
|
38
|
-
"steps": 50,
|
|
39
|
-
"fallback_models": ["your-fallback-model"]
|
|
40
|
-
},
|
|
41
|
-
"planner": {
|
|
42
|
-
"model": "your-model",
|
|
43
|
-
"skills": ["brainstorming", "writing-plans", "system-analyst"],
|
|
44
|
-
"steps": 80,
|
|
45
|
-
"fallback_models": ["your-fallback-model"]
|
|
46
|
-
},
|
|
47
|
-
"task-manager": {
|
|
48
|
-
"model": "your-model",
|
|
49
|
-
"skills": ["subagent-driven-development", "executing-plans", "test-driven-development"],
|
|
50
|
-
"steps": 100,
|
|
51
|
-
"fallback_models": ["your-fallback-model"]
|
|
52
|
-
},
|
|
53
|
-
"code-reviewer": {
|
|
54
|
-
"model": "your-model",
|
|
55
|
-
"skills": ["qa-expert", "security-expert"],
|
|
56
|
-
"steps": 80,
|
|
57
|
-
"fallback_models": ["your-fallback-model"]
|
|
58
|
-
},
|
|
59
|
-
"explorer": {
|
|
60
|
-
"model": "your-model",
|
|
61
|
-
"steps": 30,
|
|
62
|
-
"tools": { "postgres_*": false, "memory_*": false, "context7_*": false }
|
|
63
|
-
},
|
|
64
|
-
"librarian": {
|
|
65
|
-
"model": "your-model",
|
|
66
|
-
"steps": 30,
|
|
67
|
-
"tools": { "postgres_*": false, "memory_*": false, "graphify_*": false }
|
|
68
|
-
},
|
|
69
|
-
"leaner": {
|
|
70
|
-
"model": "your-model",
|
|
71
|
-
"skills": ["verification-before-completion", "qa-expert"]
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Step 4: Start working
|
|
78
|
-
|
|
79
|
-
Open the project in OpenCode. The plugin auto-loads:
|
|
80
|
-
|
|
81
|
-
1. 8 skills registered automatically
|
|
82
|
-
2. Orchestration contract injected into every session
|
|
83
|
-
3. Pre-flight enforcement active (branch check, contract load)
|
|
84
|
-
4. Scoring pipeline available after every delegation
|
|
85
|
-
5. ADR generator for architectural decisions
|
|
86
|
-
6. Telemetry tracking elapsed time per phase
|
|
87
|
-
|
|
88
|
-
## Step 5: Set a goal
|
|
89
|
-
|
|
90
|
-
Edit `.opencode/orchestration/contract.json`:
|
|
91
|
-
|
|
92
|
-
```json
|
|
93
|
-
{
|
|
94
|
-
"state": "INIT",
|
|
95
|
-
"requirements": {
|
|
96
|
-
"goal": "Add user authentication with JWT",
|
|
97
|
-
"acceptance_criteria": ["Users can register", "Users can login", "Tokens expire after 24h"]
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Step 6: Workflow runs itself
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
INIT → PLAN → PLAN_SCORED → EXECUTE → EXECUTE_SCORED → REVIEW → REVIEW_SCORED → COMPLETE
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Each phase transition requires score ≥ 70. Score < 50 → BLOCKED.
|
|
109
|
-
|
|
110
|
-
## What you get
|
|
111
|
-
|
|
112
|
-
| Feature | Provider |
|
|
113
|
-
|---------|----------|
|
|
114
|
-
| Contract protocol | orchestration-template skill |
|
|
115
|
-
| Scoring pipeline | scoring-pipeline skill |
|
|
116
|
-
| ADR records | adr-generator skill |
|
|
117
|
-
| QA standards | qa-expert skill |
|
|
118
|
-
| Impact analysis | system-analyst skill |
|
|
119
|
-
| Token optimization | token-optimize skill |
|
|
120
|
-
| Verification gates | verification-before-completion skill |
|
|
121
|
-
| Post-task learning | learner skill |
|
|
122
|
-
| Telemetry | src/telemetry.sh |
|
|
123
|
-
| Rules enforcement | rules.json + validation.sh |
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# Extension Skill Template
|
|
2
|
-
|
|
3
|
-
Create project-specific skills in `.opencode/skills/` to extend opencode-kit.
|
|
4
|
-
|
|
5
|
-
## Resolution Order
|
|
6
|
-
|
|
7
|
-
1. `.opencode/skills/<name>/SKILL.md` — user project skill (highest priority)
|
|
8
|
-
2. `node_modules/@ikieaneh/opencode-kit/skills/<name>/SKILL.md` — plugin skill (fallback)
|
|
9
|
-
|
|
10
|
-
If a user skill and plugin skill have the **same name**, the user's version takes priority.
|
|
11
|
-
|
|
12
|
-
## Example: Java/Spring Conventions
|
|
13
|
-
|
|
14
|
-
Create `.opencode/skills/java-conventions/SKILL.md`:
|
|
15
|
-
|
|
16
|
-
```markdown
|
|
17
|
-
---
|
|
18
|
-
description: Java 21 + Spring Boot 3.4 conventions for this project.
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
# Java Conventions
|
|
22
|
-
|
|
23
|
-
## Build & Test
|
|
24
|
-
|
|
25
|
-
| Command | Action |
|
|
26
|
-
|---------|--------|
|
|
27
|
-
| `mvn spotless:apply` | Format (Google Java Style) |
|
|
28
|
-
| `mvn test` | ArchUnit + unit tests |
|
|
29
|
-
| `mvn verify` | SpotBugs + PMD CPD |
|
|
30
|
-
|
|
31
|
-
## Hexagonal Architecture
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
application/ → domain model, ports, services (no Spring/JPA)
|
|
35
|
-
infrastructure/ → web adapters, persistence, events
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Writing Order
|
|
39
|
-
|
|
40
|
-
Port → Service → Mapper → Adapter → Constants → Events → Tests
|
|
41
|
-
|
|
42
|
-
## Naming Rules
|
|
43
|
-
|
|
44
|
-
| Concern | Suffix | Example |
|
|
45
|
-
|---------|--------|---------|
|
|
46
|
-
| API DTO | none | `Product` |
|
|
47
|
-
| Domain Model | `Domain` | `ProductDomain` |
|
|
48
|
-
| JPA Entity | `Entity` | `ProductEntity` |
|
|
49
|
-
|
|
50
|
-
## ArchUnit Rules (7)
|
|
51
|
-
|
|
52
|
-
1. domainMustNotDependOnInfrastructure
|
|
53
|
-
2. domainModelsMustNotHaveJpaAnnotations
|
|
54
|
-
3. portsMustNotReturnOptional
|
|
55
|
-
4. entitiesMustNotUseJpaRelationshipAnnotations
|
|
56
|
-
5. layeredArchitectureShouldRespectHexagonalBoundaries
|
|
57
|
-
6. domainServicesMustBeAnnotatedWithService
|
|
58
|
-
7. repositoryAdaptersMustBeAnnotatedWithComponent
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Example: Python/Django Conventions
|
|
62
|
-
|
|
63
|
-
Create `.opencode/skills/python-conventions/SKILL.md`:
|
|
64
|
-
|
|
65
|
-
```markdown
|
|
66
|
-
---
|
|
67
|
-
description: Django REST Framework conventions for this project.
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
# Python Conventions
|
|
71
|
-
|
|
72
|
-
## Build & Test
|
|
73
|
-
|
|
74
|
-
| Command | Action |
|
|
75
|
-
|---------|--------|
|
|
76
|
-
| `black .` | Format code |
|
|
77
|
-
| `ruff check .` | Lint |
|
|
78
|
-
| `pytest` | Run tests |
|
|
79
|
-
| `mypy .` | Type check |
|
|
80
|
-
|
|
81
|
-
## Architecture
|
|
82
|
-
|
|
83
|
-
Apps follow clean architecture:
|
|
84
|
-
- `models/` — domain models with business logic
|
|
85
|
-
- `serializers/` — input/output validation
|
|
86
|
-
- `views/` — HTTP handlers (thin)
|
|
87
|
-
- `services/` — business logic layer
|
|
88
|
-
- `tests/` — mirrors app structure
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## How to Load
|
|
92
|
-
|
|
93
|
-
In `opencode.json`, add to any agent's skills array:
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{
|
|
97
|
-
"agent": {
|
|
98
|
-
"task-manager": {
|
|
99
|
-
"skills": [
|
|
100
|
-
"verification-before-completion",
|
|
101
|
-
"java-conventions"
|
|
102
|
-
]
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
Or load it ad-hoc with: `/skill java-conventions`
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# Model Provider Configurations
|
|
2
|
-
|
|
3
|
-
Add these to your `opencode.json` to configure AI models for opencode-kit agents.
|
|
4
|
-
|
|
5
|
-
## DeepSeek (via Sumopod)
|
|
6
|
-
|
|
7
|
-
```json
|
|
8
|
-
{
|
|
9
|
-
"model": "sumopod/deepseek-v4-flash",
|
|
10
|
-
"provider": {
|
|
11
|
-
"sumopod": {
|
|
12
|
-
"npm": "@ai-sdk/openai-compatible",
|
|
13
|
-
"name": "Sumopod AI",
|
|
14
|
-
"options": {
|
|
15
|
-
"baseURL": "https://ai.sumopod.com/v1",
|
|
16
|
-
"apiKey": "sk-your-key"
|
|
17
|
-
},
|
|
18
|
-
"models": {
|
|
19
|
-
"deepseek-v4-flash": {
|
|
20
|
-
"name": "DeepSeek V4 Flash",
|
|
21
|
-
"options": {
|
|
22
|
-
"reasoningEffort": "high",
|
|
23
|
-
"textVerbosity": "low"
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## OpenAI
|
|
33
|
-
|
|
34
|
-
```json
|
|
35
|
-
{
|
|
36
|
-
"model": "gpt-4o",
|
|
37
|
-
"provider": {
|
|
38
|
-
"openai": {
|
|
39
|
-
"npm": "@ai-sdk/openai",
|
|
40
|
-
"models": {
|
|
41
|
-
"gpt-4o": { "name": "GPT-4o" },
|
|
42
|
-
"gpt-4o-mini": { "name": "GPT-4o Mini" }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Anthropic (Claude)
|
|
50
|
-
|
|
51
|
-
```json
|
|
52
|
-
{
|
|
53
|
-
"model": "claude-sonnet-4-20250514",
|
|
54
|
-
"provider": {
|
|
55
|
-
"anthropic": {
|
|
56
|
-
"npm": "@ai-sdk/anthropic",
|
|
57
|
-
"models": {
|
|
58
|
-
"claude-sonnet-4-20250514": { "name": "Claude Sonnet 4" },
|
|
59
|
-
"claude-haiku-3-5-20241022": { "name": "Claude Haiku 3.5" }
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Google (Gemini)
|
|
67
|
-
|
|
68
|
-
```json
|
|
69
|
-
{
|
|
70
|
-
"model": "gemini-2.5-flash",
|
|
71
|
-
"provider": {
|
|
72
|
-
"google": {
|
|
73
|
-
"npm": "@ai-sdk/google",
|
|
74
|
-
"models": {
|
|
75
|
-
"gemini-2.5-flash": { "name": "Gemini 2.5 Flash" },
|
|
76
|
-
"gemini-2.5-pro": { "name": "Gemini 2.5 Pro" }
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Agent Assignment Strategy
|
|
84
|
-
|
|
85
|
-
Use **cheaper models** for simple agents, **better models** for complex reasoning:
|
|
86
|
-
|
|
87
|
-
| Agent | Recommended Model | Why |
|
|
88
|
-
|-------|------------------|-----|
|
|
89
|
-
| orchestrator | Cheaper (orchestration, not deep thinking) | Delegates most work |
|
|
90
|
-
| planner | Better (architecture, impact analysis) | Needs deep reasoning |
|
|
91
|
-
| task-manager | Better (implementation, code quality) | Needs to write correct code |
|
|
92
|
-
| code-reviewer | Better (security, edge cases) | Needs sharp analysis |
|
|
93
|
-
| explorer | Cheaper (just searches) | Simple grep/glob |
|
|
94
|
-
| librarian | Cheaper (fetches docs) | Simple fetch operations |
|
|
95
|
-
| learner | Cheaper (analysis after the fact) | Post-processing only |
|
|
96
|
-
| fixer | Cheaper (bounded edits) | Well-defined scope |
|
|
97
|
-
|
|
98
|
-
Example with mixed models:
|
|
99
|
-
|
|
100
|
-
```json
|
|
101
|
-
{
|
|
102
|
-
"agent": {
|
|
103
|
-
"orchestrator": {
|
|
104
|
-
"model": "sumopod/deepseek-v4-flash",
|
|
105
|
-
"fallback_models": ["gpt-4o-mini"]
|
|
106
|
-
},
|
|
107
|
-
"planner": {
|
|
108
|
-
"model": "gpt-4o",
|
|
109
|
-
"fallback_models": ["sumopod/deepseek-v4-flash"]
|
|
110
|
-
},
|
|
111
|
-
"task-manager": {
|
|
112
|
-
"model": "gpt-4o",
|
|
113
|
-
"fallback_models": ["sumopod/deepseek-v4-flash"]
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
```
|