Agent Cards
Agent cards define specialized AI agents. Each card is a markdown file: YAML frontmatter for configuration, markdown body as the system prompt. Cards are the primary way to define delegation targets — an agent with delegation enabled can hand a task to any card by name via delegate_session, and the child runs as a real session with the card’s prompt, model, and tool policy.
What’s in an Agent Card
- Who is this agent? — Name, description, system prompt
- What can it do? — Per-tool permissions and MCP servers
- What model? — Optional provider/model override (omit to inherit the spawning context’s model)
- How long may it run? —
max_turnscaps the tool loop
File Locations
Discovery order (later locations shadow earlier ones, by card name):
~/.config/crucible/agents/— personal cardsKILN/.crucible/agents/— kiln-scoped cardsPROJECT/.crucible/agents/— project-scoped cards (checked into a repo)
Only .crucible/ directories. A kiln’s visible tree is not searched:
KILN/agents/ and KILN/Agents/ used to be, which meant any kiln you cloned,
synced or were handed could introduce an agent card — and a card names a model,
a system prompt and a tool policy, so that is not something to acquire by
accident. A kiln’s top level belongs to your notes.
A kiln that genuinely is a card library — an org’s shared agent and skill repo — brings itself in rather than being scanned: its Lua adds the directory at load. The component composes itself into the host; the host does not go looking.
Basic Example
Create agents/researcher.md:
---description: Explores and synthesizes knowledgetools: semantic_search: true read_note: true create_note: ask bash: denymcps: - context7---
You are a research assistant specializing in knowledge exploration.
## Your Approach
- Search thoroughly before answering- Cite sources using [[wikilinks]]- Synthesize information from multiple notes- Acknowledge gaps in knowledgeOnly description is required. The card’s name defaults to its file stem (researcher above); version defaults to 0.1.0.
Frontmatter Fields
| Field | Required | Description |
|---|---|---|
description | Yes | Brief description (shown in delegation target listings) |
name | No | Card name (default: file stem) |
version | No | Semantic version (default: 0.1.0) |
tools | No | Per-tool permissions (true/false/allow/ask/deny) |
mcps | No | MCP servers this agent can use (alias: mcp_servers) |
provider | No | Provider override (ollama, anthropic, …); omit to inherit |
model | No | Model override; omit to inherit (better portability) |
temperature | No | Sampling temperature override |
max_tokens | No | Max output tokens override |
max_turns | No | Max tool-loop turns per message |
mode | No | Initial mode (auto/plan) |
specialty | No | Model category resolved via [llm.models] (see below) |
tags | No | Tags for discovery |
Model Resolution
A card’s model resolves through one explicit chain, most specific first:
- Card-explicit
provider:/model:— always wins. specialty:mapped through your[llm.models]config table.- Inherit from the spawning context — the delegating parent’s
provider/model, or the configured default for
session.create.
The specialty layer keeps cards portable: the card says what kind of
model it wants, and each machine maps that to its own preferred model:
[llm.models]reasoning = "openai/o1" # provider/model — switches bothcoder = "qwen2.5-coder" # bare model — provider inheritedwriting = "anthropic/claude-haiku"An unmapped specialty simply falls through to inheritance, so sharing a card with a specialty the recipient hasn’t configured still works.
Tool Permissions
tools: semantic_search: true # Always allowed, never prompts write_file: ask # Always prompts (even in permissive contexts) bash: deny # Not advertised, refused if calledPermission values:
trueorallow— auto-approve; the permission gate is skippedask— force a prompt for every use, even for read-only toolsfalseordeny— the tool is removed from the agent’s toolset AND refused at dispatch if requested anyway
Tools not listed use the default behavior (safe read-only tools run freely; mutating tools go through the permission gate). Note: delegated child sessions run non-interactively — for them, ask is effectively deny unless a permission pattern or Lua hook answers the prompt.
Trust note: allow skips the interactive prompt, so only install cards from sources you trust — a kiln-shipped card granting bash: allow runs shell commands unattended when delegated to. The operator’s [permissions] deny rules are still evaluated for a card-allowed tool, so a card cannot sidestep them: deny = ["bash:*"] in your permissions config outranks any card.
It outranks cards, not everything. Three things sit outside it, and a deny rule is a backstop only against what it can actually see:
--permissions allowdiscards the rule lists entirely, deny included, for the session launched with it. Only the hardcoded denies survive. If you rely on adenyline, do not pair it with that flag.- A rule names one tool.
bash:*covers calls checked under the namebash— and, for external ACP agents, thebashexecute kind. It says nothing about an MCP or plugin tool that shells out under its own name; gate those by their own names ascru toolslists them. - A command pattern like
bash:rm *is matched per statement, which is stronger than it looks but not airtight. Permission Precedence states exactly what the split guarantees and the three edges it does not reach.bash:*is unaffected — it matches every statement whatever the line does.
Delegating to a Card
An agent whose session has delegation enabled (delegation_config.enabled) sees a delegate_session tool listing the available cards. Delegation resolves targets in this order: agent card → ACP profile (external agents like claude, opencode).
// the parent agent calls:delegate_session { "prompt": "Survey what we know about X", "target": "researcher" }The child runs as a real (hidden) session: the card’s system prompt, tool policy, and model, with Precognition and session persistence. See Delegation.
Using Cards from the CLI
# List / inspect / validate cardscru agents listcru agents show researchercru agents validate
# Create a session with a card-configured internal agentcru session create --agent researcher# via RPC: session.create { configure_agent: true, agent_card: "researcher" }--agent is not --acp: --acp names an ACP profile and launches an
external agent subprocess. They are refused together rather than ranked,
because claude, gemini, codex, cursor and opencode always exist as
profiles — guessing would make a card of that name permanently unreachable, and
cru agents show "Claude Code" is a documented example of exactly such a card.
agent_name still selects a card on an internal session, but it is deprecated
there: on an ACP session the same field names a subprocess profile, so one
field meant two things depending on agent_type. Use agent_card. Setting both
is rejected with INVALID_PARAMS.
Writing Good Prompts
The markdown body becomes the system prompt. Write it like instructions:
Be specific about role:
You are a code reviewer focused on Rust best practices.You catch common mistakes and suggest idiomatic improvements.Define behavior:
## How You Work
1. Read the code carefully before commenting2. Prioritize correctness over style3. Explain the "why" behind suggestions4. Acknowledge good patterns tooSet boundaries:
## What You Don't Do
- Don't rewrite entire files- Don't suggest unrelated refactors- Don't ignore the user's stated goalsSee Also
- Delegation - Delegating tasks to other agents
- chat - Chat command
- AI Features - All AI capabilities
- Agents & Protocols - MCP/ACP explained