Commit 5d26909
authored
feat(skills): SKILL.md loader, validator, discovery + gaia skill CLI core (#2669)
Nothing in GAIA could read a `SKILL.md` before this. An agent gained
capability only by shipping new Python, so a user who wanted a new one
had no path short of forking the agent — and the large library of skills
already published for Claude Code and friends was unreachable. Now a
folder with a `SKILL.md` drops into `~/.gaia/skills/` and any agent
loads it at runtime with `agent.load_skill("name")`, and an existing
`.claude/skills/` library is discovered read-only with zero migration
(this repo's own 11 skills load unchanged). This is Phase 1 of #1019 —
the layer #2466, #2467, #2468, #893, and #692 are all blocked on.
Scoped deliberately so no sandbox is needed to ship it: a skill may add
instructions and reach connector-backed services, and one declaring a
local-capability permission
(`filesystem`/`shell`/`database`/`desktop`/`env`) is **refused with an
actionable error** rather than loaded without enforcement. `network:*`
and `mcp:connect` resolve to the existing `ConnectorRequirement` — no
second grant ledger.
### Decisions taken where the specs were silent
- `mcp:connect` must be scoped to a catalog connector id
(`mcp:connect:mcp-tavily`); a bare one fails loudly listing the
available ids. A `network:*` permission that names no catalog connector
resolves against a reserved `network` pseudo-id — a **declaration**
surface only, since Phase 1 does not enforce egress.
- `<domain>:none` is inert in both directions: it grants nothing, so it
neither refuses nor produces a requirement.
- `tools_required` names that aren't in the current agent's registry are
logged, not fatal — the tool universe is assembled dynamically from
mixins, so absence is scoping, not a manifest defect (the open question
in `skill-format.mdx`).
- Discovery trims the spec's five roots to three; project-local
`./.gaia/skills/` and the registry-lock root are marked deferred in the
spec, not deleted.
- `src/gaia/schedule/runner.py` and the `gaia schedule add --skill` gate
told users their problem was "blocked on #888" — a claim this PR makes
false on merge. Reworded to point at #1019, where wiring the scheduler
to the skills runtime actually lives; that is why those files (and their
two tests) are in the diff.
- Three of `skill-format.mdx`'s own example skills (`rag-search`,
`file-operations`, migrated `git-status`) declare local-capability
permissions and are therefore refused today. The doc now marks which
examples load rather than quietly rewriting their permissions.
### Test plan
- [ ] `python -m pytest tests/unit/test_skills_format.py
tests/unit/test_skills_manager.py tests/unit/test_skills_cli.py -q` —
150 tests, one per acceptance-criterion bullet
- [ ] Round-trip identity: `parse → write → parse` on every fixture, and
byte-stability on a second write
- [ ] A bare agentskills.io skill (only `name` + `description`) loads
instruction-only at `security_tier: experimental`; writing it back does
**not** stamp a `metadata.gaia` block into it
- [ ] `load_skill` registers tools as `<skill>/<tool>` and injects the
body — including when the skill's unqualified tool name collides with
one the framework already registered
- [ ] A manifest that contradicts `tools.py` (missing tool, undeclared
extra, parameter/requiredness/type mismatch, raising module) leaves
`_TOOL_REGISTRY` byte-identical — assert on the whole dict, not just the
absent key
- [ ] A `filesystem:write` skill is refused via `Agent.load_skill`
**and** via the lower-level `register_skill_tools`
- [ ] Precedence: the same skill in all three roots resolves to the
agent-bundled copy; the shadowed copies stay visible via
`SkillManager.shadowed()` and in `gaia skill list`
- [ ] Real CLI, cold `GAIA_CONFIG_DIR`: `gaia skill create` → `list` →
`info` → `export` → `import` into a second home, plus `--json` stdout
parsing cleanly with logs on stderr
- [ ] `python -m pytest tests/unit/ -q` — the 16 failures on this
machine reproduce identically on an untouched `main` checkout (macOS
`/private/var` sandbox paths, network-dependent hub installer, missing
faiss, venv-not-on-PATH)
- [ ] `python util/lint.py --all` clean
Closes #8881 parent 0ae019c commit 5d26909
30 files changed
Lines changed: 4844 additions & 154 deletions
File tree
- docs
- plans
- reference
- spec
- src/gaia
- agents/base
- schedule
- skills
- tests
- fixtures/skills
- bare-standard
- incident-review
- local-capability
- tool-mismatch
- triage-support-ticket
- web-search
- unit
- cli
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2065 | 2065 | | |
2066 | 2066 | | |
2067 | 2067 | | |
| 2068 | + | |
| 2069 | + | |
| 2070 | + | |
| 2071 | + | |
| 2072 | + | |
| 2073 | + | |
| 2074 | + | |
| 2075 | + | |
| 2076 | + | |
| 2077 | + | |
| 2078 | + | |
| 2079 | + | |
| 2080 | + | |
| 2081 | + | |
| 2082 | + | |
| 2083 | + | |
| 2084 | + | |
| 2085 | + | |
| 2086 | + | |
| 2087 | + | |
| 2088 | + | |
| 2089 | + | |
| 2090 | + | |
| 2091 | + | |
| 2092 | + | |
| 2093 | + | |
| 2094 | + | |
| 2095 | + | |
| 2096 | + | |
| 2097 | + | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
| 2102 | + | |
| 2103 | + | |
| 2104 | + | |
| 2105 | + | |
| 2106 | + | |
| 2107 | + | |
| 2108 | + | |
| 2109 | + | |
| 2110 | + | |
| 2111 | + | |
| 2112 | + | |
| 2113 | + | |
| 2114 | + | |
| 2115 | + | |
| 2116 | + | |
| 2117 | + | |
| 2118 | + | |
| 2119 | + | |
| 2120 | + | |
| 2121 | + | |
| 2122 | + | |
| 2123 | + | |
| 2124 | + | |
| 2125 | + | |
| 2126 | + | |
| 2127 | + | |
| 2128 | + | |
| 2129 | + | |
| 2130 | + | |
| 2131 | + | |
| 2132 | + | |
| 2133 | + | |
| 2134 | + | |
| 2135 | + | |
| 2136 | + | |
| 2137 | + | |
| 2138 | + | |
| 2139 | + | |
| 2140 | + | |
| 2141 | + | |
| 2142 | + | |
| 2143 | + | |
| 2144 | + | |
| 2145 | + | |
| 2146 | + | |
| 2147 | + | |
| 2148 | + | |
| 2149 | + | |
| 2150 | + | |
| 2151 | + | |
| 2152 | + | |
| 2153 | + | |
| 2154 | + | |
| 2155 | + | |
| 2156 | + | |
| 2157 | + | |
| 2158 | + | |
| 2159 | + | |
| 2160 | + | |
| 2161 | + | |
| 2162 | + | |
| 2163 | + | |
| 2164 | + | |
| 2165 | + | |
| 2166 | + | |
| 2167 | + | |
| 2168 | + | |
| 2169 | + | |
| 2170 | + | |
| 2171 | + | |
| 2172 | + | |
| 2173 | + | |
| 2174 | + | |
| 2175 | + | |
| 2176 | + | |
| 2177 | + | |
| 2178 | + | |
| 2179 | + | |
| 2180 | + | |
| 2181 | + | |
| 2182 | + | |
| 2183 | + | |
| 2184 | + | |
| 2185 | + | |
| 2186 | + | |
| 2187 | + | |
| 2188 | + | |
| 2189 | + | |
| 2190 | + | |
| 2191 | + | |
| 2192 | + | |
| 2193 | + | |
| 2194 | + | |
| 2195 | + | |
| 2196 | + | |
| 2197 | + | |
| 2198 | + | |
| 2199 | + | |
| 2200 | + | |
| 2201 | + | |
| 2202 | + | |
| 2203 | + | |
| 2204 | + | |
| 2205 | + | |
| 2206 | + | |
| 2207 | + | |
| 2208 | + | |
| 2209 | + | |
| 2210 | + | |
| 2211 | + | |
| 2212 | + | |
| 2213 | + | |
| 2214 | + | |
| 2215 | + | |
| 2216 | + | |
| 2217 | + | |
| 2218 | + | |
| 2219 | + | |
| 2220 | + | |
| 2221 | + | |
| 2222 | + | |
| 2223 | + | |
2068 | 2224 | | |
2069 | 2225 | | |
2070 | 2226 | | |
| |||
2149 | 2305 | | |
2150 | 2306 | | |
2151 | 2307 | | |
2152 | | - | |
| 2308 | + | |
2153 | 2309 | | |
2154 | 2310 | | |
2155 | 2311 | | |
| |||
3077 | 3233 | | |
3078 | 3234 | | |
3079 | 3235 | | |
| 3236 | + | |
| 3237 | + | |
| 3238 | + | |
3080 | 3239 | | |
3081 | 3240 | | |
3082 | 3241 | | |
| |||
0 commit comments