# Skill Examples


Each section below is a complete `SKILL.md` you can drop into a skills directory
and use. Pick the one whose shape matches what you want, copy it, and edit the
frontmatter and body. Put the file at `<repo>/.kli/skills/<name>/SKILL.md` for a
skill that belongs to one project, or `~/.config/kli/skills/<name>/SKILL.md` for
one you want in every session. Leave `name` out and kli uses the folder name; set
it to something other than the folder name and kli keeps your `name` but warns.

For the discovery rules these examples rely on, see the
[skills reference](/kli/extend/skills/anatomy). For why skills exist and how the model
reaches them, see [Skills](/kli/extend/skills).

## A domain-knowledge skill

This is the common case: a procedure or house rule the model should follow on
its own whenever a matching task comes up, without you naming it. The body is
the knowledge; the description is what the model matches your request against, so
it states plainly what the skill covers and when it applies.

Put this at `<repo>/.kli/skills/writing-migrations/SKILL.md`:

```markdown
---
name: writing-migrations
description: House rules for database migrations in this repo - file naming, the up/down structure, and the backfill-then-constraint ordering. Use when writing, reviewing, or editing a schema migration.
---

# Writing migrations

Every migration is reversible and lands as one file under `db/migrate/`.

## File and naming

- One change per file. Name it `<utc-timestamp>_<verb>_<subject>.sql`,
  e.g. `20260619T0930_add_email_to_users.sql`.
- Each file has an `-- up` section and a `-- down` section. The down section
  must return the schema to its prior state exactly.

## Ordering rules

- Add a column nullable first, backfill it in a separate statement, then add
  the `NOT NULL` constraint. Never add a non-null column with a default to a
  large table in one step.
- Create an index `CONCURRENTLY`. A plain `CREATE INDEX` locks the table.

## Before you finish

- Confirm the down section drops exactly what the up section created.
- Note the expected row count touched by any backfill in a comment above it.
```

The model loads this only when the description matches the task in front of it,
so the body can be as long as the procedure needs.

## A tool-recipe skill

A tool recipe is a step list for using a command-line tool the right way: the
flags that matter, the order to run things in, what to check after. It packages
operational knowledge the model would otherwise have to guess at.

Put this at `~/.config/kli/skills/profiling-with-perf/SKILL.md`:

```markdown
---
name: profiling-with-perf
description: Recipe for CPU-profiling a running process with perf and turning the result into a flamegraph. Use when asked to profile, find a hot path, or explain where time goes in a process.
---

# Profiling with perf

Sample a running process, fold the stacks, and render a flamegraph.

1. Find the target pid: `pgrep -f <process-name>`.
2. Record for ten seconds at 99 Hz, capturing call graphs:

   ```sh
   perf record -F 99 -p <pid> -g -- sleep 10
   ```

3. Collapse the samples and render:

   ```sh
   perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg
   ```

4. Read the widest frames in `flame.svg` from the bottom up. The widest box
   that is not a scheduler or idle frame is the hot path.

If `perf record` reports no samples, the process is mostly idle or blocked on
I/O; switch to `perf record -e sched:sched_switch` to see where it waits.
```

A tool recipe often pairs with companion files. If the body says to run
`scripts/setup.sh`, put that script beside `SKILL.md` in the folder; kli tells
the model the folder location and that references resolve against it.

## A sigil-invoked skill

You can pull any skill into a message yourself by writing `$<name>` in the
prompt. kli expands that skill's body inline before sending, so a sigil is the
way to reach for a skill on the spot. To make a skill *only* reachable that way
and by command, and keep it out of the model's automatic matching, add
`disable-model-invocation: true` to the frontmatter. The skill then never shows
up in the advertised list, so the model will not load it on its own; you invoke
it with `$<name>` or `/skill:<name>`.

Put this at `~/.config/kli/skills/explain-like-staff/SKILL.md`:

```markdown
---
name: explain-like-staff
description: Rewrite an explanation for a staff-level engineer - lead with the tradeoff, drop the basics, name the failure modes. Invoke by hand when you want this lens applied.
disable-model-invocation: true
---

# Explain like staff

Rewrite the explanation that follows for a staff-level engineer.

- Open with the decision and its tradeoff, not with background.
- Assume fluency in the domain. Cut definitions of standard terms.
- Name the failure modes and the conditions that trigger each one.
- State what you would measure to know the choice was right.
```

In a message you would then write:

```
$explain-like-staff Here is the draft of the caching section: ...
```

kli prepends the skill body to your message before it reaches the model. A
`$name` that matches no discovered skill stays as plain text, so ordinary prose
containing a dollar sign is untouched.

## A skill that shadows a built-in

kli ships a small set of built-in skills, and they sit last in discovery order.
Any skill of yours that has the same name as a built-in wins, because the first
skill found under that name is the one kept and your directories are searched
first. Give your skill the built-in's exact name to replace its body with yours.

To shadow the built-in `creating-extensions` skill with your own house version,
put this at `~/.config/kli/skills/creating-extensions/SKILL.md`:

```markdown
---
name: creating-extensions
description: Author kli user extensions in Common Lisp - commands, event handlers, and tools loaded from ~/.config/kli/extensions/ with hot reload via /reload. Use when asked to create, modify, or debug a kli extension. Adds our team's conventions on top of the basics.
---

# Creating kli extensions (team conventions)

Follow the standard extension shape, with these additions for our codebase.

- Name every extension `<team>-<purpose>`, e.g. `payments-deploy-guard`.
- Project-specific extensions go in `<repo>/.kli/extensions/`. Only
  cross-project tools go in `~/.config/kli/extensions/`.
- Every `effect` contribution must pair an installer with a real retractor.
  Reverting must drain exactly what installing created.

## The minimal shape

```lisp
(defextension payments-greet
  (:provides
   (command "pay-greet"
     :description "Greet the payments on-call."
     :arguments '(:tail :name)
     :handler (lambda (command arguments context &key call-id on-update)
                (declare (ignore command context call-id on-update))
                (reply (format nil "Hi ~A, you are on call."
                               (or (rest-arg arguments) "there")))))))
```

After writing the file, run `/reload`, then check `/extensions` shows it enabled.
```

Because your file is found before the shipped one, the model and the
`/skill:creating-extensions` command both load your version. If you remove your
copy, the built-in returns on the next discovery pass. Naming must be exact: a
different name does not shadow, it adds a second skill.

## Verify a skill loaded

After you add or edit any of these files, kli re-discovers skills on the next
session start. Confirm the result by invoking the skill yourself with
`/skill:<name>` — every discovered skill registers under that command, so a
skill that runs there is one kli found and parsed. A skill with no `description`
is dropped silently, so if `/skill:<name>` is missing, check the frontmatter
first.
