@softspark/ai-toolkit 4.5.0 → 4.6.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/AGENTS.md +50 -0
- package/CHANGELOG.md +37 -0
- package/README.md +10 -10
- package/app/.claude-plugin/plugin.json +1 -1
- package/app/hooks/loop-guard.sh +2 -1
- package/benchmarks/ecosystem-doctor-snapshot.json +67 -54
- package/bin/ai-toolkit.js +2 -5
- package/kb/procedures/release-preparation-sop.md +24 -16
- package/kb/procedures/release-verification-sop.md +3 -5
- package/kb/reference/architecture-overview.md +2 -3
- package/kb/reference/cli-reference.md +2 -3
- package/kb/reference/global-install-model.md +3 -3
- package/kb/reference/opencode-compatibility.md +2 -2
- package/kb/reference/supported-tools-registry.md +20 -18
- package/llms-full.txt +57 -51
- package/manifest.json +1 -1
- package/package.json +2 -3
- package/scripts/ecosystem_tools.json +18 -15
- package/scripts/generate_antigravity.py +11 -7
- package/scripts/generate_augment_agents.py +9 -10
- package/scripts/generate_augment_commands.py +4 -17
- package/scripts/generate_augment_hooks.py +7 -5
- package/scripts/generate_codex.py +28 -0
- package/scripts/generate_codex_hooks.py +23 -1
- package/scripts/generate_cursor_agents.py +13 -29
- package/scripts/generate_opencode_commands.py +9 -9
- package/scripts/install.py +1 -1
- package/scripts/install_steps/ai_tools.py +47 -26
- package/scripts/plugin.py +2 -2
- package/scripts/generate_codex_rules.py +0 -52
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
3
|
"description": "Authoritative registry of tools ai-toolkit integrates with. Consumed by scripts/ecosystem_doctor.py to detect upstream doc/version drift.",
|
|
4
|
-
"last_updated": "2026-05
|
|
4
|
+
"last_updated": "2026-06-05",
|
|
5
5
|
"tools": [
|
|
6
6
|
{
|
|
7
7
|
"id": "claude-code",
|
|
8
8
|
"display_name": "Claude Code",
|
|
9
9
|
"kind": "primary",
|
|
10
10
|
"urls": {
|
|
11
|
-
"docs": "https://
|
|
11
|
+
"docs": "https://code.claude.com/docs",
|
|
12
12
|
"release_notes": "https://github.com/anthropics/claude-code/releases",
|
|
13
|
-
"changelog":
|
|
13
|
+
"changelog": "https://code.claude.com/docs/en/changelog"
|
|
14
14
|
},
|
|
15
15
|
"config_paths": [
|
|
16
16
|
"~/.claude/settings.json",
|
|
@@ -97,6 +97,8 @@
|
|
|
97
97
|
"our_generators": [
|
|
98
98
|
"scripts/generate_cursor_rules.py",
|
|
99
99
|
"scripts/generate_cursor_mdc.py",
|
|
100
|
+
"scripts/generate_cursor_hooks.py",
|
|
101
|
+
"scripts/generate_cursor_agents.py",
|
|
100
102
|
"scripts/generate_cursor_skills.py"
|
|
101
103
|
],
|
|
102
104
|
"capability_markers": [
|
|
@@ -118,9 +120,9 @@
|
|
|
118
120
|
"display_name": "Windsurf",
|
|
119
121
|
"kind": "editor",
|
|
120
122
|
"urls": {
|
|
121
|
-
"docs": "https://docs.
|
|
122
|
-
"release_notes": "https://
|
|
123
|
-
"changelog": "https://
|
|
123
|
+
"docs": "https://docs.devin.ai/desktop",
|
|
124
|
+
"release_notes": "https://docs.devin.ai/desktop/changelog",
|
|
125
|
+
"changelog": "https://docs.devin.ai/desktop/changelog"
|
|
124
126
|
},
|
|
125
127
|
"config_paths": [
|
|
126
128
|
".windsurfrules",
|
|
@@ -219,12 +221,12 @@
|
|
|
219
221
|
"BeforeModel",
|
|
220
222
|
"SessionStart",
|
|
221
223
|
"SessionEnd",
|
|
222
|
-
"Stop",
|
|
223
224
|
"SKILL.md",
|
|
224
225
|
"activate_skill",
|
|
225
226
|
"custom commands",
|
|
226
227
|
"gemini-extension.json"
|
|
227
228
|
],
|
|
229
|
+
"status_note": "Gemini CLI drops free + paid (AI Pro/Ultra) tiers on 2026-06-18 in favor of the new Antigravity CLI (we ship generate_antigravity.py); enterprise Gemini Code Assist Standard/Enterprise keeps full Gemini CLI support. The .gemini/* generators remain valid for the enterprise audience.",
|
|
228
230
|
"version_probe": {
|
|
229
231
|
"kind": "command",
|
|
230
232
|
"command": "gemini --version"
|
|
@@ -242,12 +244,11 @@
|
|
|
242
244
|
"config_paths": [
|
|
243
245
|
".clinerules/*.md",
|
|
244
246
|
".clinerules/workflows/*.md",
|
|
245
|
-
".
|
|
246
|
-
".
|
|
247
|
+
".clinerules/skills/*/SKILL.md",
|
|
248
|
+
".clinerules/hooks/",
|
|
247
249
|
".cline/skills/*/SKILL.md",
|
|
248
|
-
"~/.cline/rules/*.md",
|
|
249
|
-
"~/.cline/hooks/",
|
|
250
250
|
"~/.cline/skills/*/SKILL.md",
|
|
251
|
+
"~/Documents/Cline/Rules/Hooks/",
|
|
251
252
|
"~/.cline/data/settings/cline_mcp_settings.json",
|
|
252
253
|
".claude/skills/*/SKILL.md"
|
|
253
254
|
],
|
|
@@ -275,10 +276,12 @@
|
|
|
275
276
|
"display_name": "Roo Code",
|
|
276
277
|
"kind": "editor",
|
|
277
278
|
"urls": {
|
|
278
|
-
"docs": "https://
|
|
279
|
+
"docs": "https://roocodeinc.github.io/Roo-Code",
|
|
279
280
|
"release_notes": "https://github.com/RooCodeInc/Roo-Code/releases",
|
|
280
281
|
"changelog": null
|
|
281
282
|
},
|
|
283
|
+
"status": "archived",
|
|
284
|
+
"status_note": "Upstream RooCodeInc/Roo-Code repo archived/read-only as of 2026-05-15, frozen at v3.54.0; docs.roocode.com 301-redirects to roocodeinc.github.io/Roo-Code. A community fork reportedly continues maintenance. JSON .roomodes is NOT deprecated; both generators remain valid.",
|
|
282
285
|
"config_paths": [
|
|
283
286
|
".roomodes",
|
|
284
287
|
".roo/rules/*.md",
|
|
@@ -399,6 +402,8 @@
|
|
|
399
402
|
"changelog": null
|
|
400
403
|
},
|
|
401
404
|
"config_paths": [
|
|
405
|
+
".agents/rules/*.md",
|
|
406
|
+
".agents/workflows/*.md",
|
|
402
407
|
".agent/rules/*.md",
|
|
403
408
|
".agent/workflows/*.md",
|
|
404
409
|
".agent/skills/*/SKILL.md",
|
|
@@ -427,20 +432,18 @@
|
|
|
427
432
|
"display_name": "Codex CLI",
|
|
428
433
|
"kind": "editor",
|
|
429
434
|
"urls": {
|
|
430
|
-
"docs": "https://
|
|
435
|
+
"docs": "https://developers.openai.com/codex",
|
|
431
436
|
"release_notes": "https://github.com/openai/codex/releases",
|
|
432
437
|
"changelog": null
|
|
433
438
|
},
|
|
434
439
|
"config_paths": [
|
|
435
440
|
"AGENTS.md",
|
|
436
|
-
".agents/rules/*.md",
|
|
437
441
|
".agents/skills/*/SKILL.md",
|
|
438
442
|
".codex/hooks.json",
|
|
439
443
|
"~/.codex/config.toml"
|
|
440
444
|
],
|
|
441
445
|
"our_generators": [
|
|
442
446
|
"scripts/generate_codex.py",
|
|
443
|
-
"scripts/generate_codex_rules.py",
|
|
444
447
|
"scripts/generate_codex_hooks.py",
|
|
445
448
|
"scripts/generate_codex_skills.py"
|
|
446
449
|
],
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Generate Antigravity IDE ``.
|
|
2
|
+
"""Generate Antigravity IDE ``.agents/rules/``, ``.agents/workflows/``, and
|
|
3
3
|
skill pointer files.
|
|
4
4
|
|
|
5
|
+
Antigravity 2.0 reads rules/workflows from the plural ``.agents/`` directory by
|
|
6
|
+
default; singular ``.agent/`` is still accepted as a backward-compatible
|
|
7
|
+
fallback (Antigravity checks plural first, then singular). We emit plural.
|
|
5
8
|
Antigravity reads rules from:
|
|
6
9
|
* ``GEMINI.md`` (highest priority) — generated by ``generate_gemini.py``
|
|
7
10
|
* ``AGENTS.md`` (cross-tool) — generated by ``generate_agents_md.py``
|
|
8
|
-
* ``.
|
|
9
|
-
* ``.
|
|
11
|
+
* ``.agents/rules/*.md`` — per-category rule files (this generator)
|
|
12
|
+
* ``.agents/workflows/*.md`` — workflow templates (this generator)
|
|
10
13
|
|
|
11
14
|
Antigravity also supports the Agent Skills standard via ``.agent/skills/
|
|
12
15
|
<skill-name>/SKILL.md`` (the changelog entry "Agent Skills now available in
|
|
@@ -19,7 +22,8 @@ that teaches Antigravity to look up the real catalogue in
|
|
|
19
22
|
Usage:
|
|
20
23
|
python3 scripts/generate_antigravity.py [target-dir]
|
|
21
24
|
|
|
22
|
-
Writes
|
|
25
|
+
Writes rules/workflows to target-dir/.agents/{rules,workflows}/ and the skill
|
|
26
|
+
pointer to target-dir/.agent/skills/ (skills location is unchanged upstream).
|
|
23
27
|
"""
|
|
24
28
|
from __future__ import annotations
|
|
25
29
|
|
|
@@ -93,7 +97,7 @@ def generate(target_dir: Path, *,
|
|
|
93
97
|
language_modules: list[str] | None = None,
|
|
94
98
|
rules_dir: Path | None = None,
|
|
95
99
|
emit_skill_pointer: bool = True) -> None:
|
|
96
|
-
"""Write ``.
|
|
100
|
+
"""Write ``.agents/rules/``, ``.agents/workflows/``, and ``.agent/skills/``.
|
|
97
101
|
|
|
98
102
|
``emit_skill_pointer`` controls whether the pointer SKILL.md is written.
|
|
99
103
|
Set to ``False`` if you manage ``.agent/skills/`` yourself.
|
|
@@ -101,8 +105,8 @@ def generate(target_dir: Path, *,
|
|
|
101
105
|
rules = dict(STANDARD_RULES)
|
|
102
106
|
rules.update(build_language_rules(language_modules))
|
|
103
107
|
rules.update(build_registered_rules(rules_dir))
|
|
104
|
-
write_rules(target_dir, rules, ".
|
|
105
|
-
write_rules(target_dir, STANDARD_WORKFLOWS, ".
|
|
108
|
+
write_rules(target_dir, rules, ".agents/rules")
|
|
109
|
+
write_rules(target_dir, STANDARD_WORKFLOWS, ".agents/workflows")
|
|
106
110
|
if emit_skill_pointer:
|
|
107
111
|
_write_skill_pointer(target_dir)
|
|
108
112
|
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"""Generate ``.augment/agents/ai-toolkit-*.md`` files for Augment Code.
|
|
3
3
|
|
|
4
4
|
Each ai-toolkit agent in ``app/agents/`` is mirrored as an Augment native
|
|
5
|
-
subagent. Augment's subagent frontmatter (per docs.augmentcode.com)
|
|
5
|
+
subagent. Augment's subagent frontmatter (per docs.augmentcode.com/cli/subagents)
|
|
6
|
+
documents: name, description, color, model, tools, disabled_tools.
|
|
6
7
|
|
|
7
8
|
---
|
|
8
9
|
name: <slug>
|
|
9
10
|
description: "<single-line description>"
|
|
10
|
-
model: inherit # or explicit model id
|
|
11
11
|
color: <color-name> # optional UI hint
|
|
12
12
|
tools: [Read, Write, ...]
|
|
13
13
|
disabled_tools: []
|
|
@@ -17,9 +17,10 @@ subagent. Augment's subagent frontmatter (per docs.augmentcode.com) supports:
|
|
|
17
17
|
|
|
18
18
|
Design choices:
|
|
19
19
|
|
|
20
|
-
* ``model
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
* ``model`` is omitted. The docs state "If not specified, the CLI default model
|
|
21
|
+
is used" and do not document ``inherit`` as a value. ai-toolkit stores short
|
|
22
|
+
aliases (``opus``/``sonnet``/``haiku``) that do not map to Augment's full
|
|
23
|
+
model ids, so we omit the field to defer to the CLI default.
|
|
23
24
|
* ``tools`` are passed through verbatim from the source file, normalized into
|
|
24
25
|
YAML flow-list form (``[Read, Write, ...]``) so Augment parses them as a
|
|
25
26
|
native list.
|
|
@@ -79,11 +80,9 @@ def _render_augment_agent(agent_file: Path) -> str:
|
|
|
79
80
|
lines: list[str] = ["---"]
|
|
80
81
|
lines.append(f"name: {name}")
|
|
81
82
|
lines.append(f'description: "{safe_desc}"')
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# we deliberately emit ``inherit`` instead of translating.
|
|
86
|
-
lines.append("model: inherit")
|
|
83
|
+
# `model` is omitted: Augment's docs say the CLI default model is used when
|
|
84
|
+
# absent, and `inherit` is not a documented value. Our short aliases do not
|
|
85
|
+
# map to Augment's provider-qualified ids, so we defer to the CLI default.
|
|
87
86
|
if color:
|
|
88
87
|
lines.append(f"color: {color}")
|
|
89
88
|
if tools:
|
|
@@ -5,13 +5,13 @@ User-invocable skills become Augment custom slash commands. Knowledge skills
|
|
|
5
5
|
(``user-invocable: false``) are excluded — they load automatically via
|
|
6
6
|
AGENTS.md/rules context instead of ``/`` invocation.
|
|
7
7
|
|
|
8
|
-
Per docs.augmentcode.com, Augment custom commands are plain
|
|
9
|
-
with an optional YAML frontmatter header. The body of the file IS
|
|
10
|
-
(no ``template:`` field, no TOML).
|
|
8
|
+
Per docs.augmentcode.com/cli/custom-commands, Augment custom commands are plain
|
|
9
|
+
markdown files with an optional YAML frontmatter header. The body of the file IS
|
|
10
|
+
the prompt (no ``template:`` field, no TOML). The documented frontmatter fields
|
|
11
|
+
are ``description``, ``argument-hint``, and ``model`` (no ``agent`` field):
|
|
11
12
|
|
|
12
13
|
---
|
|
13
14
|
description: "<short one-liner shown in the palette>"
|
|
14
|
-
agent: <optional agent slug to route into>
|
|
15
15
|
argument-hint: "<optional hint shown after the command name>"
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -44,20 +44,9 @@ def _skill_body(skill_file: Path) -> str:
|
|
|
44
44
|
return parts[2].lstrip("\n") if len(parts) >= 3 else text
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
def _map_agent_name(value: str) -> str:
|
|
48
|
-
"""Map ai-toolkit agent names to our prefixed Augment subagent slugs."""
|
|
49
|
-
value = value.strip()
|
|
50
|
-
if not value:
|
|
51
|
-
return value
|
|
52
|
-
if value.startswith(COMMAND_PREFIX):
|
|
53
|
-
return value
|
|
54
|
-
return f"{COMMAND_PREFIX}{value}"
|
|
55
|
-
|
|
56
|
-
|
|
57
47
|
def _render_augment_command(skill_file: Path) -> str:
|
|
58
48
|
"""Render a single Augment command .md file from a user-invocable skill."""
|
|
59
49
|
description = frontmatter_field(skill_file, "description")
|
|
60
|
-
agent_field = frontmatter_field(skill_file, "agent")
|
|
61
50
|
argument_hint = frontmatter_field(skill_file, "argument-hint")
|
|
62
51
|
body = _skill_body(skill_file).rstrip()
|
|
63
52
|
|
|
@@ -65,8 +54,6 @@ def _render_augment_command(skill_file: Path) -> str:
|
|
|
65
54
|
if description:
|
|
66
55
|
safe_desc = description.replace('"', "'")
|
|
67
56
|
lines.append(f'description: "{safe_desc}"')
|
|
68
|
-
if agent_field:
|
|
69
|
-
lines.append(f"agent: {_map_agent_name(agent_field)}")
|
|
70
57
|
if argument_hint:
|
|
71
58
|
safe_hint = argument_hint.replace('"', "'")
|
|
72
59
|
lines.append(f'argument-hint: "{safe_hint}"')
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Generate Augment settings.json hooks block.
|
|
3
3
|
|
|
4
|
-
Augment
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
Augment reads hooks from several settings.json layers (per
|
|
5
|
+
docs.augmentcode.com/cli/hooks): `<workspace>/.augment/settings.local.json`,
|
|
6
|
+
`<workspace>/.augment/settings.json`, `~/.augment/settings.json` (user scope),
|
|
7
|
+
and `/etc/augment/settings.json` (system policy). This generator writes the
|
|
8
|
+
user-scope file: it accepts an optional target directory and defaults to the
|
|
9
|
+
user's `$HOME`, writing `~/.augment/settings.json`. Project-local hook emission
|
|
10
|
+
for `--local` installs is a possible future extension.
|
|
9
11
|
|
|
10
12
|
Augment hook events (per docs.augmentcode.com/cli/hooks.md):
|
|
11
13
|
PreToolUse, PostToolUse, SessionStart, SessionEnd, Stop
|
|
@@ -13,6 +13,12 @@ from pathlib import Path
|
|
|
13
13
|
|
|
14
14
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
15
15
|
from codex_skill_adapter import codex_skill_description
|
|
16
|
+
from dir_rules_shared import (
|
|
17
|
+
rule_code_style,
|
|
18
|
+
rule_output_mode,
|
|
19
|
+
rule_security,
|
|
20
|
+
rule_testing,
|
|
21
|
+
)
|
|
16
22
|
from emission import (
|
|
17
23
|
agents_dir,
|
|
18
24
|
skills_dir,
|
|
@@ -54,6 +60,23 @@ def _emit_skills() -> str:
|
|
|
54
60
|
return "\n".join(lines)
|
|
55
61
|
|
|
56
62
|
|
|
63
|
+
def _emit_coding_rules() -> str:
|
|
64
|
+
"""Inline the universal coding-rule bodies so Codex receives them.
|
|
65
|
+
|
|
66
|
+
Codex reads project instructions only from AGENTS.md (and AGENTS.override.md);
|
|
67
|
+
it does not read a ``.agents/rules/`` directory. Workflow + quality standards
|
|
68
|
+
are already emitted above, so this adds code-style, testing, security, and
|
|
69
|
+
output-mode under a single ``## Coding Rules`` section (H1 demoted to H3).
|
|
70
|
+
"""
|
|
71
|
+
sections: list[str] = []
|
|
72
|
+
for rule_fn in (rule_code_style, rule_testing, rule_security, rule_output_mode):
|
|
73
|
+
body = rule_fn().rstrip()
|
|
74
|
+
if body.startswith("# "):
|
|
75
|
+
body = "### " + body[2:]
|
|
76
|
+
sections.append(body)
|
|
77
|
+
return "## Coding Rules\n\n" + "\n\n".join(sections)
|
|
78
|
+
|
|
79
|
+
|
|
57
80
|
def main() -> None:
|
|
58
81
|
print_toolkit_start()
|
|
59
82
|
|
|
@@ -86,6 +109,11 @@ def main() -> None:
|
|
|
86
109
|
print()
|
|
87
110
|
print(generate_workflow_guidelines())
|
|
88
111
|
|
|
112
|
+
# Universal coding rules — Codex reads instructions only from AGENTS.md,
|
|
113
|
+
# so inline them here (previously emitted to the unread .agents/rules/).
|
|
114
|
+
print()
|
|
115
|
+
print(_emit_coding_rules())
|
|
116
|
+
|
|
89
117
|
print_toolkit_end()
|
|
90
118
|
|
|
91
119
|
# Registered custom rules from ~/.softspark/ai-toolkit/rules/
|
|
@@ -8,7 +8,8 @@ Codex exposes 10 lifecycle events (PascalCase in config.toml / hooks.json):
|
|
|
8
8
|
``PreToolUse``, ``PostToolUse``, ``PermissionRequest``, ``PreCompact``,
|
|
9
9
|
``PostCompact``, ``SessionStart``, ``UserPromptSubmit``, ``SubagentStart``,
|
|
10
10
|
``SubagentStop``, ``Stop``. PreToolUse/PostToolUse only support the ``Bash``
|
|
11
|
-
matcher. We
|
|
11
|
+
matcher. We wire all 10 events in ``CODEX_HOOKS`` below to the shared toolkit
|
|
12
|
+
hook scripts, mirroring the Claude Code mapping in ``app/hooks.json``.
|
|
12
13
|
|
|
13
14
|
Handler types in Codex: ``command`` (what we emit), ``prompt``, and ``agent``.
|
|
14
15
|
Reference: codex-rs/config/src/hook_config.rs.
|
|
@@ -39,6 +40,12 @@ CODEX_HOOKS: dict[str, list[tuple[str, str]]] = {
|
|
|
39
40
|
("Bash", "commit-quality.sh"),
|
|
40
41
|
("Bash", "revert-guard.sh"),
|
|
41
42
|
],
|
|
43
|
+
"PostToolUse": [
|
|
44
|
+
# Fires after Bash/apply_patch/MCP tool output. Capture governance
|
|
45
|
+
# signals and detect repetition loops (mirrors app/hooks.json).
|
|
46
|
+
("Bash", "governance-capture.sh"),
|
|
47
|
+
("Bash", "loop-guard.sh"),
|
|
48
|
+
],
|
|
42
49
|
"PermissionRequest": [
|
|
43
50
|
# Fires when Codex asks the user to approve a tool call. Our guard
|
|
44
51
|
# reviews the tool input and can veto destructive patterns before the
|
|
@@ -49,6 +56,21 @@ CODEX_HOOKS: dict[str, list[tuple[str, str]]] = {
|
|
|
49
56
|
("", "user-prompt-submit.sh"),
|
|
50
57
|
("", "track-usage.sh"),
|
|
51
58
|
],
|
|
59
|
+
"SubagentStart": [
|
|
60
|
+
("", "subagent-start.sh"),
|
|
61
|
+
],
|
|
62
|
+
"SubagentStop": [
|
|
63
|
+
("", "subagent-stop.sh"),
|
|
64
|
+
],
|
|
65
|
+
"PreCompact": [
|
|
66
|
+
# Capture session memory before Codex compacts the conversation.
|
|
67
|
+
("", "pre-compact.sh"),
|
|
68
|
+
("", "pre-compact-save.sh"),
|
|
69
|
+
],
|
|
70
|
+
"PostCompact": [
|
|
71
|
+
# Re-establish working context after compaction.
|
|
72
|
+
("", "session-context.sh"),
|
|
73
|
+
],
|
|
52
74
|
"Stop": [
|
|
53
75
|
("", "quality-check.sh"),
|
|
54
76
|
("", "save-session.sh"),
|
|
@@ -2,25 +2,24 @@
|
|
|
2
2
|
"""Generate ``.cursor/agents/ai-toolkit-*.md`` files for Cursor IDE.
|
|
3
3
|
|
|
4
4
|
Each ai-toolkit agent is mirrored as a Cursor custom agent. Per Cursor's
|
|
5
|
-
docs (
|
|
5
|
+
subagent docs (cursor.com/docs/subagents) the frontmatter schema documents
|
|
6
|
+
only these fields:
|
|
6
7
|
|
|
7
8
|
---
|
|
8
|
-
name: <slug>
|
|
9
|
-
description: "<one-line summary shown in the picker>"
|
|
10
|
-
model:
|
|
11
|
-
color: <color-name> # optional UI hint
|
|
12
|
-
tools: [Read, Write, ...] # list of allowed tool names
|
|
9
|
+
name: <slug> # lowercase letters and hyphens
|
|
10
|
+
description: "<one-line summary shown in the Task picker>"
|
|
11
|
+
model: inherit # `inherit` (default) or a specific model id
|
|
13
12
|
---
|
|
14
13
|
|
|
15
14
|
<system prompt body>
|
|
16
15
|
|
|
17
16
|
Design choices:
|
|
18
17
|
|
|
19
|
-
* ``model`` is
|
|
20
|
-
``haiku``) that do not map to
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
* ``model: inherit`` is emitted — the documented default value. Our agents
|
|
19
|
+
store short aliases (``opus``/``sonnet``/``haiku``) that do not map to
|
|
20
|
+
Cursor's provider-qualified model ids, so we use the literal ``inherit``.
|
|
21
|
+
* ``tools`` and ``color`` are NOT emitted — the current Cursor schema documents
|
|
22
|
+
only name/description/model/readonly/is_background (tools/color were dropped).
|
|
24
23
|
* Files are prefixed ``ai-toolkit-`` so install/uninstall can identify ours.
|
|
25
24
|
* Regeneration removes stale ``ai-toolkit-*.md`` files whose source agent
|
|
26
25
|
no longer exists, but leaves user-authored agents untouched.
|
|
@@ -53,34 +52,19 @@ def _agent_body(agent_file: Path) -> str:
|
|
|
53
52
|
return parts[2].lstrip("\n")
|
|
54
53
|
|
|
55
54
|
|
|
56
|
-
def _parse_tools(tools_raw: str) -> list[str]:
|
|
57
|
-
"""Parse the comma-separated ``tools:`` frontmatter value into a list."""
|
|
58
|
-
if not tools_raw:
|
|
59
|
-
return []
|
|
60
|
-
return [t.strip() for t in tools_raw.split(",") if t.strip()]
|
|
61
|
-
|
|
62
|
-
|
|
63
55
|
def _render_cursor_agent(agent_file: Path) -> str:
|
|
64
56
|
"""Render a single Cursor custom agent .md file."""
|
|
65
57
|
name = frontmatter_field(agent_file, "name")
|
|
66
58
|
description = frontmatter_field(agent_file, "description")
|
|
67
|
-
color = frontmatter_field(agent_file, "color")
|
|
68
|
-
tools_raw = frontmatter_field(agent_file, "tools")
|
|
69
|
-
tools = _parse_tools(tools_raw)
|
|
70
59
|
|
|
71
60
|
safe_desc = description.replace('"', "'")
|
|
72
61
|
|
|
73
62
|
lines: list[str] = ["---"]
|
|
74
63
|
lines.append(f"name: {name}")
|
|
75
64
|
lines.append(f'description: "{safe_desc}"')
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if tools:
|
|
80
|
-
tools_flow = ", ".join(tools)
|
|
81
|
-
lines.append(f"tools: [{tools_flow}]")
|
|
82
|
-
else:
|
|
83
|
-
lines.append("tools: []")
|
|
65
|
+
# `inherit` is the documented default model value; our short aliases do not
|
|
66
|
+
# map to Cursor's provider-qualified model ids.
|
|
67
|
+
lines.append("model: inherit")
|
|
84
68
|
lines.append("---")
|
|
85
69
|
lines.append("")
|
|
86
70
|
body = _agent_body(agent_file).rstrip()
|
|
@@ -5,8 +5,10 @@ User-invocable skills become opencode slash commands. Knowledge skills
|
|
|
5
5
|
(``user-invocable: false``) are excluded — they load automatically via
|
|
6
6
|
AGENTS.md context instead of `/` invocation.
|
|
7
7
|
|
|
8
|
-
Generated commands
|
|
9
|
-
|
|
8
|
+
Generated commands put the prompt in the markdown BODY. opencode reads the
|
|
9
|
+
body as the prompt template; the ``template`` frontmatter field is JSON-config
|
|
10
|
+
only and is ignored in .md command files. Files are prefixed ``ai-toolkit-``
|
|
11
|
+
for clean uninstall.
|
|
10
12
|
|
|
11
13
|
opencode commands: https://opencode.ai/docs/commands/
|
|
12
14
|
"""
|
|
@@ -47,12 +49,11 @@ def _skill_body(skill_file: Path) -> str:
|
|
|
47
49
|
|
|
48
50
|
def _render_opencode_command(skill_file: Path) -> str:
|
|
49
51
|
"""Render a single opencode command .md file from a user-invocable skill."""
|
|
50
|
-
name = frontmatter_field(skill_file, "name")
|
|
51
52
|
description = frontmatter_field(skill_file, "description")
|
|
52
53
|
agent_field = frontmatter_field(skill_file, "agent")
|
|
53
|
-
# opencode
|
|
54
|
-
# frontmatter
|
|
55
|
-
#
|
|
54
|
+
# opencode reads the command prompt from the markdown BODY of the file.
|
|
55
|
+
# The frontmatter only defines command properties; the `template` field is
|
|
56
|
+
# JSON-config-only and is ignored in .md command files.
|
|
56
57
|
body = _skill_body(skill_file).rstrip()
|
|
57
58
|
|
|
58
59
|
lines: list[str] = ["---"]
|
|
@@ -62,11 +63,10 @@ def _render_opencode_command(skill_file: Path) -> str:
|
|
|
62
63
|
if agent_field:
|
|
63
64
|
# opencode accepts an `agent` frontmatter field pointing at a subagent
|
|
64
65
|
lines.append(f"agent: {_map_agent_name(agent_field)}")
|
|
65
|
-
lines.append("template: |")
|
|
66
|
-
for tpl_line in body.splitlines() or [""]:
|
|
67
|
-
lines.append(f" {tpl_line}" if tpl_line else " ")
|
|
68
66
|
lines.append("---")
|
|
69
67
|
lines.append("")
|
|
68
|
+
lines.append(body)
|
|
69
|
+
lines.append("")
|
|
70
70
|
return "\n".join(lines)
|
|
71
71
|
|
|
72
72
|
|
package/scripts/install.py
CHANGED
|
@@ -14,7 +14,7 @@ Claude Code (~/.claude/):
|
|
|
14
14
|
Other tools (global config locations):
|
|
15
15
|
- Windsurf: ~/.codeium/windsurf/memories/global_rules.md + ~/.codeium/windsurf/skills/
|
|
16
16
|
- Gemini: ~/.gemini/GEMINI.md
|
|
17
|
-
- Cline:
|
|
17
|
+
- Cline: ~/Documents/Cline/Rules/ + ~/.cline/skills/
|
|
18
18
|
- Roo Code: ~/.roo/rules/
|
|
19
19
|
- Aider: ~/.aider.conf.yml (created only if absent)
|
|
20
20
|
- Augment: ~/.augment/rules/ai-toolkit.md
|