Compare commits

..

10 Commits

Author SHA1 Message Date
Michael Sitarzewski 1189f0f9bc fix(convert): make antigravity date_added deterministic (#608)
convert_antigravity() stamped `date_added: '${TODAY}'` (the convert-run date), so
every regeneration produced different bytes for every antigravity skill — churning
the gitignored output and blocking byte-reproducible rendering downstream (the app
can't implement a renderer for output it can't reproduce).

Replace ${TODAY} with a fixed constant (ANTIGRAVITY_DATE_ADDED="2026-03-08",
matching the documented example in integrations/antigravity/README.md). The field
stays (it's part of the Antigravity frontmatter format); it's just stable now.

Verified: two consecutive `convert.sh --tool antigravity` runs produce a
byte-identical SKILL.md (same sha), and no convert-run date appears in output.

This unblocks the app from rendering antigravity (format `antigravity-skill` in
tools.json) once it implements that renderer.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:30:39 -05:00
Michael Sitarzewski d4067cc48a ci: add check-tools.yml to enforce the tool contract (#607)
Mirrors check-divisions.yml. Runs scripts/check-tools.sh on every PR and on
push to main (no path filter) so any change to ALL_TOOLS in install.sh, the
converter set in convert.sh, or tools.json that breaks consistency fails the
build — same CI protection divisions.json already has.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:30:35 -05:00
Michael Sitarzewski 9262649a48 Add tools.json canonical registry + check-tools.sh guard (#606)
Mirrors the divisions.json / check-divisions.sh pattern for the supported tool
set. tools.json (repo root) is the single source of truth for all 13 tools,
consumed by the Agency Agents app and by scripts/convert.sh + scripts/install.sh.
scripts/check-tools.sh (no-jq, bash 3.2) fails the build if tools.json disagrees
with ALL_TOOLS in install.sh or the converter set in convert.sh, or if any entry
is missing id/label/kebab/format/dest.

Every tool carries its real install contract (format, dest, scope, detect,
version) — verified against actual convert.sh/install.sh behavior via a
sandboxed install pass (all dest templates resolve to the real on-disk layout).

`format` is the renderer contract: same name => byte-identical output. The five
formerly-undescribed tools get distinct names — aider-conventions, antigravity-skill
(its non-deterministic date_added means it can't share osaurus's skill-md),
kimi-agent, openclaw-workspace, windsurf-rules — none colliding with the app's
implemented renderers. Removed the `wired` field: it encoded app renderer state
(not catalog truth); consumers derive installability from `format` against their
own implemented-format set. check-tools.sh requires format+dest for every tool,
not just some. Also fixes antigravity detect (.gemini/antigravity-cli ->
.gemini/antigravity/skills, matching the actual code).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:38:47 -05:00
Michael Sitarzewski 55beae93a7 fix(convert): prune stale tool output before regenerating (#605)
convert.sh overwrote per-agent output in place but never removed files for
agents that were renamed or deleted, so orphans accumulated in the gitignored
integrations/<tool>/ dirs (e.g. agency-security-engineer lingered in
antigravity/ and openclaw/ long after the source agent was gone) — and install.sh
would happily copy them.

Add clean_tool_output(), called once at the top of run_conversions (the single
choke point for serial, parallel, and single-file paths): it wipes the tool's
generated output but preserves the committed README.md (the only tracked file
under integrations/<tool>/ for conversion targets).

Verified: antigravity regenerated to 232 (was 233), orphan pruned, README kept.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:38:43 -05:00
Michael Sitarzewski 48b5225986 docs(install): list OSAURUS_SKILLS_DIR in the Env override header (#604)
resolve_dest honors OSAURUS_SKILLS_DIR but the header's Env: line omitted it.
One-line doc add for completeness. Follow-up to #603.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 15:48:15 -05:00
Michael Sitarzewski f56a217945 Add Osaurus tool target + document the division contract (#603)
Tooling: add Osaurus (Anthropic Agent-Skills SKILL.md format) as a conversion
and install target, wired into convert.sh (convert_osaurus + dispatch/valid/all/
parallel lists, --osaurus flag) and install.sh (detect/label/dest/install_osaurus
+ dispatch). Generated output lands in integrations/osaurus/agency-*/SKILL.md and
is gitignored like every other tool's output (regenerate via convert.sh osaurus).

Docs/guardrails — make the division contract discoverable, since it lived only
in scattered script comments and tripped up multiple contributors:
- CONTRIBUTING.md: complete the division list to all 16 (was missing academic/
  gis/sales) and document that divisions.json is the source of truth (CI-checked
  by check-divisions.sh), how to propose a new division, and that strategy/
  (NEXUS playbooks) and integrations/ (generated output) are NOT divisions.
- install.sh: correct the stale "sync with convert.sh / lint-agents.sh" comment —
  install.sh intentionally keeps strategy/ in AGENT_DIRS (filtered at scan time),
  so it is deliberately NOT the same set as the other two.
- .gitignore: ignore integrations/osaurus/agency-*/ (the osaurus output was the
  one tool whose generated files weren't excluded).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 15:45:50 -05:00
Michael Sitarzewski 93f3c5f818 check-divisions: enumerate git-tracked dirs, not a filesystem glob (#597)
actual_dirs() globbed the filesystem (`for d in */`), so it picked up gitignored
or otherwise untracked top-level directories — e.g. a local notes/ scratch dir —
and reported them as "division(s) not in divisions.json". That's a false
failure: CI uses a clean `actions/checkout` and never sees those dirs, so the
check passed in CI but failed locally, undermining a guard meant to be run
locally before pushing.

Use `git ls-files` to enumerate only top-level dirs that contain a tracked file,
keeping the dot-prefix and NON_DIVISION_DIRS filters. Local now matches CI.

Verified: passes at 16 divisions; an untracked dir is ignored; a tracked
unregistered division dir still fails the check.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 22:48:03 -05:00
Michael Sitarzewski 4d07efdb70 Drop strategy/ as a division — it's playbooks/runbooks, not agents (#595)
strategy/ holds 16 markdown files and ZERO have agent frontmatter — they're
playbooks (playbooks/phase-*.md), runbooks (runbooks/scenario-*.md), and briefs
(EXECUTIVE-BRIEF.md, QUICKSTART.md, nexus-strategy.md), not agent definitions.
There are 16 real agent divisions, 232 agents; strategy is not one of them.

#592 added `strategy` to lint-agents.sh AGENT_DIRS and the lint workflow paths
(to match divisions.json), which made CI lint those 16 frontmatter-less docs as
agents and fail every one with "missing frontmatter opening ---". So any PR
touching strategy/ broke CI. The original lint-agents.sh correctly excluded
strategy; #592 misread that deliberate exclusion as drift (same mistake as
integrations/ in #593).

Fix: remove strategy from convert.sh / lint-agents.sh AGENT_DIRS, the lint
workflow, and divisions.json; add it to NON_DIVISION_DIRS in check-divisions.sh.
divisions.json is now 16, matching the app's parse_agent count exactly.

Also add a content-derived backstop to check-divisions.sh: every division must
contain at least one .md with '---' frontmatter, or the build fails. This is
what stops a docs/playbook directory from being registered as an empty agent
division again — regardless of whether someone remembers the exclude list.

check-divisions.sh PASSES at 16; negative-tested that re-adding strategy fails
with "division 'strategy' has no agent files".

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 22:19:25 -05:00
Michael Sitarzewski 3f78a30bb2 Exclude integrations/ from the source-agent scan (it's convert.sh output) (#593)
#592 added `integrations` to AGENT_DIRS in convert.sh and lint-agents.sh and to
the lint workflow paths, to make those lists match divisions.json. That was
wrong: integrations/ is not a source-agent category — it's where convert.sh
WRITES per-tool conversions (e.g. openclaw output → integrations/openclaw/<agent>/SOUL.md).
It holds 957 conversion outputs across openclaw/opencode/qwen/antigravity, vs
248 real source agents in the 17 genuine categories.

Scanning integrations/ as source made the toolchain re-convert its own outputs:
the same agent appears under every tool (brand-guardian ×5), output slugs
collide, and convert.sh's last-writer-wins corrupts the catalog — which broke
downstream parity checks. convert.sh originally omitted integrations on purpose;
#592 misread that deliberate exclusion as drift.

Fix: drop integrations from convert.sh / lint-agents.sh AGENT_DIRS and the lint
workflow, remove it from divisions.json (it's not a division), and add it to
NON_DIVISION_DIRS in check-divisions.sh so the guard's canonical set is the real
17 source categories. The `strategy` additions from #592 were correct and stay.

check-divisions.sh now PASSES at 17 divisions consistent across divisions.json,
directories, scripts, and CI.

Note: integrations/mcp-memory holds 2 real source agents stranded in the output
tree; relocating them to a real category is left as separate follow-up.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:52:08 -05:00
Michael Sitarzewski a5688be6cc Add divisions.json — division presentation metadata (label, icon, color) (#592)
* Add divisions.json — presentation metadata (label, icon, color) per division

Establishes a source of truth for how each division (top-level agent directory)
is presented: a display label, a Lucide icon name, and a brand color. Lets the
Agency Agents app (and any other tooling) render divisions consistently —
including fixing "GIS" (was title-cased to "Gis") and covering `gis` +
`integrations`, which had no metadata before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Make divisions.json the source of truth + enforce in CI

divisions.json now drives the division set. Add scripts/check-divisions.sh
(CI: check-divisions.yml, runs on every PR with no path filter) which fails
if divisions.json disagrees with the directories on disk, the AGENT_DIRS
arrays in convert.sh / lint-agents.sh, or the lint-agents.yml path filters,
or if any entry lacks label/icon/color.

Fixes pre-existing drift surfaced by the new check: integrations was missing
from convert.sh and lint-agents.sh; integrations and strategy were missing
from lint-agents.sh and the lint workflow (so those agents weren't being
linted at all).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 15:13:33 -05:00
11 changed files with 261 additions and 31 deletions
+20
View File
@@ -0,0 +1,20 @@
name: Check Tools Consistency
# Runs on every PR (no path filter on purpose): a new or renamed tool must trip
# this check even when nobody touched tools.json or the install/convert scripts.
on:
pull_request:
push:
branches: [main]
jobs:
check-tools:
name: tools.json is the single source of truth
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate tool set
run: |
chmod +x scripts/check-tools.sh
./scripts/check-tools.sh
+2 -4
View File
@@ -9,7 +9,6 @@ on:
- "finance/**" - "finance/**"
- "game-development/**" - "game-development/**"
- "gis/**" - "gis/**"
- "integrations/**"
- "marketing/**" - "marketing/**"
- "paid-media/**" - "paid-media/**"
- "sales/**" - "sales/**"
@@ -20,7 +19,6 @@ on:
- "support/**" - "support/**"
- "spatial-computing/**" - "spatial-computing/**"
- "specialized/**" - "specialized/**"
- "strategy/**"
jobs: jobs:
lint: lint:
@@ -35,9 +33,9 @@ jobs:
id: changed id: changed
run: | run: |
FILES=$(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- \ FILES=$(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- \
'academic/**/*.md' 'design/**/*.md' 'engineering/**/*.md' 'finance/**/*.md' 'game-development/**/*.md' 'gis/**/*.md' 'integrations/**/*.md' 'marketing/**/*.md' 'paid-media/**/*.md' 'sales/**/*.md' 'security/**/*.md' 'product/**/*.md' \ 'academic/**/*.md' 'design/**/*.md' 'engineering/**/*.md' 'finance/**/*.md' 'game-development/**/*.md' 'gis/**/*.md' 'marketing/**/*.md' 'paid-media/**/*.md' 'sales/**/*.md' 'security/**/*.md' 'product/**/*.md' \
'project-management/**/*.md' 'testing/**/*.md' 'support/**/*.md' \ 'project-management/**/*.md' 'testing/**/*.md' 'support/**/*.md' \
'spatial-computing/**/*.md' 'specialized/**/*.md' 'strategy/**/*.md') 'spatial-computing/**/*.md' 'specialized/**/*.md')
{ {
echo "files<<ENDOFLIST" echo "files<<ENDOFLIST"
echo "$FILES" echo "$FILES"
+1
View File
@@ -80,3 +80,4 @@ integrations/kimi/*/
!integrations/openclaw/README.md !integrations/openclaw/README.md
!integrations/kimi/README.md !integrations/kimi/README.md
integrations/codex/agents/* integrations/codex/agents/*
integrations/osaurus/agency-*/
+18 -4
View File
@@ -31,20 +31,34 @@ This project and everyone participating in it is governed by our Code of Conduct
Have an idea for a specialized agent? Great! Here's how to add one: Have an idea for a specialized agent? Great! Here's how to add one:
1. **Fork the repository** 1. **Fork the repository**
2. **Choose the appropriate category** (or propose a new one): 2. **Choose the appropriate division** (one of the 16 — or propose a new one):
- `engineering/` - Software development specialists - `academic/` - Research, scholarship, and domain-expert specialists
- `design/` - UX/UI and creative specialists - `design/` - UX/UI and creative specialists
- `engineering/` - Software development specialists
- `finance/` - Financial planning, accounting, and investment specialists - `finance/` - Financial planning, accounting, and investment specialists
- `game-development/` - Game design and development specialists - `game-development/` - Game design and development specialists
- `gis/` - Geospatial, mapping, and spatial-analysis specialists
- `marketing/` - Growth and marketing specialists - `marketing/` - Growth and marketing specialists
- `paid-media/` - Paid acquisition and media specialists - `paid-media/` - Paid acquisition and media specialists
- `product/` - Product management specialists - `product/` - Product management specialists
- `project-management/` - PM and coordination specialists - `project-management/` - PM and coordination specialists
- `testing/` - QA and testing specialists - `sales/` - Sales, revenue, and deal specialists
- `security/` - Security architecture, AppSec, pentest, threat intel, and incident response - `security/` - Security architecture, AppSec, pentest, threat intel, and incident response
- `support/` - Operations and support specialists
- `spatial-computing/` - AR/VR/XR specialists - `spatial-computing/` - AR/VR/XR specialists
- `specialized/` - Unique specialists that don't fit elsewhere - `specialized/` - Unique specialists that don't fit elsewhere
- `support/` - Operations and support specialists
- `testing/` - QA and testing specialists
> **Divisions are defined by `divisions.json`** (repo root) — the single source of
> truth for the division set, validated in CI by `scripts/check-divisions.sh`.
> **Proposing a new division** means: create the directory, add an entry to
> `divisions.json` (label/icon/color), and add it to `AGENT_DIRS` in both
> `scripts/convert.sh` and `scripts/lint-agents.sh`. The check fails the build
> unless all of these agree and the directory contains at least one agent file.
>
> Note: `strategy/` (NEXUS playbooks/runbooks — no agent frontmatter) and
> `integrations/` (generated per-tool output from `convert.sh`) are **not**
> divisions and must never be added to the division lists.
3. **Create your agent file** following the template below 3. **Create your agent file** following the template below
4. **Test your agent** in real scenarios 4. **Test your agent** in real scenarios
+1 -3
View File
@@ -1,5 +1,5 @@
{ {
"_note": "Source of truth for the agent division set. Each division (a top-level agent directory) maps to a display label, a Lucide icon name (PascalCase), and a brand color (hex). Consumed by the Agency Agents app and any other catalog tooling. scripts/check-divisions.sh (CI: check-divisions.yml) fails the build if this list disagrees with the directories on disk, the AGENT_DIRS arrays in scripts/convert.sh and scripts/lint-agents.sh, or the path filters in lint-agents.yml. To add a division: create its directory, add an entry here, then run scripts/check-divisions.sh and update wherever it points.", "_note": "Source of truth for the agent division set. Each division (a top-level agent directory) maps to a display label, a Lucide icon name (PascalCase), and a brand color (hex). Consumed by the Agency Agents app and any other catalog tooling. scripts/check-divisions.sh (CI: check-divisions.yml) fails the build if this list disagrees with the directories on disk, the AGENT_DIRS arrays in scripts/convert.sh and scripts/lint-agents.sh, or the path filters in lint-agents.yml. To add a division: create its directory, add an entry here, then run scripts/check-divisions.sh and update wherever it points. NOT every top-level directory is a division: integrations/ holds per-tool conversion OUTPUTS written by scripts/convert.sh (not source agents); strategy/ holds playbooks and runbooks with no agent frontmatter; both — plus examples/ and scripts/ — are excluded via NON_DIVISION_DIRS in check-divisions.sh. A division must contain at least one frontmatter agent file.",
"divisions": { "divisions": {
"academic": { "label": "Academic", "icon": "GraduationCap", "color": "#8B5CF6" }, "academic": { "label": "Academic", "icon": "GraduationCap", "color": "#8B5CF6" },
"design": { "label": "Design", "icon": "PenTool", "color": "#EC4899" }, "design": { "label": "Design", "icon": "PenTool", "color": "#EC4899" },
@@ -7,7 +7,6 @@
"finance": { "label": "Finance", "icon": "DollarSign", "color": "#22C55E" }, "finance": { "label": "Finance", "icon": "DollarSign", "color": "#22C55E" },
"game-development": { "label": "Game Development", "icon": "Gamepad2", "color": "#A855F7" }, "game-development": { "label": "Game Development", "icon": "Gamepad2", "color": "#A855F7" },
"gis": { "label": "GIS", "icon": "Map", "color": "#14B8A6" }, "gis": { "label": "GIS", "icon": "Map", "color": "#14B8A6" },
"integrations": { "label": "Integrations", "icon": "Workflow", "color": "#64748B" },
"marketing": { "label": "Marketing", "icon": "Megaphone", "color": "#F97316" }, "marketing": { "label": "Marketing", "icon": "Megaphone", "color": "#F97316" },
"paid-media": { "label": "Paid Media", "icon": "Target", "color": "#EAB308" }, "paid-media": { "label": "Paid Media", "icon": "Target", "color": "#EAB308" },
"product": { "label": "Product", "icon": "Box", "color": "#D946EF" }, "product": { "label": "Product", "icon": "Box", "color": "#D946EF" },
@@ -16,7 +15,6 @@
"security": { "label": "Security", "icon": "ShieldCheck", "color": "#EF4444" }, "security": { "label": "Security", "icon": "ShieldCheck", "color": "#EF4444" },
"spatial-computing": { "label": "Spatial Computing", "icon": "Boxes", "color": "#06B6D4" }, "spatial-computing": { "label": "Spatial Computing", "icon": "Boxes", "color": "#06B6D4" },
"specialized": { "label": "Specialized", "icon": "Sparkles", "color": "#6366F1" }, "specialized": { "label": "Specialized", "icon": "Sparkles", "color": "#6366F1" },
"strategy": { "label": "Strategy", "icon": "Network", "color": "#F43F5E" },
"support": { "label": "Support", "icon": "LifeBuoy", "color": "#84CC16" }, "support": { "label": "Support", "icon": "LifeBuoy", "color": "#84CC16" },
"testing": { "label": "Testing", "icon": "FlaskConical", "color": "#F59E0B" } "testing": { "label": "Testing", "icon": "FlaskConical", "color": "#F59E0B" }
} }
+33 -7
View File
@@ -25,7 +25,11 @@ JSON="divisions.json"
# Top-level directories that are NOT divisions. Everything else at the repo # Top-level directories that are NOT divisions. Everything else at the repo
# root that is a directory is treated as a division (so a new division dir is # root that is a directory is treated as a division (so a new division dir is
# caught even if nobody remembered to register it). # caught even if nobody remembered to register it).
NON_DIVISION_DIRS=(examples scripts) # integrations/ is convert.sh's OUTPUT tree (per-tool conversions written back
# into the repo), not a source-agent category. strategy/ holds playbooks and
# runbooks (no agent frontmatter), not agents. Neither is a division — they must
# never be scanned as source-agent categories.
NON_DIVISION_DIRS=(examples scripts integrations strategy)
errors=0 errors=0
fail() { echo "ERROR $*"; errors=$((errors + 1)); } fail() { echo "ERROR $*"; errors=$((errors + 1)); }
@@ -41,16 +45,18 @@ canonical() {
| sed -E 's/"([a-z0-9-]+)".*/\1/' | sort -u | sed -E 's/"([a-z0-9-]+)".*/\1/' | sort -u
} }
# Actual division directories on disk (top-level dirs minus the excludes and # Actual division directories: top-level dirs that contain at least one
# anything dot-prefixed). # git-TRACKED file, minus the excludes and anything dot-prefixed. Using
# `git ls-files` (not a filesystem glob) keeps this in lockstep with what CI's
# clean checkout sees, so a local gitignored scratch dir (e.g. notes/) can't
# produce a false failure.
actual_dirs() { actual_dirs() {
local d base local base
for d in */; do git ls-files | awk -F/ 'NF>1{print $1}' | sort -u | while IFS= read -r base; do
base="${d%/}"
[[ "$base" == .* ]] && continue [[ "$base" == .* ]] && continue
case " ${NON_DIVISION_DIRS[*]} " in *" $base "*) continue ;; esac case " ${NON_DIVISION_DIRS[*]} " in *" $base "*) continue ;; esac
echo "$base" echo "$base"
done | sort -u done
} }
# Contents of a bash AGENT_DIRS=( ... ) array in the given file, one per line. # Contents of a bash AGENT_DIRS=( ... ) array in the given file, one per line.
@@ -102,6 +108,26 @@ while IFS= read -r div; do
done done
done < <(canonical) done < <(canonical)
# Every division must contain at least one agent file: a .md whose first line is
# '---' frontmatter. This is the content-derived backstop that keeps a docs or
# playbook directory (e.g. strategy/, all of whose files are frontmatter-less)
# from being registered as an empty agent division.
has_agent_file() {
local f first
while IFS= read -r f; do
first="$(head -1 "$f" | tr -d '\r')"
[[ "$first" == "---" ]] && return 0
done < <(find "$1" -name '*.md' -type f 2>/dev/null)
return 1
}
while IFS= read -r div; do
if [[ ! -d "$div" ]]; then
fail "division '$div' has no directory on disk"
elif ! has_agent_file "$div"; then
fail "division '$div' has no agent files (.md with '---' frontmatter) — not a real division"
fi
done < <(canonical)
# --- result ---------------------------------------------------------------- # --- result ----------------------------------------------------------------
count="$(canonical | wc -l | tr -d ' ')" count="$(canonical | wc -l | tr -d ' ')"
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
#
# check-tools.sh — enforce a single source of truth for the supported tool set.
#
# tools.json (repo root) is canonical. This script fails if any of the following
# disagree with it:
# 1. ALL_TOOLS in scripts/install.sh (exact set — every installable tool)
# 2. valid_tools in scripts/convert.sh (every converter tool must exist in tools.json)
# 3. Every tools.json entry has id, label, kebab, format, and dest
#
# Add a tool: add an entry to tools.json, a convert_<tool> (or reuse a `format`)
# in convert.sh, and an install_<tool> in install.sh, then run this script — it
# tells you every place that must agree. No deps beyond bash 3.2 + coreutils
# (no jq) so it runs the same on macOS and CI. Mirrors scripts/check-divisions.sh.
#
# Usage: ./scripts/check-tools.sh
set -euo pipefail
cd "$(dirname "$0")/.."
JSON="tools.json"
errors=0
fail() { echo "ERROR $*"; errors=$((errors + 1)); }
# --- helpers ---------------------------------------------------------------
# Canonical tool keys (kebab) from tools.json: the keys at 4-space indent inside
# the "tools" object. One tool per line keeps the nested "scope"/"detect"/…
# objects off the line start, so only tool keys match.
canonical() {
awk '/"tools"[[:space:]]*:[[:space:]]*\{/{f=1; next} f' "$JSON" \
| grep -oE '^ "[a-z0-9-]+"' \
| sed -E 's/.*"([a-z0-9-]+)".*/\1/' | sort -u
}
# Entries of a single-line bash array NAME=( ... ) (quoted or bare), one per line.
bash_array() {
grep -oE "$2=\([^)]*\)" "$1" | head -1 | sed -E "s/^$2=\(//; s/\)\$//" \
| tr -d '"' | tr ' \t' '\n\n' | grep -E '^[a-z0-9-]+$' | sort -u
}
# --- checks ----------------------------------------------------------------
[[ -f "$JSON" ]] || { echo "ERROR $JSON not found at repo root"; exit 1; }
canon="$(canonical)"
# 1. tools.json keys == ALL_TOOLS in install.sh (exact, both directions).
all_tools="$(bash_array scripts/install.sh ALL_TOOLS)"
missing="$(comm -23 <(echo "$canon") <(echo "$all_tools"))"
extra="$(comm -13 <(echo "$canon") <(echo "$all_tools"))"
[[ -n "$missing" ]] && fail "scripts/install.sh ALL_TOOLS is missing tool(s) in $JSON: $(echo $missing)"
[[ -n "$extra" ]] && fail "scripts/install.sh ALL_TOOLS has tool(s) not in $JSON: $(echo $extra)"
# 2. Every converter in convert.sh must exist in tools.json (subset; identity
# tools like claude-code/copilot are install-only, so it's a subset not equal).
conv="$(bash_array scripts/convert.sh valid_tools | grep -v '^all$' || true)"
notin="$(comm -13 <(echo "$canon") <(echo "$conv"))"
[[ -n "$notin" ]] && fail "scripts/convert.sh converts tool(s) absent from $JSON: $(echo $notin)"
# 3. Required fields per entry (each tool is one line). aa converts+installs
# every listed tool, so every entry must carry format + dest — there is no
# "half-described" tool. (Renderer coverage is a consumer's concern, derived
# from `format`; the catalog itself carries no such flag.)
while IFS= read -r t; do
[[ -n "$t" ]] || continue
line="$(grep -E "^ \"$t\"[[:space:]]*:" "$JSON")"
for field in id label kebab format dest; do
echo "$line" | grep -qE "\"$field\":" || fail "tool '$t' in $JSON is missing \"$field\""
done
done < <(echo "$canon")
# --- result ----------------------------------------------------------------
count="$(echo "$canon" | grep -c .)"
if [[ $errors -gt 0 ]]; then
echo ""
echo "FAILED: $errors tool consistency error(s). $JSON is the source of truth."
exit 1
fi
echo "PASSED: $count tools consistent across $JSON, install.sh, and convert.sh."
+54 -7
View File
@@ -20,6 +20,7 @@
# qwen — Qwen Code SubAgent files (~/.qwen/agents/*.md) # qwen — Qwen Code SubAgent files (~/.qwen/agents/*.md)
# kimi — Kimi Code CLI agent files (~/.config/kimi/agents/) # kimi — Kimi Code CLI agent files (~/.config/kimi/agents/)
# codex — Codex custom agent TOML files (~/.codex/agents/*.toml) # codex — Codex custom agent TOML files (~/.codex/agents/*.toml)
# osaurus — Osaurus skill files (~/.osaurus/skills/<name>/SKILL.md)
# all — All tools (default) # all — All tools (default)
# #
# Output is written to integrations/<tool>/ relative to the repo root. # Output is written to integrations/<tool>/ relative to the repo root.
@@ -62,18 +63,24 @@ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
OUT_DIR="$REPO_ROOT/integrations" OUT_DIR="$REPO_ROOT/integrations"
TODAY="$(date +%Y-%m-%d)" TODAY="$(date +%Y-%m-%d)"
# Static date stamped into Antigravity skill frontmatter. Deliberately fixed (NOT
# the convert-run date): a per-run TODAY made every regeneration produce different
# bytes, which churns the gitignored output and breaks byte-reproducible rendering
# downstream. Matches the documented example in integrations/antigravity/README.md.
ANTIGRAVITY_DATE_ADDED="2026-03-08"
# Shared helpers (get_field, get_body, slugify, ...) # Shared helpers (get_field, get_body, slugify, ...)
# shellcheck source=lib.sh # shellcheck source=lib.sh
. "$SCRIPT_DIR/lib.sh" . "$SCRIPT_DIR/lib.sh"
AGENT_DIRS=( AGENT_DIRS=(
academic design engineering finance game-development gis integrations marketing paid-media product project-management academic design engineering finance game-development gis marketing paid-media product project-management
sales security spatial-computing specialized strategy support testing sales security spatial-computing specialized support testing
) )
# --- Usage --- # --- Usage ---
usage() { usage() {
sed -n '3,26p' "$0" | sed 's/^# \{0,1\}//' sed -n '3,27p' "$0" | sed 's/^# \{0,1\}//'
exit 0 exit 0
} }
@@ -124,7 +131,34 @@ name: ${slug}
description: ${description} description: ${description}
risk: low risk: low
source: community source: community
date_added: '${TODAY}' date_added: '${ANTIGRAVITY_DATE_ADDED}'
---
${body}
HEREDOC
}
convert_osaurus() {
local file="$1"
local name description slug outdir outfile body
name="$(get_field "name" "$file")"
description="$(get_field "description" "$file")"
slug="agency-$(slugify "$name")"
body="$(get_body "$file")"
# Stage one dir per skill (install.sh copies into ~/.osaurus/skills/<name>/).
outdir="$OUT_DIR/osaurus/$slug"
outfile="$outdir/SKILL.md"
mkdir -p "$outdir"
# Osaurus skill format: the Anthropic "Agent Skills" SKILL.md — a directory
# named for the skill containing a SKILL.md with name + description frontmatter
# and the persona as the instruction body. Installs into ~/.osaurus/skills/.
# Kept to the standard fields so it stays compatible with any Agent-Skills host.
cat > "$outfile" <<HEREDOC
---
name: ${slug}
description: ${description}
--- ---
${body} ${body}
HEREDOC HEREDOC
@@ -500,10 +534,22 @@ HEREDOC
# --- Main loop --- # --- Main loop ---
# Remove a tool's previously-generated output before regenerating, so renamed or
# deleted agents don't leave orphan files behind (convert.sh overwrites in place
# but never pruned stale output). Preserves the committed README.md — the only
# tracked file under integrations/<tool>/ for conversion targets.
clean_tool_output() {
local dir="$OUT_DIR/$1"
[[ -d "$dir" ]] || return 0
find "$dir" -mindepth 1 -maxdepth 1 ! -name 'README.md' -exec rm -rf {} +
}
run_conversions() { run_conversions() {
local tool="$1" local tool="$1"
local count=0 local count=0
clean_tool_output "$tool"
for dir in "${AGENT_DIRS[@]}"; do for dir in "${AGENT_DIRS[@]}"; do
local dirpath="$REPO_ROOT/$dir" local dirpath="$REPO_ROOT/$dir"
[[ -d "$dirpath" ]] || continue [[ -d "$dirpath" ]] || continue
@@ -527,6 +573,7 @@ run_conversions() {
openclaw) convert_openclaw "$file" ;; openclaw) convert_openclaw "$file" ;;
qwen) convert_qwen "$file" ;; qwen) convert_qwen "$file" ;;
kimi) convert_kimi "$file" ;; kimi) convert_kimi "$file" ;;
osaurus) convert_osaurus "$file" ;;
aider) accumulate_aider "$file" ;; aider) accumulate_aider "$file" ;;
windsurf) accumulate_windsurf "$file" ;; windsurf) accumulate_windsurf "$file" ;;
esac esac
@@ -557,7 +604,7 @@ main() {
esac esac
done done
local valid_tools=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi" "codex" "all") local valid_tools=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi" "codex" "osaurus" "all")
local valid=false local valid=false
for t in "${valid_tools[@]}"; do [[ "$t" == "$tool" ]] && valid=true && break; done for t in "${valid_tools[@]}"; do [[ "$t" == "$tool" ]] && valid=true && break; done
if ! $valid; then if ! $valid; then
@@ -576,7 +623,7 @@ main() {
local tools_to_run=() local tools_to_run=()
if [[ "$tool" == "all" ]]; then if [[ "$tool" == "all" ]]; then
tools_to_run=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi" "codex") tools_to_run=("antigravity" "gemini-cli" "opencode" "cursor" "aider" "windsurf" "openclaw" "qwen" "kimi" "codex" "osaurus")
else else
tools_to_run=("$tool") tools_to_run=("$tool")
fi fi
@@ -587,7 +634,7 @@ main() {
if $use_parallel && [[ "$tool" == "all" ]]; then if $use_parallel && [[ "$tool" == "all" ]]; then
# Tools that write to separate dirs can run in parallel; buffer output so each tool's output stays together # Tools that write to separate dirs can run in parallel; buffer output so each tool's output stays together
local parallel_tools=(antigravity gemini-cli opencode cursor openclaw qwen codex) local parallel_tools=(antigravity gemini-cli opencode cursor openclaw qwen codex osaurus)
local parallel_out_dir local parallel_out_dir
parallel_out_dir="$(mktemp -d)" parallel_out_dir="$(mktemp -d)"
info "Converting: ${#parallel_tools[@]}/${n_tools} tools in parallel (output buffered per tool)..." info "Converting: ${#parallel_tools[@]}/${n_tools} tools in parallel (output buffered per tool)..."
+33 -4
View File
@@ -23,6 +23,7 @@
# openclaw -- Copy workspaces to ~/.openclaw/agency-agents/ # openclaw -- Copy workspaces to ~/.openclaw/agency-agents/
# qwen -- Copy SubAgents to ~/.qwen/agents/ (user-wide) or .qwen/agents/ (project) # qwen -- Copy SubAgents to ~/.qwen/agents/ (user-wide) or .qwen/agents/ (project)
# codex -- Copy custom agent TOML files to ~/.codex/agents/ # codex -- Copy custom agent TOML files to ~/.codex/agents/
# osaurus -- Copy skills to ~/.osaurus/skills/
# all -- Install for all detected tools (default) # all -- Install for all detected tools (default)
# #
# Selection (compose freely; empty = everything): # Selection (compose freely; empty = everything):
@@ -46,7 +47,8 @@
# --help Show this help # --help Show this help
# #
# Env: CLAUDE_CONFIG_DIR, COPILOT_AGENT_DIR, CURSOR_RULES_DIR, GEMINI_AGENTS_DIR, # Env: CLAUDE_CONFIG_DIR, COPILOT_AGENT_DIR, CURSOR_RULES_DIR, GEMINI_AGENTS_DIR,
# OPENCODE_AGENTS_DIR, OPENCLAW_DIR, QWEN_AGENTS_DIR, CODEX_AGENTS_DIR # OPENCODE_AGENTS_DIR, OPENCLAW_DIR, QWEN_AGENTS_DIR, CODEX_AGENTS_DIR,
# OSAURUS_SKILLS_DIR
# override default install paths (checked before hardcoded defaults). # override default install paths (checked before hardcoded defaults).
# #
# --- USAGE-END --- (sentinel for usage(); do not remove) # --- USAGE-END --- (sentinel for usage(); do not remove)
@@ -125,9 +127,13 @@ INTEGRATIONS="$REPO_ROOT/integrations"
# shellcheck source=lib.sh # shellcheck source=lib.sh
. "$SCRIPT_DIR/lib.sh" . "$SCRIPT_DIR/lib.sh"
ALL_TOOLS=(claude-code copilot antigravity gemini-cli opencode openclaw cursor aider windsurf qwen kimi codex) ALL_TOOLS=(claude-code copilot antigravity gemini-cli opencode openclaw cursor aider windsurf qwen kimi codex osaurus)
# Standard agent category directories (keep sorted, sync with convert.sh / lint-agents.sh) # Directories scanned for installable agents. Intentionally includes strategy/
# (its frontmatter-less NEXUS docs are filtered out by is_agent_file at scan time);
# the selectable division list below is this set minus strategy. This is NOT the
# same set as AGENT_DIRS in convert.sh / lint-agents.sh, which exclude strategy
# entirely — see divisions.json (the source of truth) and scripts/check-divisions.sh.
AGENT_DIRS=( AGENT_DIRS=(
academic design engineering finance game-development gis marketing paid-media product project-management academic design engineering finance game-development gis marketing paid-media product project-management
sales security spatial-computing specialized strategy support testing sales security spatial-computing specialized strategy support testing
@@ -255,6 +261,7 @@ resolve_dest() {
openclaw) var="OPENCLAW_DIR" ;; openclaw) var="OPENCLAW_DIR" ;;
qwen) var="QWEN_AGENTS_DIR" ;; qwen) var="QWEN_AGENTS_DIR" ;;
codex) var="CODEX_AGENTS_DIR" ;; codex) var="CODEX_AGENTS_DIR" ;;
osaurus) var="OSAURUS_SKILLS_DIR" ;;
esac esac
if [[ -n "$var" && -n "${!var:-}" ]]; then printf '%s' "${!var}"; else printf '%s' "$def"; fi if [[ -n "$var" && -n "${!var:-}" ]]; then printf '%s' "${!var}"; else printf '%s' "$def"; fi
} }
@@ -267,6 +274,7 @@ resolve_tool_path() {
opencode) bin="opencode" ;; openclaw) bin="openclaw" ;; cursor) bin="cursor" ;; opencode) bin="opencode" ;; openclaw) bin="openclaw" ;; cursor) bin="cursor" ;;
aider) bin="aider" ;; windsurf) bin="windsurf" ;; qwen) bin="qwen" ;; aider) bin="aider" ;; windsurf) bin="windsurf" ;; qwen) bin="qwen" ;;
kimi) bin="kimi" ;; codex) bin="codex" ;; antigravity) bin="" ;; kimi) bin="kimi" ;; codex) bin="codex" ;; antigravity) bin="" ;;
osaurus) bin="osaurus" ;;
esac esac
[[ -n "$bin" ]] && command -v "$bin" 2>/dev/null [[ -n "$bin" ]] && command -v "$bin" 2>/dev/null
} }
@@ -363,6 +371,7 @@ detect_windsurf() { command -v windsurf >/dev/null 2>&1 || [[ -d "${HOME}/.c
detect_qwen() { command -v qwen >/dev/null 2>&1 || [[ -d "${HOME}/.qwen" ]]; } detect_qwen() { command -v qwen >/dev/null 2>&1 || [[ -d "${HOME}/.qwen" ]]; }
detect_kimi() { command -v kimi >/dev/null 2>&1; } detect_kimi() { command -v kimi >/dev/null 2>&1; }
detect_codex() { command -v codex >/dev/null 2>&1 || [[ -d "${HOME}/.codex" ]]; } detect_codex() { command -v codex >/dev/null 2>&1 || [[ -d "${HOME}/.codex" ]]; }
detect_osaurus() { command -v osaurus >/dev/null 2>&1 || [[ -d "${HOME}/.osaurus" ]]; }
is_detected() { is_detected() {
case "$1" in case "$1" in
@@ -378,6 +387,7 @@ is_detected() {
qwen) detect_qwen ;; qwen) detect_qwen ;;
kimi) detect_kimi ;; kimi) detect_kimi ;;
codex) detect_codex ;; codex) detect_codex ;;
osaurus) detect_osaurus ;;
*) return 1 ;; *) return 1 ;;
esac esac
} }
@@ -397,6 +407,7 @@ tool_label() {
qwen) printf "%-14s %s" "Qwen Code" "(~/.qwen/agents)" ;; qwen) printf "%-14s %s" "Qwen Code" "(~/.qwen/agents)" ;;
kimi) printf "%-14s %s" "Kimi Code" "(~/.config/kimi/agents)" ;; kimi) printf "%-14s %s" "Kimi Code" "(~/.config/kimi/agents)" ;;
codex) printf "%-14s %s" "Codex" "(~/.codex/agents)" ;; codex) printf "%-14s %s" "Codex" "(~/.codex/agents)" ;;
osaurus) printf "%-14s %s" "Osaurus" "(~/.osaurus/skills)" ;;
esac esac
} }
@@ -520,7 +531,7 @@ tool_simple_name() {
claude-code) echo "Claude Code";; copilot) echo "Copilot";; antigravity) echo "Antigravity";; claude-code) echo "Claude Code";; copilot) echo "Copilot";; antigravity) echo "Antigravity";;
gemini-cli) echo "Gemini CLI";; opencode) echo "OpenCode";; openclaw) echo "OpenClaw";; gemini-cli) echo "Gemini CLI";; opencode) echo "OpenCode";; openclaw) echo "OpenClaw";;
cursor) echo "Cursor";; aider) echo "Aider";; windsurf) echo "Windsurf";; cursor) echo "Cursor";; aider) echo "Aider";; windsurf) echo "Windsurf";;
qwen) echo "Qwen Code";; kimi) echo "Kimi Code";; codex) echo "Codex";; *) echo "$1";; qwen) echo "Qwen Code";; kimi) echo "Kimi Code";; codex) echo "Codex";; osaurus) echo "Osaurus";; *) echo "$1";;
esac esac
} }
@@ -719,6 +730,23 @@ install_antigravity() {
ok "Antigravity: $count skills -> $dest" ok "Antigravity: $count skills -> $dest"
} }
install_osaurus() {
local src="$INTEGRATIONS/osaurus"
local dest; dest="$(resolve_dest osaurus "${HOME}/.osaurus/skills")"
local count=0
[[ -d "$src" ]] || { err "integrations/osaurus missing. Run convert.sh first."; return 1; }
mkdir -p "$dest"
local d
while IFS= read -r -d '' d; do
local name; name="$(basename "$d")"
slug_allowed "$name" || continue
mkdir -p "$dest/$name"
install_file "$d/SKILL.md" "$dest/$name/SKILL.md"
incr count
done < <(find "$src" -mindepth 1 -maxdepth 1 -type d -print0)
ok "Osaurus: $count skills -> $dest"
}
install_gemini_cli() { install_gemini_cli() {
local src="$INTEGRATIONS/gemini-cli/agents" local src="$INTEGRATIONS/gemini-cli/agents"
local dest; dest="$(resolve_dest gemini-cli "${HOME}/.gemini/agents")" local dest; dest="$(resolve_dest gemini-cli "${HOME}/.gemini/agents")"
@@ -912,6 +940,7 @@ install_tool() {
qwen) install_qwen ;; qwen) install_qwen ;;
kimi) install_kimi ;; kimi) install_kimi ;;
codex) install_codex ;; codex) install_codex ;;
osaurus) install_osaurus ;;
esac esac
} }
-2
View File
@@ -18,7 +18,6 @@ AGENT_DIRS=(
finance finance
game-development game-development
gis gis
integrations
marketing marketing
paid-media paid-media
product product
@@ -27,7 +26,6 @@ AGENT_DIRS=(
security security
spatial-computing spatial-computing
specialized specialized
strategy
support support
testing testing
) )
+18
View File
@@ -0,0 +1,18 @@
{
"_note": "Source of truth for the supported tool set. Keyed by the CLI tool name (kebab). Each entry carries the install contract (id, detect dirs, dest templates, render `format`, scope, version cmd) plus app presentation (label, short, accent, icon, order). aa converts + installs ALL listed tools. `format` is the renderer contract: the same `format` name guarantees byte-identical output, so two tools may share a format only if their rendered files are identical. Consumers (the Agency Agents app, scripts/convert.sh, scripts/install.sh) derive any per-format capability — e.g. whether the app ships a native renderer — from `format` against their own set; the catalog carries NO app-release state. scripts/check-tools.sh (CI) fails the build if this disagrees with ALL_TOOLS in install.sh or the converter set in convert.sh, or if any entry is missing id/label/kebab/format/dest. Add a tool: add an entry here, a convert_<tool> (or reuse a `format`) in convert.sh, and an install_<tool> in install.sh, then run scripts/check-tools.sh.",
"tools": {
"claude-code": {"id":"claudeCode","label":"Claude Code","short":"Claude","kebab":"claude-code","accent":"#D97757","icon":"claudecode","order":1,"scope":{"user":true,"project":true},"detect":{"dirs":[".claude"],"agentsDir":".claude/agents"},"version":{"bin":"claude","args":["--version"]},"format":"identity","slugFrom":"source","dest":{"user":[".claude/agents/{slug}.md"],"project":[".claude/agents/{slug}.md"]}},
"codex": {"id":"codex","label":"Codex","short":"Codex","kebab":"codex","accent":"#10A37F","icon":"codex","order":2,"scope":{"user":true,"project":true},"detect":{"dirs":[".codex"],"agentsDir":".codex/agents"},"version":{"bin":"codex","args":["--version"]},"format":"codex-toml","slugFrom":"name","dest":{"user":[".codex/agents/{slug}.toml"],"project":[".codex/agents/{slug}.toml"]}},
"gemini-cli": {"id":"geminiCli","label":"Gemini CLI","short":"Gemini","kebab":"gemini-cli","accent":"#4285F4","icon":"geminicli","order":3,"scope":{"user":true,"project":true},"detect":{"dirs":[".gemini/agents"],"agentsDir":".gemini/agents"},"version":{"bin":"gemini","args":["--version"]},"format":"gemini-md","slugFrom":"name","dest":{"user":[".gemini/agents/{slug}.md"],"project":[".gemini/agents/{slug}.md"]}},
"copilot": {"id":"copilot","label":"GitHub Copilot","short":"Copilot","kebab":"copilot","accent":"#6E40C9","icon":"githubcopilot","order":4,"scope":{"user":true,"project":true},"detect":{"dirs":[".github",".copilot"],"agentsDir":".github/agents"},"version":{"bin":"gh","args":["copilot","--version"]},"format":"identity","slugFrom":"source","dest":{"user":[".copilot/agents/{slug}.md",".github/agents/{slug}.md"],"project":[".github/agents/{slug}.md"]}},
"qwen": {"id":"qwen","label":"Qwen Code","short":"Qwen","kebab":"qwen","accent":"#615CED","icon":"qwen","order":5,"scope":{"user":true,"project":true},"detect":{"dirs":[".qwen"],"agentsDir":".qwen/agents"},"version":{"bin":"qwen","args":["--version"]},"format":"qwen-md","slugFrom":"name","dest":{"user":[".qwen/agents/{slug}.md"],"project":[".qwen/agents/{slug}.md"]}},
"cursor": {"id":"cursor","label":"Cursor","short":"Cursor","kebab":"cursor","accent":"#1F2430","icon":"cursor","order":6,"scope":{"user":false,"project":true},"detect":{"dirs":[".cursor"],"agentsDir":null},"version":{"bin":"cursor","args":["--version"]},"format":"cursor-mdc","slugFrom":"name","dest":{"user":[],"project":[".cursor/rules/{slug}.mdc"]}},
"opencode": {"id":"opencode","label":"opencode","short":"opencode","kebab":"opencode","accent":"#FF6B35","icon":"opencode","order":7,"scope":{"user":true,"project":true},"detect":{"dirs":[".config/opencode"],"agentsDir":null},"version":{"bin":"opencode","args":["--version"]},"format":"opencode-md","slugFrom":"name","dest":{"user":[".config/opencode/agents/{slug}.md"],"project":[".opencode/agents/{slug}.md"]}},
"osaurus": {"id":"osaurus","label":"Osaurus","short":"Osaurus","kebab":"osaurus","accent":"#10B981","icon":null,"order":8,"scope":{"user":true,"project":false},"detect":{"dirs":[".osaurus"],"agentsDir":".osaurus/skills"},"version":{"bin":"osaurus","args":["--version"]},"format":"skill-md","slugFrom":"name","slugPrefix":"agency-","dest":{"user":[".osaurus/skills/{slug}/SKILL.md"],"project":[]}},
"aider": {"id":"aider","label":"Aider","short":"Aider","kebab":"aider","accent":"#8B5CF6","icon":null,"order":9,"scope":{"user":false,"project":true},"detect":{"dirs":[],"agentsDir":null},"version":{"bin":"aider","args":["--version"]},"format":"aider-conventions","slugFrom":null,"dest":{"user":[],"project":["CONVENTIONS.md"]}},
"antigravity": {"id":"antigravity","label":"Antigravity","short":"antigravity","kebab":"antigravity","accent":"#0EA5E9","icon":"antigravity","order":10,"scope":{"user":true,"project":false},"detect":{"dirs":[".gemini/antigravity/skills"],"agentsDir":".gemini/antigravity/skills"},"version":{"bin":"agy","args":["--version"]},"format":"antigravity-skill","slugFrom":"name","slugPrefix":"agency-","dest":{"user":[".gemini/antigravity/skills/{slug}/SKILL.md"],"project":[]}},
"kimi": {"id":"kimi","label":"Kimi","short":"Kimi","kebab":"kimi","accent":"#0F0F12","icon":"kimi","order":11,"scope":{"user":true,"project":false},"detect":{"dirs":[],"agentsDir":".config/kimi/agents"},"version":{"bin":"kimi","args":["--version"]},"format":"kimi-agent","slugFrom":"name","dest":{"user":[".config/kimi/agents/{slug}/agent.yaml",".config/kimi/agents/{slug}/system.md"],"project":[]}},
"openclaw": {"id":"openclaw","label":"OpenClaw","short":"openclaw","kebab":"openclaw","accent":"#E11D48","icon":null,"order":12,"scope":{"user":true,"project":false},"detect":{"dirs":[".openclaw"],"agentsDir":".openclaw/agency-agents"},"version":{"bin":"openclaw","args":["--version"]},"format":"openclaw-workspace","slugFrom":"name","dest":{"user":[".openclaw/agency-agents/{slug}/SOUL.md",".openclaw/agency-agents/{slug}/AGENTS.md",".openclaw/agency-agents/{slug}/IDENTITY.md"],"project":[]}},
"windsurf": {"id":"windsurf","label":"Windsurf","short":"Windsurf","kebab":"windsurf","accent":"#09B6A2","icon":"windsurf","order":13,"scope":{"user":false,"project":true},"detect":{"dirs":[".codeium"],"agentsDir":null},"version":{"bin":"windsurf","args":["--version"]},"format":"windsurf-rules","slugFrom":null,"dest":{"user":[],"project":[".windsurfrules"]}}
}
}