# Agent Instructions — Editing Skills ## Two kinds of skills **Integration skills** document how to use a specific external tool or API — non-obvious flags, auth gotchas, silent failure modes. They may (and should) name the tool, show CLI commands, and reference binary names directly. They declare `provides` in metadata. **Workflow skills** describe how to carry out a process. They are tool-agnostic by design: they declare `requires` in metadata and reference only capability names in their body — never tool names, binary names, CLI flags, or other skill names. **CLI providers** — when a tool has comprehensive `--help`, map the capability to `cli://` in `capabilities.yaml` instead of writing a wrapper skill. Only write an integration skill when there are genuine gotchas that help text won't surface. ### Integration skill provider preference When a capability is fulfilled by a CLI, prefer providers in this order (simplest first, fall through when the previous tier doesn't fit): 1. **Pure CLI.** If `--help` is sufficient, just map `: cli://` in `capabilities.yaml`. The default for self-explanatory tools. 2. **CLI with capability notes.** If the CLI has good `--help` plus one or two gotchas, map `: { provider: cli://, notes: "..." }`. No skill file needed. 3. **External skill from the CLI maintainer.** If the CLI ships a SKILL.md upstream (e.g. `BRO3886/ical`, `schpet/linear-cli`), install it via `gh skill install` declared in `.chezmoidata/packages.yaml: skills:`. The maintainer owns the gotchas; updates flow automatically. 4. **Local integration skill.** When no upstream skill exists but the CLI has gotchas that don't fit in `notes:`, write a local skill in `skills//SKILL.md` with `provides: []`. This is the consolation pattern — keep it until an adequate upstream skill appears. When evaluating an existing local integration skill, ask: does an upstream skill exist now? If yes, switch. #### Watchlist — local integrations to upstream when an adequate skill appears | Local skill | Upstream candidate to watch | |---|---| | `slack` | A maintained Slack CLI on `gh skill install` discoverable, or an Anthropic-published Slack skill bundle | | `gh` (provides `source-control`, `ci`, `automated-review`) | `cli/cli` shipping a SKILL.md, or a community skill bundle for inline review/CI patterns | | `figma` | Figma maintainer publishing a SKILL.md alongside the REST API docs | | `elasticsearch` | An ES-maintained or APM-vendor skill bundle for log/trace queries | Re-evaluate during each `/audit` run. **When using any CLI capability, read `--help` first.** Run ` --help` and ` --help` before issuing commands. Integration skills document only what help text won't tell you — silent failures, wrong-output traps, and non-obvious cross-command dependencies. Everything else is in `--help`. **For short gotchas (1-3 sentences), use the `notes` field in `capabilities.yaml` instead of a skill file.** The manifest supports an extended map form: ```yaml # flat form — no gotchas issues: cli://linear # extended form — with notes calendar: provider: cli://ical notes: "Timestamps in JSON output are UTC — always convert to local before displaying." ``` Use a skill file when the guidance needs examples, command references, or spans more than a few sentences. Use `notes` for single silent-failure facts. ## The mechanism: `requires` + manifest The manifest (`~/.agents/capabilities.yaml`) is the registry. It maps capability names to providers — a skill name, `cli://`, or `mcp://`. Workflow skills declare what they need: ```yaml metadata: requires: - code-review - issues - ci ``` `requires` is a YAML list of capability names — **no colons, no defaults**. `provides` is optional author metadata for discoverability. The manifest is authoritative, not skill frontmatter. **Workflow skills that no other skill consumes correctly omit `provides`.** Examples: `attention`, `conversations`, `context-log`, `post-meeting`, `thinking-tools`. They orchestrate capabilities for direct invocation; nothing depends on them, so there's no capability to declare. Adding a `provides` here is noise. ## Capability naming Capability names must be **provider-agnostic** — they name the domain, not the tool. | Good (domain) | Bad (tool-specific) | |---|---| | `code-review` | `pull-requests`, `github-prs` | | `issues` | `linear-issues`, `jira` | | `calendar` | `ical`, `gcal` | | `chat` | `slack` | | `ci` | `github-actions` | If the name would only make sense with one specific tool, it's wrong. ## Coupling violations A **coupling violation** is any reference in a workflow skill body (or its included sub-files) to: - A CLI binary name: `gh`, `git`, `linear`, `sqlite3`, `opencode`, `jq`, `curl`, etc. - A specific skill name: `` `load the slack skill` ``, `` `the architecture skill` `` - An MCP tool name: `context7`, `webfetch` (when used as a named tool, not a concept) - A platform-specific term as a noun: "pull request", "PR" (use "merge request" or "code review request") **These are always violations in workflow skill bodies**, regardless of how reasonable they seem in context. **These are never violations** in integration skill bodies or their sub-files — that's exactly where tool-specific content belongs. ### Examples | Violation | Fix | |---|---| | `` `gh pr view`, `gh pr diff` `` | `use your \`code-review\` capability` | | `gh api graphql -f query='...'` | `use your \`code-review\` capability` | | `load the \`commit\` skill` | `use your \`commit\` capability` | | `the \`architecture\` skill Section 2` | `the \`architecture\` capability Section 2` | | `via \`gq\`` | remove — capability reference is sufficient | | `` `gh repo view --json visibility` `` | `use your \`code-review\` capability` | | `context7` (in workflow body) | `your documentation lookup capability` | | "PR", "pull request" (in workflow body) | "merge request" or "code review request" | ## Adding a skill 1. Determine: integration or workflow? 2. If workflow: - Add `requires` listing the capabilities it needs - In the body, reference only capability names — never tools, binaries, or other skills - Name capabilities after domains, not tools - Add a manifest entry in `dot_agents/capabilities.yaml` if the capability isn't already mapped 3. If integration: - Add `provides` listing the capability name(s) this skill implements - Tool-specific content is expected and correct here 4. Run `agentskills validate` on the skill directory ## Don't expose machine-specific configuration This is a public repository. Skill bodies must not hard-code values that are configured per-workspace in an external system: template names, project names, team keys, channel names, account IDs, internal URLs, or anything that's a label inside someone's tool. These vary by user and won't apply to anyone else who clones this repo. Instead, teach the agent how to *discover* the values at runtime — show the query, command, or config file that surfaces them, so each user sees their own. Examples that need this treatment: list templates via the integration's API, read repo-level template files (`.github/ISSUE_TEMPLATE/`), check workspace config (`.linear.toml`, `orgs..*`). If the value is a true public constant of the tool (a documented endpoint URL, a stable command name, a published vocabulary term), it can be hard-coded. ## Editing an existing skill **Before adding any content to a workflow skill**, scan the section you're editing for existing violations and fix them. Do not add new content that would introduce a violation. After editing, re-read the full body of the skill and ask: "If this skill were used with a different tool provider, would this line still make sense?" If not, it's a violation. ## Sub-files Sub-files (`.md` files referenced from a SKILL.md) inherit the type of their parent skill. A sub-file of a workflow skill is also a workflow skill and must follow the same rules. A sub-file of an integration skill may contain tool-specific content. ## When something shouldn't be a skill Before writing a skill, ask what the trigger looks like. Three patterns map to three primitives, only one of them being a skill: | Trigger pattern | Right primitive | Example | |---|---|---| | Continuous — applies to every session of some kind | Instructions file (`opencode.json`'s `instructions:` array) | TDD: every code-change session, write the failing test first. Lives in `dot_config/opencode/tdd.md`, always loaded. | | Mode-restricted — needs different tool/skill access than the default agent | Built-in or custom agent + `permission` config | Plan: read-only deliberation. Built-in plan agent (Tab) with its own skill allow-list. Build agent denies the deliberation skills. | | Concrete moment — fires at a specific, named point in a workflow | Skill (SKILL.md) | Commit, push, review, qa — each has a clear trigger ("about to commit"). | Signs you're building the wrong primitive: - "This skill should fire on every code change." → it's an instructions file, not a skill. - "Build agent shouldn't see this skill." → use `permission.skill` deny on build, not a skill body that tells the agent when to skip. - "This skill orchestrates several other skills." → see the orchestrator failure section below. When the data shows a skill is underperforming its trigger (low load rate when the moment clearly happened), the fix is usually relocating to the right primitive, not redesigning the skill description. ## Skill shape — lessons from the orchestrator failure A previous "process" skill declared ten required capabilities and an eight-phase workflow. Measured across 69 sessions: TDD compliance fell from 34% to 9%, and architecture capability loading fell from 26% to 7%, **when the orchestrator was loaded vs. not**. The orchestrator actively suppressed the capabilities it wrapped. The rules below are the generalized lessons — follow them when creating or editing any skill. ### One skill = one trigger = one moment of action A skill should fire at a specific, concrete moment. If you find yourself writing "Phase 1… Phase 2… Phase 3…" or "After step N, also do X," you are building an orchestrator. Split instead. Signs a skill is becoming an orchestrator: - A single skill covers multiple distinct moments in a workflow (e.g., one that governs both pre-commit and post-commit behavior) - `provides` lists more than one capability whose triggers fire at different times - Step N of the skill says "do this other thing from a different capability" Split rule: **split by when the skill fires, not by what topic it covers.** Two skills that both cover "git stuff" but fire at different moments (commit-time vs. push-time) are correctly separate. One skill that covers "commit and format conventions" is correctly one skill because both fire at commit-time. ### Agents read long phase graphs as menus A long workflow skill is not read as imperatives — it is read as a list the agent skim-selects from. The action phases (implement, commit, push) get executed; the deliberative phases (plan, verify, capture) get skipped. This is why the process skill suppressed TDD — TDD was mentioned inside a phase list, not as a standing imperative. The fix that worked: TDD became an always-loaded instructions file, not a skill at all. Corollary: short, standalone skills with concrete triggers outperform long skills with phase graphs, even when the long skill formally `requires` the same capabilities. ### Indirection beyond one hop is not followed Measured: sub-files referenced from a parent skill were loaded in 4% of sessions that loaded the parent. A skill body that says "read this other file and follow the instructions there" or "load your X capability and then load your Y capability" will lose ~90% of the intended behavior at each hop. Keep the concrete action in the skill that fires, not one hop away. ### Skills that work share a shape Skills measured with high adoption (commit 57%, push similar) all have: - A clear, concrete trigger (a specific moment, not a general topic) - Imperative steps, not descriptive phases - <80 lines in the main body - No chained `requires` that the agent must load additional skills to satisfy the described behavior **`conversations` is the workflow-skill success case** — 3% session load with a phase-graph-shaped body of four sources (KB, meetings, chat, email). It works because the trigger is concrete ("research a person/decision") and the body is a *decision tree*, not a phase graph. The agent enters at one of four entry points based on the question; it doesn't read top-to-bottom executing each phase. When writing a workflow skill that needs to cover multiple sources or paths, prefer decision-tree structure (here's the question, here's where to go) over phase structure (do this, then this, then this). ### Measure before refactoring a skill If a skill feels wrong, query the session DB at `~/.local/share/opencode/opencode.db` for actual loading and capability-use patterns before redesigning. Designing skill ontologies in the abstract reproduces the orchestrator failure.