- discovery/frontmatter contract incl. the bare->/| subset limit - bundled table with upstream provenance and adaptation rules - install target semantics, sidecar shape, maintenance workflow - wired in AGENTS.md, README layout; drift test in BundledSkillsTests
120 lines
6.8 KiB
Markdown
120 lines
6.8 KiB
Markdown
# skills.md
|
|
|
|
The skill system and the bundled default skills: discovery contract,
|
|
frontmatter subset, the six shipped skills with their upstream provenance
|
|
and tai adaptations, install semantics, and maintenance.
|
|
|
|
## The system
|
|
|
|
Skills are directories containing a `SKILL.md` file with `name` plus
|
|
`description` frontmatter, optionally with `scripts/`, `references/`, and
|
|
`assets/` alongside (the open Agent Skills layout). Discovery
|
|
(`discover_skills`) scans four roots and the most tai-specific one wins a
|
|
name collision: `~/.claude/skills` and `<project>/.claude/skills` /
|
|
`<project>/.agents/skills` first (external, read-only interop), then
|
|
`~/.tai/skills` and `<project>/.tai/skills` (managed).
|
|
|
|
`load_skill` returns the body plus a provenance note plus the absolute
|
|
paths of the top-level entries under `scripts/`, `references/`, and
|
|
`assets/` (`skill_extra_files`, not recursive: a nested directory shows up
|
|
as its own path and the agent descends from there). Descriptions ride the
|
|
system-prompt catalog truncated to 300 characters; bodies load on demand.
|
|
|
|
Frontmatter is a deliberate subset, not YAML (`parse_skill_front`): one
|
|
`key: value` per line, double-quoted values have their outer quotes
|
|
stripped, unknown keys are ignored, and only bare `>` (fold with spaces)
|
|
and `|` (join with newlines) continue a value onto indented lines.
|
|
Chomping variants (`>-`, `|-`, `>+`, `|+`) do NOT parse: a `>-`
|
|
description reads back as the literal string `">-"` and the folded lines
|
|
are dropped. Shipped skills must use single-line descriptions.
|
|
|
|
Missing skills with a `SKILL_BLUEPRINTS` entry are researched and built on
|
|
first `load_skill` (`bot-creator`, `api-client`, `web-researcher`,
|
|
`pdf-forms`, `data-wrangler`, `home-sysadmin`); anything else is an
|
|
"unknown skill" error listing what exists.
|
|
|
|
## Bundled skills
|
|
|
|
Six skills ship inside `tai.py` itself (`BUNDLED_SKILLS`, 21 files) so a
|
|
bare copy installs them anywhere. Upstream provenance per skill lives in
|
|
`BUNDLED_SKILL_UPSTREAM` and is copied into each installed sidecar.
|
|
|
|
| Skill | Files | Upstream | Status |
|
|
|---|---|---|---|
|
|
| `deep-research` | 6 (`SKILL.md`, 4 `references/`, `UPSTREAM.md`) | author's Muse user skill (itself from `wanqingying/debian-railway`, see `UPSTREAM.md`) | adapted |
|
|
| `seriousdevelopment` | 10 (`SKILL.md`, `CHANGELOG.md`, 8 `assets/templates/`) | author's Muse user skill v1.7.1 | verbatim |
|
|
| `git` | 2 (`SKILL.md`, `scripts/workspace-recovery.sh`) | Muse's bundled set | adapted |
|
|
| `plan` | 1 (`SKILL.md`) | Muse's bundled set | adapted |
|
|
| `requirements-clarification` | 1 (`SKILL.md`) | Muse's bundled set | adapted |
|
|
| `taste` | 1 (`SKILL.md`) | Muse's bundled set | one word |
|
|
|
|
`seriousdevelopment` is byte-identical to upstream: it carries no host
|
|
references and no em dashes. Everything else changed only where the host
|
|
leaks through; the method prose is untouched.
|
|
|
|
## Adaptation rules
|
|
|
|
Each rule below was applied everywhere its token appeared, and
|
|
`BundledSkillsTests.test_embedded_content_guards` fails if any of them
|
|
regresses:
|
|
|
|
| Upstream token | Tai equivalent | Why |
|
|
|---|---|---|
|
|
| `read_skill` | `load_skill` | tai's loader is named `load_skill` |
|
|
| `request_user_input` / `request_user_input_async` (+ `auto_resolution_ms`) | `ask_user` (question plus options, blocks; unavailable to workers and autonomous mode, decide and state the assumption there) | tai's only question tool blocks and has no async form |
|
|
| subagent / `Task` / `explore` workers, wait-call mechanics | `fork` (task plus timeout up to one hour) / `poll` (up to two minutes per call, loop until done); workers get 12 steps, no questions, nesting depth 2, 8 live max | tai's orchestration primitives and their real caps |
|
|
| `curl` recipes, `curl` commands | `web_fetch` GET with the same URL and headers | tai forbids curl and wget via shell; every recipe is a plain GET so nothing is lost (`auth_secret` covers the token case) |
|
|
| `webfetch` / `websearch` | `web_fetch` / `web_search` | tai's tool names |
|
|
| `/plan`, `/skill plan` | prose request or `load_skill` | tai has no slash-command skill routes |
|
|
| `>-` folded description | single-line description | the frontmatter subset (above) |
|
|
| em dash (U+2014) | hyphen | project prose rule, no exceptions |
|
|
|
|
Two judgment calls beyond mechanical mapping:
|
|
|
|
- `git` got an "Authorization in tai" paragraph: its never-commit rule
|
|
would otherwise veto the user's standing auto-commit rule, so history
|
|
writes follow the session's approval setting while the recovery
|
|
snapshot, lock discipline, and named-files rules still apply as
|
|
written. The `<git-skill-dir>` placeholder became `<recovery>`, bound
|
|
to the absolute script path from the bundled-files list.
|
|
- `deep-research` briefs still hand workers literal URLs even though tai
|
|
workers could read the skill directory: inline URLs keep briefs
|
|
self-contained under the 12-step budget.
|
|
|
|
## Install target
|
|
|
|
`skills` is the twelfth `INSTALL_TARGETS` entry, implemented by
|
|
`op_skills` on top of `write_bundled_skill` / `remove_bundled_skill`,
|
|
included in bare `./tai.py --install` and refreshable via the `install`
|
|
tool or `/install`. All six land in home scope (`~/.tai/skills`); project scope
|
|
never receives bundled skills. After any non-status action through the
|
|
tool, the live session re-runs discovery so the skills are usable without
|
|
a restart.
|
|
|
|
| Action | Semantics |
|
|
|---|---|
|
|
| `install` | writes missing skills only; a present `SKILL.md` means "already present", never an overwrite |
|
|
| `upgrade` | rewrites files that are missing or already equal; differing files are kept untouched and named loudly (`kept modified`) |
|
|
| `reinstall` | force-rewrites every tracked file, including user edits; user-added extra files still survive |
|
|
| `uninstall` | removes tracked files that still match (plus orphan sidecars); user-modified and user-added files stay, named loudly, with their sidecar |
|
|
| `status` | one line: `skills: P/6 bundled present`, plus `missing:` and `modified:` lists when non-empty |
|
|
|
|
The `.installs/<name>.json` sidecar records `source: tai-bundled`,
|
|
`mode: bundled`, `scope: home`, the `upstream` locator, the
|
|
`bundled_version` that wrote it, per-file sha8 `files`, and
|
|
`installed_at`. `load_skill` renders this as `[installed bundled, home
|
|
scope, from tai-bundled]`. The sidecar is rewritten only when a write
|
|
leaves zero kept files, so user edits are never re-baselined as
|
|
pristine behind their back.
|
|
|
|
## Maintenance
|
|
|
|
The embedded copies ARE the source: fix typos and drift directly in
|
|
`BUNDLED_SKILLS`, never by re-copying upstream over them (re-copying
|
|
would silently drop the adaptations above). To pull a new upstream
|
|
version of one skill: diff upstream against the embedded copy, re-apply
|
|
the adaptation rules to the new text, re-embed, and confirm the guard
|
|
test plus a fresh install round-trip. Raw strings keep backslashes
|
|
byte-exact, so no embedded file may contain a triple-double-quote or
|
|
end in a backslash; the guard test enforces the quote half.
|