carlos
a small library you grow

Skills, explained.

A skill is a piece of folded-up procedural knowledge: a recipe carlos can reach for when a task fits its description. You can write skills by hand. You can drop the ones the open agentskills.io standard already publishes into a folder. And here's the distinguishing part: carlos can watch a transcript, notice that a piece of work probably wants to be reusable, and propose a new skill for you to review before it ever lands on disk. Nothing auto-publishes. The human is always the gate.

01What a skill is.

A skill is a directory containing a SKILL.md file with YAML frontmatter and a markdown body. Frontmatter declares the metadata; the body is the prompt content the model loads when the skill is relevant. Optional scripts/ and reference/ subdirectories can ship alongside for deterministic code or supporting docs.

Frontmatter fields

Caps: body up to ~20,000 chars (≈5,000 tokens), 50 files per skill directory. Bigger than that, split it.

Example shapes

Three real skills from this codebase, switchable below: a bundled one carlos ships with, a hand-written one a user might add, and an induced proposal as it lands in the approval queue before promotion.

skills/calendar/apple-calendar.md
---
name: calendar-apple
description: Drive Calendar.app on macOS via osascript. Reads, creates, deletes events in the user's local Calendar database.
backend: apple
frame_default: personal
triggers: [calendar, apple, ical, schedule, event, meeting]
---

# calendar-apple

You drive Calendar.app on macOS through `osascript`. This skill only works on
darwin. If the host is Linux, stop and tell the user to switch backends.

Run every AppleScript snippet via the `bash` tool:

  tool: bash
  args:
    command: osascript -e '<applescript here>'
~/.agents/skills/release-bump/SKILL.md
---
name: release-bump
description: Use when the user asks to cut a new release of this project. Bumps the version in go.mod aux, regenerates the CHANGELOG via git-cliff, drafts release notes, and tags.
provenance: hand-written
---

# release-bump

Steps, in order. Each is a single tool call. Never bundle.

1. Read VERSION. Parse it. Confirm the bump kind (major/minor/patch)
   with the user before changing anything.
2. Run `git-cliff --unreleased` to draft the changelog delta. Show
   the user; let them edit before commit.
3. Update VERSION and CHANGELOG.md in a single commit titled
   `release: vX.Y.Z` (no emoji prefix; releases use plain prefixes).
4. Tag with `git tag -s vX.Y.Z` and push only when explicitly asked.

Never push to main without the user's explicit OK.
approval-queue · skill: gh-pr-from-branch · proposed
---
name: gh-pr-from-branch
description: Use when the user asks to open a PR for the current branch and the branch has unpushed commits. Pushes with -u, drafts a title and body from the diff, and opens via gh pr create.
provenance: induced
inducer_model: anthropic:claude-sonnet-4-7
induced_from: [agent-7f3e, agent-7f9c]
---

# gh-pr-from-branch

# Confidence: 0.82 from replay-eval against 14 historical transcripts
# Reuse predicted: 6 invocations / 30d

Verify the branch exists on origin (`git rev-parse --abbrev-ref --symbolic-full-name @{u}`);
if not, push with -u. Then run `gh pr create` with a title under 70
chars and a body built from the diff summary…

02Where they live.

Carlos looks for skills in four locations, in priority order. Later wins on name collision, so a project-local skill overrides a user-level one of the same name. Carlos respects both the Claude convention (.claude/skills) and the open agentskills.io standard (.agents/skills), so you don't have to choose.

  1. 1~/.claude/skills/user · Claude convention
  2. 2~/.agents/skills/user · open standard
  3. 3<projectRoot>/.claude/skills/project · Claude convention
  4. 4<projectRoot>/.agents/skills/project · open standard

Two layouts are supported: a single-skill directory with one SKILL.md plus optional scripts/ and reference/ subdirs; and a bundle directory with multiple .md files, one per skill, each carrying its own frontmatter. The shipped calendar bundle uses the second shape to namespace six related skills (calendar, calendar-apple, calendar-caldav, calendar-ics-file, calendar-mcp, calendar-cross-frame-view) without spawning six sibling directories.

03Authoring a new skill.

The smallest possible flow:

  1. Pick a name. Make a directory: ~/.agents/skills/your-skill-name/.
  2. Drop a SKILL.md in it with the frontmatter from §1.
  3. Write the body as if you were instructing a careful intern. Be concrete about steps, tool calls, and when to stop and ask.
  4. Restart your carlos session, or just open a new chat. Skills are scanned at session start.

That's it. No build step, no install command, no manifest registry. The description is what gets matched against intent, so phrase it as "Use when …". That wording is load-bearing. If the description is vague, carlos can't reach for it; if it's too narrow, it'll be invisible to adjacent tasks that should have triggered it.

Naming and shape rules of thumb

04How carlos proposes skills.

The distinguishing piece. Carlos watches transcripts and, when it spots a chunk of work that's likely reusable, generates a SKILL.md proposal in the same shape you'd hand-author, then routes it through the same approval queue your plans and diffs go through. Nothing publishes itself. The model proposes; the human disposes.

conversation finishes
A turn ends; the supervisor reads the transcript and the set of skill descriptions already in the library.
inducer.Induce()
Single LLM pass (mid-tier model, ≈$0.02). Prompt asks for either a SKILL.md draft or a null answer, and constrains the description to start with "Use when …". Output is structured.
replay-evaluator
Optional. Scores the proposal against historical transcripts: would-this-have-helped with-vs-without. Low-confidence candidates are auto-rejected before the queue, logged for telemetry.
approval queue
Surviving proposals land alongside plans, diffs, and other artifacts in the manage TUI's approval pane, titled skill: <name>. You accept, reject, or edit before accepting.
PromoteAccepted
On accept, the SKILL.md is written to .agents/skills/<name>/ (or your configured location). On reject, the proposal is discarded but the rejection is logged so the inducer can learn what shape you didn't want.

The architectural commitment is the human gate. Even with perfect replay scoring, carlos will not auto-publish a skill. The cost of a wrong skill is high (every future session loads it on relevance match), and the cost of pausing for a one-second approval is low. That asymmetry is why the queue exists.

05What's in scope, what isn't.

Honest about where the system is today, since this is a v0 area still moving.

working today

  • Hand-authored skills in all five search paths.
  • Bundled calendar skills shipped in the binary.
  • Induction pass with structured proposal output.
  • Optional replay-evaluator gating before the queue.
  • Approval queue + accept/reject workflow.
  • Curator: skills go active → stale → archived based on use-recency; never hard-deleted.

still ahead

  • Auto-triggered induction wired to the supervisor (today the caller invokes it explicitly).
  • Real description-embedder (today's retrieval is a deterministic stub for v0; a real embedder comes when the cost is worth it).
  • Skill versioning, dependencies, and sharing/marketplace. Local-only for now.
  • A first-class carlos skill new CLI scaffolder.

If you author a skill you think the world should have, the right place to share it today is the open agentskills.io ecosystem. Anything that follows that format works in carlos without modification, and anything you write for carlos works in the other clients that adopt the same standard. Skills are portable on purpose.

Implementation: internal/skills/skill.go (data model), internal/skills/library.go (loader), internal/skills/inducer.go (proposal), internal/skills/skillwire/wire.go (queue + promotion), internal/skills/curator.go (lifecycle). Open standard: agentskills.io.