@softspark/ai-toolkit 2.5.0 → 2.6.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/AGENTS.md +1 -1
- package/CHANGELOG.md +34 -0
- package/README.md +19 -3
- package/app/.claude-plugin/plugin.json +3 -2
- package/app/ARCHITECTURE.md +11 -0
- package/app/skills/hipaa-validate/SKILL.md +39 -23
- package/app/skills/hipaa-validate/scripts/hipaa_scan.py +64 -7
- package/bin/ai-toolkit.js +20 -5
- package/kb/reference/opencode-compatibility.md +161 -0
- package/llms-full.txt +168 -1
- package/llms.txt +1 -0
- package/manifest.json +1 -1
- package/package.json +6 -3
- package/scripts/generate_opencode.py +117 -0
- package/scripts/generate_opencode_agents.py +126 -0
- package/scripts/generate_opencode_commands.py +158 -0
- package/scripts/generate_opencode_json.py +133 -0
- package/scripts/generate_opencode_plugin.py +169 -0
- package/scripts/install_steps/ai_tools.py +117 -1
- package/scripts/install_steps/install_state.py +1 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "AI Toolkit - opencode Compatibility"
|
|
3
|
+
category: reference
|
|
4
|
+
service: ai-toolkit
|
|
5
|
+
tags: [opencode, compatibility, install, skills, hooks, mcp, plugins]
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
created: "2026-04-16"
|
|
8
|
+
last_updated: "2026-04-16"
|
|
9
|
+
description: "Reference for how ai-toolkit integrates with opencode — AGENTS.md, subagents, slash commands, JS plugin hook bridge, and MCP merge into opencode.json."
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# AI Toolkit - opencode Compatibility
|
|
13
|
+
|
|
14
|
+
## Summary
|
|
15
|
+
|
|
16
|
+
opencode (https://opencode.ai) is the 11th supported editor. `ai-toolkit install --editors opencode` (or `--editors all`) lays down a full native integration: shared `AGENTS.md`, per-agent `.opencode/agents/` files, per-command `.opencode/commands/` files, a JS plugin bridging toolkit Bash hooks to opencode lifecycle events, and MCP server merge into `opencode.json`.
|
|
17
|
+
|
|
18
|
+
opencode also reads `CLAUDE.md` as a fallback, so a user without the native integration still gets baseline rules. The native path adds subagents, slash commands, hooks, and MCP.
|
|
19
|
+
|
|
20
|
+
## Local Install Outputs
|
|
21
|
+
|
|
22
|
+
`ai-toolkit install --local --editors opencode` generates:
|
|
23
|
+
|
|
24
|
+
- `AGENTS.md` (shared with Codex CLI via distinct marker sections)
|
|
25
|
+
- `.opencode/agents/ai-toolkit-*.md` (one per ai-toolkit agent, `mode: subagent`)
|
|
26
|
+
- `.opencode/commands/ai-toolkit-*.md` (one per user-invocable skill, required `template: |` frontmatter field)
|
|
27
|
+
- `.opencode/plugins/ai-toolkit-hooks.js` (JS plugin bridging Bash hooks)
|
|
28
|
+
- `opencode.json` (MCP key merged from `.mcp.json`, user keys preserved)
|
|
29
|
+
|
|
30
|
+
## Global Install Outputs
|
|
31
|
+
|
|
32
|
+
`ai-toolkit install --editors opencode` (no `--local`) lays down:
|
|
33
|
+
|
|
34
|
+
- `~/.config/opencode/AGENTS.md`
|
|
35
|
+
- `~/.config/opencode/agents/ai-toolkit-*.md`
|
|
36
|
+
- `~/.config/opencode/commands/ai-toolkit-*.md`
|
|
37
|
+
- `~/.config/opencode/plugins/ai-toolkit-hooks.js`
|
|
38
|
+
- `~/.config/opencode/opencode.json` (MCP merge, user keys preserved)
|
|
39
|
+
|
|
40
|
+
Files land directly under `~/.config/opencode/` (no `.opencode/` nesting) because that is the global layout opencode expects per https://opencode.ai/docs/config/. Shared hook scripts stay in `~/.softspark/ai-toolkit/hooks/` and are referenced by the global JS plugin.
|
|
41
|
+
|
|
42
|
+
## Editor Surface Comparison
|
|
43
|
+
|
|
44
|
+
| Feature | Claude Code | Codex CLI | opencode |
|
|
45
|
+
|--------------------|-------------|-----------------|-------------------------------------------|
|
|
46
|
+
| Rules file | `CLAUDE.md` | `AGENTS.md` | `AGENTS.md` + `CLAUDE.md` fallback |
|
|
47
|
+
| Subagents | Yes | No | Yes (`mode: subagent`) |
|
|
48
|
+
| Slash commands | Skills | Adapted skills | Native commands with frontmatter |
|
|
49
|
+
| MCP | Yes | Yes | Yes (`opencode.json`) |
|
|
50
|
+
| Lifecycle hooks | JSON config | `.codex/hooks` | JS/TS plugins (~30+ events) |
|
|
51
|
+
| Global config dir | `~/.claude` | `~/.codex` | `~/.config/opencode` |
|
|
52
|
+
| Project config dir | `.claude` | `.agents` | `.opencode` |
|
|
53
|
+
|
|
54
|
+
## Shared AGENTS.md
|
|
55
|
+
|
|
56
|
+
opencode and Codex CLI both read `AGENTS.md`. The toolkit emits two distinct marker-bounded sections in a single file, so installing both editors does not clobber either. The Codex section is produced by `generate_codex.py`; the opencode section is produced by `generate_opencode.py`. Both sections reuse `codex_skill_adapter.py` because both editors lack Claude-only orchestration primitives (`Agent`, `TeamCreate`, `TaskCreate`).
|
|
57
|
+
|
|
58
|
+
## Subagent Translation Model
|
|
59
|
+
|
|
60
|
+
Each file in `app/agents/*.md` emits a corresponding `.opencode/agents/ai-toolkit-<name>.md` with:
|
|
61
|
+
|
|
62
|
+
- `description` — copied from the source agent frontmatter
|
|
63
|
+
- `mode: subagent` (required)
|
|
64
|
+
- `color` — copied when present
|
|
65
|
+
|
|
66
|
+
The `model` field is deliberately omitted. opencode requires the `provider/model-id` form; ai-toolkit only stores a short alias (`opus`/`sonnet`/`haiku`) which cannot be mapped without assuming a provider. opencode falls back to the user's `default_agent` / top-level `model` config.
|
|
67
|
+
|
|
68
|
+
Opencode treats these files as auto-completable with `@` and can delegate to them from the primary agent.
|
|
69
|
+
|
|
70
|
+
## Slash Command Translation Model
|
|
71
|
+
|
|
72
|
+
Only user-invocable skills (`user-invocable: true` or no `disable-model-invocation`) emit to `.opencode/commands/`. Knowledge skills (`user-invocable: false`) are intentionally skipped — they are not intended as commands.
|
|
73
|
+
|
|
74
|
+
Each command file carries opencode's required `template: |` frontmatter field, built from the SKILL.md body.
|
|
75
|
+
|
|
76
|
+
## Hook Bridge (JS Plugin)
|
|
77
|
+
|
|
78
|
+
`.opencode/plugins/ai-toolkit-hooks.js` is a single-file plugin that maps opencode events to the shared Bash hooks in `~/.softspark/ai-toolkit/hooks/`:
|
|
79
|
+
|
|
80
|
+
| opencode event | Bash hook(s) |
|
|
81
|
+
|----------------------------|--------------------------------------------------------------------|
|
|
82
|
+
| `session.created` | `session-start.sh` + `session-context.sh` + `mcp-health.sh` |
|
|
83
|
+
| `session.compacted` | `pre-compact.sh` + `pre-compact-save.sh` (PreCompact equivalent) |
|
|
84
|
+
| `session.deleted` | `session-end.sh` + `save-session.sh` |
|
|
85
|
+
| `message.updated` | `user-prompt-submit.sh` + `track-usage.sh` |
|
|
86
|
+
| `message.part.updated` | `user-prompt-submit.sh` + `track-usage.sh` |
|
|
87
|
+
| `tool.execute.before` (bash) | `guard-destructive.sh` + `commit-quality.sh` |
|
|
88
|
+
| `tool.execute.after` | `post-tool-use.sh` |
|
|
89
|
+
| `permission.asked` | `guard-destructive.sh` (approval-gate bridge) |
|
|
90
|
+
| `command.executed` | `post-tool-use.sh` |
|
|
91
|
+
|
|
92
|
+
Plugin exports a single named export `AiToolkitHooks` — per opencode docs, named exports only (no default export). Hook scripts are invoked via Bun's `$` with the script path bound as a JS constant; opencode event payloads are passed as JSON on stdin, never interpolated into the shell command, so payload data cannot inject shell metacharacters. The toolkit's `exit 2` semantics for PreToolUse guards are preserved and bubble up as the plugin's return code.
|
|
93
|
+
|
|
94
|
+
**Intentionally unmapped events**: `tui.*`, `lsp.*`, `installation.*`, `session.idle/status/updated/error/diff`, `file.edited`, `file.watcher.updated`, `todo.updated`, `shell.env`, `server.connected`, `message.*.removed`, `experimental.*` — no matching Bash hook in the toolkit, or the event is opencode-UI-only.
|
|
95
|
+
|
|
96
|
+
## MCP Merge (opencode.json)
|
|
97
|
+
|
|
98
|
+
`generate_opencode_json.py` reads `.mcp.json` and merges its servers under the `mcp` key in `opencode.json`:
|
|
99
|
+
|
|
100
|
+
- `local` shape entries are translated to opencode's local command shape.
|
|
101
|
+
- `remote` shape entries are translated to opencode's remote URL shape.
|
|
102
|
+
- User-authored keys in `opencode.json` (outside `mcp`) are preserved.
|
|
103
|
+
- Re-running the generator is idempotent.
|
|
104
|
+
|
|
105
|
+
## Auto-Detection
|
|
106
|
+
|
|
107
|
+
The installer detects opencode as configured when any of these markers exist:
|
|
108
|
+
|
|
109
|
+
- `opencode.json`
|
|
110
|
+
- `.opencode/` directory
|
|
111
|
+
- `.opencode/agents/`
|
|
112
|
+
- `.opencode/commands/`
|
|
113
|
+
- `~/.config/opencode/`
|
|
114
|
+
|
|
115
|
+
`ai-toolkit update` picks up opencode automatically when detection fires.
|
|
116
|
+
|
|
117
|
+
## Uninstall & Reset
|
|
118
|
+
|
|
119
|
+
`scripts/install_steps/ai_tools.py` cleanup only removes ai-toolkit-marked artifacts:
|
|
120
|
+
|
|
121
|
+
- Generated `.opencode/agents/ai-toolkit-*.md`
|
|
122
|
+
- Generated `.opencode/commands/ai-toolkit-*.md`
|
|
123
|
+
- Generated `.opencode/plugins/ai-toolkit-hooks.js`
|
|
124
|
+
- Managed markers from `AGENTS.md`
|
|
125
|
+
- `mcp` key entries injected by the toolkit (user keys preserved)
|
|
126
|
+
|
|
127
|
+
User-authored opencode files and user-authored `opencode.json` keys are never deleted.
|
|
128
|
+
|
|
129
|
+
## Behavioral Limits
|
|
130
|
+
|
|
131
|
+
- opencode does not expose the full Claude hook event surface; only the events in the mapping table above are bridged. Claude-only events (`TaskCompleted`, `TeammateIdle`, `SubagentStart`, `SubagentStop`, `PreCompact`) are silently skipped.
|
|
132
|
+
- Multi-agent orchestration skills (`/orchestrate`, `/workflow`, `/swarm`, `/teams`, `/subagent-development`) run through the Codex adaptation layer — they use opencode subagents and explicit file ownership instead of Claude's `Agent`/`TaskCreate` primitives.
|
|
133
|
+
|
|
134
|
+
## Verification
|
|
135
|
+
|
|
136
|
+
The opencode integration is verified by:
|
|
137
|
+
|
|
138
|
+
1. Generator contract tests for the five `generate_opencode*.py` scripts (bats)
|
|
139
|
+
2. MCP merge idempotency and user-key preservation tests
|
|
140
|
+
3. Plugin export shape and event coverage tests
|
|
141
|
+
4. Auto-detection tests for install / update flow
|
|
142
|
+
5. `validate.py --strict` + `audit_skills.py --ci` in CI
|
|
143
|
+
|
|
144
|
+
## CLI Commands
|
|
145
|
+
|
|
146
|
+
| Command | Description |
|
|
147
|
+
|---------|-------------|
|
|
148
|
+
| `ai-toolkit opencode-md` | Generate `AGENTS.md` body for opencode |
|
|
149
|
+
| `ai-toolkit opencode-agents` | Generate `.opencode/agents/ai-toolkit-*.md` |
|
|
150
|
+
| `ai-toolkit opencode-commands` | Generate `.opencode/commands/ai-toolkit-*.md` |
|
|
151
|
+
| `ai-toolkit opencode-plugin` | Generate `.opencode/plugins/ai-toolkit-hooks.js` |
|
|
152
|
+
| `ai-toolkit opencode-json` | Merge MCP servers into `opencode.json` |
|
|
153
|
+
|
|
154
|
+
## Related
|
|
155
|
+
|
|
156
|
+
- `kb/reference/skills-catalog.md`
|
|
157
|
+
- `kb/reference/agents-catalog.md`
|
|
158
|
+
- `kb/reference/codex-cli-compatibility.md`
|
|
159
|
+
- `kb/reference/architecture-overview.md`
|
|
160
|
+
- `kb/reference/global-install-model.md`
|
|
161
|
+
- `kb/reference/mcp-editor-compatibility.md`
|
package/llms-full.txt
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
- [MCP Editor Compatibility](kb/reference/mcp-editor-compatibility.md)
|
|
45
45
|
- [MCP Server Templates](kb/reference/mcp-templates.md)
|
|
46
46
|
- [Merge-Friendly Install Model](kb/reference/merge-friendly-install-model.md)
|
|
47
|
+
- [AI Toolkit - opencode Compatibility](kb/reference/opencode-compatibility.md)
|
|
47
48
|
- [Plugin Pack Conventions](kb/reference/plugin-pack-conventions.md)
|
|
48
49
|
- [Quick Wins Implementation Summary](kb/reference/quick-wins-implementation-summary.md)
|
|
49
50
|
- [Skill Templates](kb/reference/skill-templates.md)
|
|
@@ -4638,7 +4639,7 @@ Three tiers determine how to approach a task:
|
|
|
4638
4639
|
|
|
4639
4640
|
| Type | Field | Invocation | Count |
|
|
4640
4641
|
|------|-------|-----------|-------|
|
|
4641
|
-
| Task | `disable-model-invocation: true` | User via `/skill` only |
|
|
4642
|
+
| Task | `disable-model-invocation: true` | User via `/skill` only | 31 |
|
|
4642
4643
|
| Hybrid | (neither) | User via `/skill` + agent knowledge | 31 |
|
|
4643
4644
|
| Knowledge | `user-invocable: false` | Claude auto-loads | 32 |
|
|
4644
4645
|
|
|
@@ -8241,6 +8242,172 @@ Project-local setup uses the same preservation approach for files that should re
|
|
|
8241
8242
|
|
|
8242
8243
|
---
|
|
8243
8244
|
|
|
8245
|
+
## kb/reference/opencode-compatibility.md
|
|
8246
|
+
|
|
8247
|
+
---
|
|
8248
|
+
title: "AI Toolkit - opencode Compatibility"
|
|
8249
|
+
category: reference
|
|
8250
|
+
service: ai-toolkit
|
|
8251
|
+
tags: [opencode, compatibility, install, skills, hooks, mcp, plugins]
|
|
8252
|
+
version: "1.0.0"
|
|
8253
|
+
created: "2026-04-16"
|
|
8254
|
+
last_updated: "2026-04-16"
|
|
8255
|
+
description: "Reference for how ai-toolkit integrates with opencode — AGENTS.md, subagents, slash commands, JS plugin hook bridge, and MCP merge into opencode.json."
|
|
8256
|
+
---
|
|
8257
|
+
|
|
8258
|
+
# AI Toolkit - opencode Compatibility
|
|
8259
|
+
|
|
8260
|
+
## Summary
|
|
8261
|
+
|
|
8262
|
+
opencode (https://opencode.ai) is the 11th supported editor. `ai-toolkit install --editors opencode` (or `--editors all`) lays down a full native integration: shared `AGENTS.md`, per-agent `.opencode/agents/` files, per-command `.opencode/commands/` files, a JS plugin bridging toolkit Bash hooks to opencode lifecycle events, and MCP server merge into `opencode.json`.
|
|
8263
|
+
|
|
8264
|
+
opencode also reads `CLAUDE.md` as a fallback, so a user without the native integration still gets baseline rules. The native path adds subagents, slash commands, hooks, and MCP.
|
|
8265
|
+
|
|
8266
|
+
## Local Install Outputs
|
|
8267
|
+
|
|
8268
|
+
`ai-toolkit install --local --editors opencode` generates:
|
|
8269
|
+
|
|
8270
|
+
- `AGENTS.md` (shared with Codex CLI via distinct marker sections)
|
|
8271
|
+
- `.opencode/agents/ai-toolkit-*.md` (one per ai-toolkit agent, `mode: subagent`)
|
|
8272
|
+
- `.opencode/commands/ai-toolkit-*.md` (one per user-invocable skill, required `template: |` frontmatter field)
|
|
8273
|
+
- `.opencode/plugins/ai-toolkit-hooks.js` (JS plugin bridging Bash hooks)
|
|
8274
|
+
- `opencode.json` (MCP key merged from `.mcp.json`, user keys preserved)
|
|
8275
|
+
|
|
8276
|
+
## Global Install Outputs
|
|
8277
|
+
|
|
8278
|
+
`ai-toolkit install --editors opencode` (no `--local`) lays down:
|
|
8279
|
+
|
|
8280
|
+
- `~/.config/opencode/AGENTS.md`
|
|
8281
|
+
- `~/.config/opencode/agents/ai-toolkit-*.md`
|
|
8282
|
+
- `~/.config/opencode/commands/ai-toolkit-*.md`
|
|
8283
|
+
- `~/.config/opencode/plugins/ai-toolkit-hooks.js`
|
|
8284
|
+
- `~/.config/opencode/opencode.json` (MCP merge, user keys preserved)
|
|
8285
|
+
|
|
8286
|
+
Files land directly under `~/.config/opencode/` (no `.opencode/` nesting) because that is the global layout opencode expects per https://opencode.ai/docs/config/. Shared hook scripts stay in `~/.softspark/ai-toolkit/hooks/` and are referenced by the global JS plugin.
|
|
8287
|
+
|
|
8288
|
+
## Editor Surface Comparison
|
|
8289
|
+
|
|
8290
|
+
| Feature | Claude Code | Codex CLI | opencode |
|
|
8291
|
+
|--------------------|-------------|-----------------|-------------------------------------------|
|
|
8292
|
+
| Rules file | `CLAUDE.md` | `AGENTS.md` | `AGENTS.md` + `CLAUDE.md` fallback |
|
|
8293
|
+
| Subagents | Yes | No | Yes (`mode: subagent`) |
|
|
8294
|
+
| Slash commands | Skills | Adapted skills | Native commands with frontmatter |
|
|
8295
|
+
| MCP | Yes | Yes | Yes (`opencode.json`) |
|
|
8296
|
+
| Lifecycle hooks | JSON config | `.codex/hooks` | JS/TS plugins (~30+ events) |
|
|
8297
|
+
| Global config dir | `~/.claude` | `~/.codex` | `~/.config/opencode` |
|
|
8298
|
+
| Project config dir | `.claude` | `.agents` | `.opencode` |
|
|
8299
|
+
|
|
8300
|
+
## Shared AGENTS.md
|
|
8301
|
+
|
|
8302
|
+
opencode and Codex CLI both read `AGENTS.md`. The toolkit emits two distinct marker-bounded sections in a single file, so installing both editors does not clobber either. The Codex section is produced by `generate_codex.py`; the opencode section is produced by `generate_opencode.py`. Both sections reuse `codex_skill_adapter.py` because both editors lack Claude-only orchestration primitives (`Agent`, `TeamCreate`, `TaskCreate`).
|
|
8303
|
+
|
|
8304
|
+
## Subagent Translation Model
|
|
8305
|
+
|
|
8306
|
+
Each file in `app/agents/*.md` emits a corresponding `.opencode/agents/ai-toolkit-<name>.md` with:
|
|
8307
|
+
|
|
8308
|
+
- `description` — copied from the source agent frontmatter
|
|
8309
|
+
- `mode: subagent` (required)
|
|
8310
|
+
- `color` — copied when present
|
|
8311
|
+
|
|
8312
|
+
The `model` field is deliberately omitted. opencode requires the `provider/model-id` form; ai-toolkit only stores a short alias (`opus`/`sonnet`/`haiku`) which cannot be mapped without assuming a provider. opencode falls back to the user's `default_agent` / top-level `model` config.
|
|
8313
|
+
|
|
8314
|
+
Opencode treats these files as auto-completable with `@` and can delegate to them from the primary agent.
|
|
8315
|
+
|
|
8316
|
+
## Slash Command Translation Model
|
|
8317
|
+
|
|
8318
|
+
Only user-invocable skills (`user-invocable: true` or no `disable-model-invocation`) emit to `.opencode/commands/`. Knowledge skills (`user-invocable: false`) are intentionally skipped — they are not intended as commands.
|
|
8319
|
+
|
|
8320
|
+
Each command file carries opencode's required `template: |` frontmatter field, built from the SKILL.md body.
|
|
8321
|
+
|
|
8322
|
+
## Hook Bridge (JS Plugin)
|
|
8323
|
+
|
|
8324
|
+
`.opencode/plugins/ai-toolkit-hooks.js` is a single-file plugin that maps opencode events to the shared Bash hooks in `~/.softspark/ai-toolkit/hooks/`:
|
|
8325
|
+
|
|
8326
|
+
| opencode event | Bash hook(s) |
|
|
8327
|
+
|----------------------------|--------------------------------------------------------------------|
|
|
8328
|
+
| `session.created` | `session-start.sh` + `session-context.sh` + `mcp-health.sh` |
|
|
8329
|
+
| `session.compacted` | `pre-compact.sh` + `pre-compact-save.sh` (PreCompact equivalent) |
|
|
8330
|
+
| `session.deleted` | `session-end.sh` + `save-session.sh` |
|
|
8331
|
+
| `message.updated` | `user-prompt-submit.sh` + `track-usage.sh` |
|
|
8332
|
+
| `message.part.updated` | `user-prompt-submit.sh` + `track-usage.sh` |
|
|
8333
|
+
| `tool.execute.before` (bash) | `guard-destructive.sh` + `commit-quality.sh` |
|
|
8334
|
+
| `tool.execute.after` | `post-tool-use.sh` |
|
|
8335
|
+
| `permission.asked` | `guard-destructive.sh` (approval-gate bridge) |
|
|
8336
|
+
| `command.executed` | `post-tool-use.sh` |
|
|
8337
|
+
|
|
8338
|
+
Plugin exports a single named export `AiToolkitHooks` — per opencode docs, named exports only (no default export). Hook scripts are invoked via Bun's `$` with the script path bound as a JS constant; opencode event payloads are passed as JSON on stdin, never interpolated into the shell command, so payload data cannot inject shell metacharacters. The toolkit's `exit 2` semantics for PreToolUse guards are preserved and bubble up as the plugin's return code.
|
|
8339
|
+
|
|
8340
|
+
**Intentionally unmapped events**: `tui.*`, `lsp.*`, `installation.*`, `session.idle/status/updated/error/diff`, `file.edited`, `file.watcher.updated`, `todo.updated`, `shell.env`, `server.connected`, `message.*.removed`, `experimental.*` — no matching Bash hook in the toolkit, or the event is opencode-UI-only.
|
|
8341
|
+
|
|
8342
|
+
## MCP Merge (opencode.json)
|
|
8343
|
+
|
|
8344
|
+
`generate_opencode_json.py` reads `.mcp.json` and merges its servers under the `mcp` key in `opencode.json`:
|
|
8345
|
+
|
|
8346
|
+
- `local` shape entries are translated to opencode's local command shape.
|
|
8347
|
+
- `remote` shape entries are translated to opencode's remote URL shape.
|
|
8348
|
+
- User-authored keys in `opencode.json` (outside `mcp`) are preserved.
|
|
8349
|
+
- Re-running the generator is idempotent.
|
|
8350
|
+
|
|
8351
|
+
## Auto-Detection
|
|
8352
|
+
|
|
8353
|
+
The installer detects opencode as configured when any of these markers exist:
|
|
8354
|
+
|
|
8355
|
+
- `opencode.json`
|
|
8356
|
+
- `.opencode/` directory
|
|
8357
|
+
- `.opencode/agents/`
|
|
8358
|
+
- `.opencode/commands/`
|
|
8359
|
+
- `~/.config/opencode/`
|
|
8360
|
+
|
|
8361
|
+
`ai-toolkit update` picks up opencode automatically when detection fires.
|
|
8362
|
+
|
|
8363
|
+
## Uninstall & Reset
|
|
8364
|
+
|
|
8365
|
+
`scripts/install_steps/ai_tools.py` cleanup only removes ai-toolkit-marked artifacts:
|
|
8366
|
+
|
|
8367
|
+
- Generated `.opencode/agents/ai-toolkit-*.md`
|
|
8368
|
+
- Generated `.opencode/commands/ai-toolkit-*.md`
|
|
8369
|
+
- Generated `.opencode/plugins/ai-toolkit-hooks.js`
|
|
8370
|
+
- Managed markers from `AGENTS.md`
|
|
8371
|
+
- `mcp` key entries injected by the toolkit (user keys preserved)
|
|
8372
|
+
|
|
8373
|
+
User-authored opencode files and user-authored `opencode.json` keys are never deleted.
|
|
8374
|
+
|
|
8375
|
+
## Behavioral Limits
|
|
8376
|
+
|
|
8377
|
+
- opencode does not expose the full Claude hook event surface; only the events in the mapping table above are bridged. Claude-only events (`TaskCompleted`, `TeammateIdle`, `SubagentStart`, `SubagentStop`, `PreCompact`) are silently skipped.
|
|
8378
|
+
- Multi-agent orchestration skills (`/orchestrate`, `/workflow`, `/swarm`, `/teams`, `/subagent-development`) run through the Codex adaptation layer — they use opencode subagents and explicit file ownership instead of Claude's `Agent`/`TaskCreate` primitives.
|
|
8379
|
+
|
|
8380
|
+
## Verification
|
|
8381
|
+
|
|
8382
|
+
The opencode integration is verified by:
|
|
8383
|
+
|
|
8384
|
+
1. Generator contract tests for the five `generate_opencode*.py` scripts (bats)
|
|
8385
|
+
2. MCP merge idempotency and user-key preservation tests
|
|
8386
|
+
3. Plugin export shape and event coverage tests
|
|
8387
|
+
4. Auto-detection tests for install / update flow
|
|
8388
|
+
5. `validate.py --strict` + `audit_skills.py --ci` in CI
|
|
8389
|
+
|
|
8390
|
+
## CLI Commands
|
|
8391
|
+
|
|
8392
|
+
| Command | Description |
|
|
8393
|
+
|---------|-------------|
|
|
8394
|
+
| `ai-toolkit opencode-md` | Generate `AGENTS.md` body for opencode |
|
|
8395
|
+
| `ai-toolkit opencode-agents` | Generate `.opencode/agents/ai-toolkit-*.md` |
|
|
8396
|
+
| `ai-toolkit opencode-commands` | Generate `.opencode/commands/ai-toolkit-*.md` |
|
|
8397
|
+
| `ai-toolkit opencode-plugin` | Generate `.opencode/plugins/ai-toolkit-hooks.js` |
|
|
8398
|
+
| `ai-toolkit opencode-json` | Merge MCP servers into `opencode.json` |
|
|
8399
|
+
|
|
8400
|
+
## Related
|
|
8401
|
+
|
|
8402
|
+
- `kb/reference/skills-catalog.md`
|
|
8403
|
+
- `kb/reference/agents-catalog.md`
|
|
8404
|
+
- `kb/reference/codex-cli-compatibility.md`
|
|
8405
|
+
- `kb/reference/architecture-overview.md`
|
|
8406
|
+
- `kb/reference/global-install-model.md`
|
|
8407
|
+
- `kb/reference/mcp-editor-compatibility.md`
|
|
8408
|
+
|
|
8409
|
+
---
|
|
8410
|
+
|
|
8244
8411
|
## kb/reference/plugin-pack-conventions.md
|
|
8245
8412
|
|
|
8246
8413
|
---
|
package/llms.txt
CHANGED
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
- [MCP Editor Compatibility](kb/reference/mcp-editor-compatibility.md)
|
|
45
45
|
- [MCP Server Templates](kb/reference/mcp-templates.md)
|
|
46
46
|
- [Merge-Friendly Install Model](kb/reference/merge-friendly-install-model.md)
|
|
47
|
+
- [AI Toolkit - opencode Compatibility](kb/reference/opencode-compatibility.md)
|
|
47
48
|
- [Plugin Pack Conventions](kb/reference/plugin-pack-conventions.md)
|
|
48
49
|
- [Quick Wins Implementation Summary](kb/reference/quick-wins-implementation-summary.md)
|
|
49
50
|
- [Skill Templates](kb/reference/skill-templates.md)
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softspark/ai-toolkit",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Professional-grade AI coding toolkit: 94 skills, 44 agents, multi-platform support (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, Augment, Google Antigravity, Codex CLI), machine-enforced safety constitution, persona presets, skill security auditor, expanded lifecycle hooks, 11 plugin packs, and benchmark tooling.",
|
|
3
|
+
"version": "2.6.1",
|
|
4
|
+
"description": "Professional-grade AI coding toolkit: 94 skills, 44 agents, multi-platform support (Claude, Cursor, Windsurf, Copilot, Gemini, Cline, Roo Code, Aider, Augment, Google Antigravity, Codex CLI, opencode), machine-enforced safety constitution, persona presets, skill security auditor, expanded lifecycle hooks, 11 plugin packs, and benchmark tooling.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
7
7
|
"claude-code",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"augment",
|
|
24
24
|
"antigravity",
|
|
25
25
|
"google-antigravity",
|
|
26
|
+
"opencode",
|
|
26
27
|
"multi-platform"
|
|
27
28
|
],
|
|
28
29
|
"homepage": "https://github.com/softspark/ai-toolkit",
|
|
@@ -56,7 +57,9 @@
|
|
|
56
57
|
"generate:roo": "python3 scripts/generate_roo_modes.py > .roomodes",
|
|
57
58
|
"generate:aider": "python3 scripts/generate_aider_conf.py > .aider.conf.yml",
|
|
58
59
|
"generate:codex-rules": "python3 scripts/generate_codex_rules.py .",
|
|
59
|
-
"generate:
|
|
60
|
+
"generate:opencode-agents": "python3 scripts/generate_opencode_agents.py .",
|
|
61
|
+
"generate:opencode-commands": "python3 scripts/generate_opencode_commands.py .",
|
|
62
|
+
"generate:all": "npm run generate:agents && npm run generate:codex-rules && npm run generate:opencode-agents && npm run generate:opencode-commands && npm run generate:cursor && npm run generate:windsurf && npm run generate:copilot && npm run generate:gemini && npm run generate:cline && npm run generate:roo && npm run generate:aider && npm run generate:llms"
|
|
60
63
|
},
|
|
61
64
|
"files": [
|
|
62
65
|
"bin/",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate AGENTS.md content for opencode (https://opencode.ai).
|
|
3
|
+
|
|
4
|
+
opencode reads AGENTS.md using the same convention as OpenAI Codex CLI.
|
|
5
|
+
The generated file is safe for both editors to consume from the same
|
|
6
|
+
project root — each injects into its own marker-wrapped block.
|
|
7
|
+
|
|
8
|
+
Usage: ./scripts/generate_opencode.py > AGENTS.md
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import sys
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
16
|
+
from codex_skill_adapter import codex_skill_description
|
|
17
|
+
from emission import (
|
|
18
|
+
agents_dir,
|
|
19
|
+
skills_dir,
|
|
20
|
+
generate_quality_standards,
|
|
21
|
+
generate_workflow_guidelines,
|
|
22
|
+
print_toolkit_end,
|
|
23
|
+
print_toolkit_start,
|
|
24
|
+
)
|
|
25
|
+
from frontmatter import frontmatter_field
|
|
26
|
+
from paths import RULES_DIR
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _emit_agents() -> str:
|
|
30
|
+
"""Emit agents as opencode subagent bullets."""
|
|
31
|
+
lines: list[str] = []
|
|
32
|
+
for agent_file in sorted(agents_dir.glob("*.md")):
|
|
33
|
+
name = frontmatter_field(agent_file, "name")
|
|
34
|
+
description = frontmatter_field(agent_file, "description")
|
|
35
|
+
if not name or not description:
|
|
36
|
+
continue
|
|
37
|
+
lines.append(f"- **{name}**: {description}")
|
|
38
|
+
return "\n".join(lines)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _emit_skills() -> str:
|
|
42
|
+
"""Emit user-invocable skills as opencode command bullets.
|
|
43
|
+
|
|
44
|
+
Adapts Claude orchestration-only descriptions via the Codex adapter —
|
|
45
|
+
opencode, like Codex, lacks Claude's Agent/Team/Task primitives so the
|
|
46
|
+
same translation layer applies.
|
|
47
|
+
"""
|
|
48
|
+
lines: list[str] = []
|
|
49
|
+
for skill_dir in sorted(skills_dir.iterdir()):
|
|
50
|
+
if skill_dir.name.startswith("_"):
|
|
51
|
+
continue
|
|
52
|
+
skill_file = skill_dir / "SKILL.md"
|
|
53
|
+
if not skill_file.is_file():
|
|
54
|
+
continue
|
|
55
|
+
name = frontmatter_field(skill_file, "name")
|
|
56
|
+
description = codex_skill_description(skill_file)
|
|
57
|
+
if not name or not description:
|
|
58
|
+
continue
|
|
59
|
+
lines.append(f"- **{name}**: {description}")
|
|
60
|
+
return "\n".join(lines)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def main() -> None:
|
|
64
|
+
print_toolkit_start()
|
|
65
|
+
|
|
66
|
+
print("# AI Toolkit — opencode Configuration")
|
|
67
|
+
print()
|
|
68
|
+
print(
|
|
69
|
+
"Shared AI development toolkit with specialized subagents,"
|
|
70
|
+
" opencode-compatible commands, quality hooks, and a safety constitution."
|
|
71
|
+
)
|
|
72
|
+
print()
|
|
73
|
+
print(
|
|
74
|
+
"opencode reads this file at session start. Subagents are also"
|
|
75
|
+
" installed under `.opencode/agents/` and slash commands under"
|
|
76
|
+
" `.opencode/commands/` for native `@` and `/` autocomplete."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Agents
|
|
80
|
+
print()
|
|
81
|
+
print("## Available Subagents")
|
|
82
|
+
print()
|
|
83
|
+
print("Invoke with `@<name>` in opencode, or delegate via `spawn_agent`:")
|
|
84
|
+
print()
|
|
85
|
+
print(_emit_agents())
|
|
86
|
+
|
|
87
|
+
# Skills / slash commands
|
|
88
|
+
print()
|
|
89
|
+
print("## Available Commands")
|
|
90
|
+
print()
|
|
91
|
+
print("Invoke with `/<name>` in opencode. Knowledge-only skills load automatically:")
|
|
92
|
+
print()
|
|
93
|
+
print(_emit_skills())
|
|
94
|
+
|
|
95
|
+
# Guidelines
|
|
96
|
+
print()
|
|
97
|
+
print(generate_quality_standards())
|
|
98
|
+
print()
|
|
99
|
+
print(generate_workflow_guidelines())
|
|
100
|
+
|
|
101
|
+
print_toolkit_end()
|
|
102
|
+
|
|
103
|
+
# Registered custom rules from ~/.softspark/ai-toolkit/rules/
|
|
104
|
+
if RULES_DIR.is_dir():
|
|
105
|
+
for rule_file in sorted(RULES_DIR.glob("*.md")):
|
|
106
|
+
rule_name = rule_file.stem
|
|
107
|
+
print()
|
|
108
|
+
print(f"<!-- TOOLKIT:{rule_name} START -->")
|
|
109
|
+
print("<!-- Auto-injected by ai-toolkit. Re-run to update. -->")
|
|
110
|
+
print()
|
|
111
|
+
print(rule_file.read_text(encoding="utf-8").rstrip())
|
|
112
|
+
print()
|
|
113
|
+
print(f"<!-- TOOLKIT:{rule_name} END -->")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if __name__ == "__main__":
|
|
117
|
+
main()
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate .opencode/agents/*.md files for opencode (https://opencode.ai).
|
|
3
|
+
|
|
4
|
+
Each ai-toolkit agent becomes an opencode subagent with frontmatter:
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
description: "..."
|
|
8
|
+
mode: subagent
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<body from agent file>
|
|
12
|
+
|
|
13
|
+
Generated files are prefixed ``ai-toolkit-`` so they never collide with
|
|
14
|
+
user-authored opencode agents and can be cleanly removed on uninstall.
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
python3 scripts/generate_opencode_agents.py [target-dir]
|
|
18
|
+
|
|
19
|
+
Writes files to target-dir/.opencode/agents/.
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import sys
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
27
|
+
from emission import agents_dir
|
|
28
|
+
from frontmatter import frontmatter_field
|
|
29
|
+
|
|
30
|
+
AGENT_PREFIX = "ai-toolkit-"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _agent_body(agent_file: Path) -> str:
|
|
34
|
+
"""Return the markdown body of an agent file (content after frontmatter)."""
|
|
35
|
+
text = agent_file.read_text(encoding="utf-8")
|
|
36
|
+
if not text.startswith("---"):
|
|
37
|
+
return text.strip() + "\n"
|
|
38
|
+
# Skip first frontmatter block
|
|
39
|
+
parts = text.split("---", 2)
|
|
40
|
+
if len(parts) < 3:
|
|
41
|
+
return text.strip() + "\n"
|
|
42
|
+
return parts[2].lstrip("\n")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _render_opencode_agent(agent_file: Path) -> str:
|
|
46
|
+
"""Render a single opencode subagent .md file from an ai-toolkit agent."""
|
|
47
|
+
name = frontmatter_field(agent_file, "name")
|
|
48
|
+
description = frontmatter_field(agent_file, "description")
|
|
49
|
+
model = frontmatter_field(agent_file, "model")
|
|
50
|
+
color = frontmatter_field(agent_file, "color")
|
|
51
|
+
|
|
52
|
+
# Escape description for YAML quoted string
|
|
53
|
+
safe_desc = description.replace('"', "'")
|
|
54
|
+
|
|
55
|
+
lines: list[str] = ["---"]
|
|
56
|
+
lines.append(f'description: "{safe_desc}"')
|
|
57
|
+
lines.append("mode: subagent")
|
|
58
|
+
# opencode requires `provider/model-id` for the `model` field. ai-toolkit
|
|
59
|
+
# only stores a short alias (opus/sonnet/haiku) which is not mappable
|
|
60
|
+
# without assuming a provider, so we deliberately omit it — opencode falls
|
|
61
|
+
# back to the user's `default_agent` / top-level `model` config.
|
|
62
|
+
_ = model # intentionally unused
|
|
63
|
+
if color:
|
|
64
|
+
lines.append(f"color: {color}")
|
|
65
|
+
lines.append("---")
|
|
66
|
+
lines.append("")
|
|
67
|
+
body = _agent_body(agent_file).rstrip()
|
|
68
|
+
if body:
|
|
69
|
+
lines.append(body)
|
|
70
|
+
lines.append("")
|
|
71
|
+
return "\n".join(lines)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _cleanup_stale(agents_out: Path) -> int:
|
|
75
|
+
"""Remove stale ai-toolkit-* agent files whose source no longer exists."""
|
|
76
|
+
if not agents_out.is_dir():
|
|
77
|
+
return 0
|
|
78
|
+
removed = 0
|
|
79
|
+
for f in sorted(agents_out.glob(f"{AGENT_PREFIX}*.md")):
|
|
80
|
+
source_name = f.stem[len(AGENT_PREFIX):]
|
|
81
|
+
source = agents_dir / f"{source_name}.md"
|
|
82
|
+
if not source.is_file():
|
|
83
|
+
f.unlink()
|
|
84
|
+
removed += 1
|
|
85
|
+
return removed
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def generate(
|
|
89
|
+
target_dir: Path, config_root: Path | None = None
|
|
90
|
+
) -> tuple[int, int]:
|
|
91
|
+
"""Write opencode agent files and return (written, removed_stale).
|
|
92
|
+
|
|
93
|
+
By default writes to ``target_dir/.opencode/agents/`` (project-local).
|
|
94
|
+
Pass ``config_root=~/.config/opencode`` for the global layout, which
|
|
95
|
+
lives directly under ``agents/`` (no ``.opencode/`` prefix).
|
|
96
|
+
"""
|
|
97
|
+
base = config_root if config_root is not None else target_dir / ".opencode"
|
|
98
|
+
agents_out = base / "agents"
|
|
99
|
+
agents_out.mkdir(parents=True, exist_ok=True)
|
|
100
|
+
|
|
101
|
+
written = 0
|
|
102
|
+
for agent_file in sorted(agents_dir.glob("*.md")):
|
|
103
|
+
name = frontmatter_field(agent_file, "name")
|
|
104
|
+
description = frontmatter_field(agent_file, "description")
|
|
105
|
+
if not name or not description:
|
|
106
|
+
continue
|
|
107
|
+
out_path = agents_out / f"{AGENT_PREFIX}{name}.md"
|
|
108
|
+
out_path.write_text(_render_opencode_agent(agent_file), encoding="utf-8")
|
|
109
|
+
written += 1
|
|
110
|
+
|
|
111
|
+
removed = _cleanup_stale(agents_out)
|
|
112
|
+
return written, removed
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def main() -> None:
|
|
116
|
+
target = Path(sys.argv[1]) if len(sys.argv) > 1 else Path.cwd()
|
|
117
|
+
written, removed = generate(target)
|
|
118
|
+
msg = f"Generated: .opencode/agents/ ({written} agents"
|
|
119
|
+
if removed:
|
|
120
|
+
msg += f", {removed} stale removed"
|
|
121
|
+
msg += ")"
|
|
122
|
+
print(msg)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
main()
|