593 lines
26 KiB
Markdown
593 lines
26 KiB
Markdown
# Skills
|
|
|
|
See also: [CONTEXT.md](CONTEXT.md) · [TOOLS.md](TOOLS.md)
|
|
|
|
## The Context Window Is Made of Skills
|
|
|
|
Every time an LLM runs, it receives a context window — the complete set of instructions and information it needs to reason and respond. In this system, **the context window is broken up into units called skills.**
|
|
|
|
```
|
|
╔══════════════════════════════════════════╗
|
|
║ CONTEXT WINDOW ║
|
|
║ ║
|
|
║ ┌────────────────────────────────────┐ ║
|
|
║ │ Skill 1: personality │ ║
|
|
║ │ │ ║
|
|
║ │ You speak concisely and directly. │ ║
|
|
║ │ You favor technical precision. │ ║
|
|
║ │ │ ║
|
|
║ │ tools: [my_name, my_npub] │ ║
|
|
║ └────────────────────────────────────┘ ║
|
|
║ ┌────────────────────────────────────┐ ║
|
|
║ │ Skill 2: chat │ ║
|
|
║ │ │ ║
|
|
║ │ Respond helpfully to the admin. │ ║
|
|
║ │ Use tools as needed. │ ║
|
|
║ │ │ ║
|
|
║ │ tools: [nostr_query, nostr_dm] │ ║
|
|
║ └────────────────────────────────────┘ ║
|
|
║ ║
|
|
╚══════════════════════════════════════════╝
|
|
```
|
|
|
|
Each skill is a block of instructions. The context window is a stack of these blocks. Different events produce different stacks — a DM conversation has one set of skills, a scheduled cron job has a completely different set.
|
|
|
|
A skill is a **set of instructions for an LLM** stored as a Nostr event. Skills teach an LLM how to accomplish tasks — the LLM reads the instructions, reasons about them, and uses tools to take action.
|
|
|
|
Think of it like a woodshop: a **skill** is knowing how to carve — technique, judgment, decision-making. A **tool** is the chisel. The skill never directly uses the chisel without the craftsperson (the LLM) in the loop.
|
|
|
|
Skills are portable, shareable, and discoverable as Nostr events. They are not specific to any single application — any app that can read Nostr events and call an LLM can use skills.
|
|
|
|
---
|
|
|
|
## What Is a Skill?
|
|
|
|
A skill has two orthogonal properties:
|
|
|
|
- **Triggers** — A skill may have trigger tags, or not. If it has triggers, a runtime can fire it automatically when matching events occur. Triggered skills appear in the context window when their trigger matches (layer 1).
|
|
- **References** — A skill may be referenced by other skills via`{{skill_d_tag}}` template variables, or not. If referenced, its content is included inside the referencing skill (layer 2).
|
|
|
|
These properties are independent. A skill can have triggers and be referenced. A skill can have triggers and never be referenced. A skill can have no triggers and only exist to be referenced. A skill can have neither (though that would be inert).
|
|
|
|
---
|
|
|
|
## Skill Events
|
|
|
|
| Kind | Purpose | Replaceable? |
|
|
| --------- | ------------------------ | ---------------------- |
|
|
| `31123` | Public skill definition | Yes, by d-tag |
|
|
| `31124` | Private skill definition | Yes, by d-tag |
|
|
| `10123` | Skill adoption list | Yes, single per pubkey |
|
|
|
|
---
|
|
|
|
## Skill Content
|
|
|
|
The `content` field of a skill event IS the template — markdown instructions that go directly into the context window. No JSON wrapper. The description lives in a tag, not in content.
|
|
|
|
```json
|
|
{
|
|
"kind": 31123,
|
|
"content": "## Spelling and Grammar Checker\n\nYou are a spelling and grammar checker.\n\n### Rules\n\n- Fix spelling errors\n- Fix grammar errors\n- Preserve original formatting\n- Return **ONLY** the corrected text, no explanations\n\nInput text:\n{{message}}",
|
|
"tags": [
|
|
["d", "spellcheck"],
|
|
["description", "Check spelling and grammar"],
|
|
["trigger", "dm"],
|
|
["filter", "{\"from\":\"admin\"}"],
|
|
["llm", "openai/gpt-4o-mini, cheap"],
|
|
["temperature", "0"]
|
|
]
|
|
}
|
|
```
|
|
|
|
- **`content`** — the template in markdown. May include `{{...}}` template variables. This is what goes into the context window.
|
|
- **Role ownership** — skill authors should write plain markdown instructions, not `system:` / `user:` / `assistant:` markers. The runtime owns role construction and appends trigger payloads (for DM triggers, raw message text) as the `user` message at execution time.
|
|
- **Heading Levels** — The runtime owns the `#` (h1) heading for the document title. All headings in skill content are automatically bumped down one level (`#` becomes `##`, `##` becomes `###`) during context assembly. Skill authors should use `##` for their top-level sections.
|
|
- **`["description", "..."]`** — human-readable description for discovery and UI display.
|
|
- Each `["tag", "value"]` is a separate tag on the Nostr event.
|
|
- The `llm` tag uses a CSS font-stack style fallback chain. See [LLM Fallback Chain](#llm-fallback-chain).
|
|
|
|
---
|
|
|
|
## Two-Layer Context Model
|
|
|
|
When a skill executes, the context window is built in two layers:
|
|
|
|
- **Layer 1:** Triggered skills whose trigger matches the current event, ordered by their position in the adoption list (`10123`). Only triggered skills can be in layer 1 — the trigger system is what puts them there.
|
|
- **Layer 2:** Skills embedded inside layer 1 skills via`{{skill_d_tag}}` template references. These are resolved inline, the same way tool-based template variables are resolved.
|
|
|
|
```
|
|
CONTEXT WINDOW — Admin DM arrives
|
|
═══════════════════════════════════════════════════
|
|
|
|
Layer 1: Triggered skills matching "dm/admin"
|
|
(ordered by adoption list)
|
|
|
|
┌─────────────────────────────────────────────────┐
|
|
│ TRIGGERED SKILL: personality │
|
|
│ trigger: dm, filter: {"from":"admin"} │
|
|
│ │
|
|
│ ┌───────────────────────────────────────┐ │
|
|
│ │ {{identity}} (adopted, no trigger) │ │
|
|
│ │ You are Didactyl. npub1abc...xyz │ │
|
|
│ └───────────────────────────────────────┘ │
|
|
│ │
|
|
│ You speak concisely and directly. │
|
|
│ You favor technical precision. │
|
|
│ You use dry humor sparingly. │
|
|
│ │
|
|
├─────────────────────────────────────────────────┤
|
|
│ TRIGGERED SKILL: chat │
|
|
│ trigger: dm, filter: {"from":"admin"} │
|
|
│ │
|
|
│ Respond helpfully. Use tools as needed. │
|
|
│ │
|
|
│ tools: [nostr_query, nostr_dm, nostr_post, │
|
|
│ memory_read, memory_write] │
|
|
│ │
|
|
├─────────────────────────────────────────────────┤
|
|
│ DM CONTENT (always last for dm triggers) │
|
|
│ │
|
|
│ "Hey, can you check who mentioned me today?" │
|
|
│ │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
```
|
|
CONTEXT WINDOW — Cron fires at noon
|
|
═══════════════════════════════════════════════════
|
|
|
|
Layer 1: Triggered skills matching "cron/0 12 * * *"
|
|
(ordered by adoption list)
|
|
|
|
┌─────────────────────────────────────────────────┐
|
|
│ TRIGGERED SKILL: readme-monitor │
|
|
│ trigger: cron, filter: 0 12 * * * │
|
|
│ │
|
|
│ ┌───────────────────────────────────────┐ │
|
|
│ │ {{identity}} (adopted, no trigger) │ │
|
|
│ │ You are Didactyl. npub1abc...xyz │ │
|
|
│ └───────────────────────────────────────┘ │
|
|
│ │
|
|
│ Check the readme at the configured URL. │
|
|
│ Compare with last known version in memory. │
|
|
│ If changed: post it and DM admin a summary. │
|
|
│ │
|
|
│ tools: [http_fetch, memory_read, │
|
|
│ memory_write, nostr_post, nostr_dm] │
|
|
│ │
|
|
├─────────────────────────────────────────────────┤
|
|
│ TRIGGERING EVENT │
|
|
│ │
|
|
│ {"type":"cron","filter":"0 12 * * *", │
|
|
│ "created_at":1742641200} │
|
|
│ │
|
|
└─────────────────────────────────────────────────┘
|
|
|
|
personality is NOT here — it has a dm trigger,
|
|
not a cron trigger, so it doesn't match layer 1.
|
|
|
|
identity IS here — but only as layer 2 inside
|
|
readme-monitor, because readme-monitor includes
|
|
{{identity}} in its template.
|
|
```
|
|
|
|
---
|
|
|
|
## Adoption List (`10123`)
|
|
|
|
The adoption list serves two purposes:
|
|
|
|
1. **Registry** — makes skills available for`{{skill_d_tag}}` resolution (layer 2 inclusion)
|
|
2. **Ordering** — determines the order of layer 1 triggered skills in the context window
|
|
|
|
```json
|
|
{
|
|
"kind": 10123,
|
|
"tags": [
|
|
["a", "31124:<pubkey>:identity"],
|
|
["a", "31124:<pubkey>:personality"],
|
|
["a", "31123:<pubkey>:chat"],
|
|
["a", "31123:<pubkey>:readme-monitor"]
|
|
]
|
|
}
|
|
```
|
|
|
|
- `identity` — no trigger, adopted so triggered skills can include it via`{{identity}}` (layer 2)
|
|
- `personality` — has`["trigger", "dm"]`, appears in layer 1 for DM events. Also referenceable via`{{personality}}` by other skills (layer 2).
|
|
- `chat` — has`["trigger", "dm"]`, appears in layer 1 for DM events after personality (adoption list order)
|
|
- `readme-monitor` — has`["trigger", "cron"]`, appears in layer 1 for cron events. Its template includes`{{identity}}` (layer 2).
|
|
|
|
Skills NOT in this list but with trigger tags are still armed — they fire when their trigger matches, but they execute in isolation (no layer 2 skill references available, only built-in variables).
|
|
|
|
---
|
|
|
|
## Template Variables
|
|
|
|
Template variables resolve through tool execution or skill lookup.
|
|
|
|
When the engine encounters `{{variable_name}}`:
|
|
|
|
1. Check if it matches a known tool — if so, execute the tool and insert the result
|
|
2. Check if it matches an adopted skill's d-tag — if so, insert that skill's content (layer 2)
|
|
3. If neither matches, resolve to empty (for portability)
|
|
|
|
### Built-in Variables
|
|
|
|
| Variable | Resolution | Description |
|
|
| ------------------------ | ---------------------------- | ---------------------- |
|
|
| `{{agent_identity}}` | `agent_identity` tool | Agent identity block |
|
|
| `{{admin_profile}}` | `nostr_admin_profile` tool | Admin kind 0 profile |
|
|
| `{{admin_notes}}` | `nostr_admin_notes` tool | Admin recent notes |
|
|
| `{{admin_relays}}` | `nostr_admin_relays` tool | Admin relay list |
|
|
| `{{dm_history}}` | *(expand directive)* | Recent DM conversation |
|
|
| `{{message}}` | *(built-in)* | Current user message |
|
|
| `{{triggering_event}}` | `trigger_event` tool | Triggering event JSON |
|
|
|
|
### Skill Reference Variables
|
|
|
|
| Variable | Resolution | Description |
|
|
| ------------------- | ------------------------------ | ----------------------- |
|
|
| `{{skill_d_tag}}` | Look up adopted skill by d-tag | Layer 2 skill inclusion |
|
|
|
|
Unknown variables resolve to empty values for portability.
|
|
|
|
---
|
|
|
|
## Triggers
|
|
|
|
A skill with trigger tags can be fired automatically by a runtime when matching events occur.
|
|
|
|
### Trigger Types
|
|
|
|
- `dm` — Direct message received
|
|
- `cron` — Scheduled time expression
|
|
- `nostr-subscription` — Nostr event matches a filter
|
|
- `webhook` — HTTP request received
|
|
- `chain` — Another skill completed execution
|
|
|
|
### Trigger Tags
|
|
|
|
| Tag | Required | Description |
|
|
| ----------- | -------- | --------------------------------- |
|
|
| `trigger` | Yes | Trigger type |
|
|
| `filter` | Yes | Type-specific filter |
|
|
|
|
If a skill is in the adoption list, its triggers are active. There is no separate `enabled` flag — adoption IS enablement.
|
|
|
|
### Execution Parameter Tags
|
|
|
|
These tags can appear at the top level of a skill event (defaults for any app) or on trigger-specific contexts (runtime overrides).
|
|
|
|
| Tag | Description |
|
|
| --------------- | -------------------------------------------------------------------------------------------------- |
|
|
| `llm` | Model spec with fallback chain (see below) |
|
|
| `max_tokens` | Max output tokens |
|
|
| `temperature` | Sampling temperature |
|
|
| `seed` | Optional deterministic seed |
|
|
|
|
### LLM Fallback Chain
|
|
|
|
The `llm` tag uses a CSS font-stack style fallback chain. The runtime tries each entry in order, falling back to the next if the previous is unavailable.
|
|
|
|
Format: `provider/model, provider/model, ..., capability_keyword`
|
|
|
|
```
|
|
["llm", "anthropic/claude-sonnet-4-20250514, openai/gpt-4o-mini, cheap"]
|
|
```
|
|
|
|
This means:
|
|
|
|
1. Try `anthropic/claude-sonnet-4-20250514` first
|
|
2. If unavailable, try `openai/gpt-4o-mini`
|
|
3. If unavailable, use whatever the runtime considers `cheap`
|
|
|
|
Each entry can be:
|
|
|
|
- **`provider/model`** — specific provider and model (e.g., `anthropic/claude-sonnet-4-20250514`)
|
|
- **`model`** — model name only, use the default provider (e.g., `gpt-4o-mini`)
|
|
- **Capability keyword** — abstract tier the runtime resolves to its best available option
|
|
|
|
Capability keywords:
|
|
|
|
| Keyword | Meaning |
|
|
|---------|---------|
|
|
| `cheap` | Lowest cost model available |
|
|
| `fast` | Lowest latency model available |
|
|
| `best` | Highest capability model available |
|
|
| `default` | Use the agent/app default model |
|
|
|
|
Examples:
|
|
|
|
```
|
|
["llm", "openai/gpt-4o-mini"] -- specific model, no fallback
|
|
["llm", "openai/gpt-4o-mini, cheap"] -- try gpt-4o-mini, fall back to cheapest
|
|
["llm", "anthropic/claude-opus-4-20250514, openai/gpt-4o, best"] -- try opus, then gpt-4o, then best available
|
|
["llm", "fast"] -- just use the fastest available
|
|
["llm", "default"] -- use agent/app default
|
|
```
|
|
|
|
This is important for portability: a skill published with `["llm", "anthropic/claude-sonnet-4-20250514, cheap"]` works on any runtime — if the runtime doesn't have Anthropic access, it falls back to its cheapest available model.
|
|
|
|
### Execution Parameter Resolution
|
|
|
|
When a trigger fires:
|
|
|
|
1. Start with agent/app defaults.
|
|
2. Apply top-level execution tags from the skill event.
|
|
3. Walk the `llm` fallback chain until a usable model is found.
|
|
4. Apply trigger-specific overrides if present.
|
|
5. Execute skill with those effective runtime settings.
|
|
6. Restore defaults after the run.
|
|
|
|
---
|
|
|
|
## Trigger Type Details
|
|
|
|
Each example below shows a complete skill event. Every `["tag", "value"]` pair is a separate tag on the Nostr event.
|
|
|
|
### `dm`
|
|
|
|
Fires when a direct message is received. `filter` is JSON with sender scope: `{"from":"admin"}`, `{"from":"wot"}`, or `{"from":"any"}`.
|
|
|
|
For DM triggers, the raw message content is always appended to the end of the context window.
|
|
|
|
```json
|
|
{
|
|
"kind": 31123,
|
|
"content": "{{identity}}\n\nRespond helpfully to the admin.",
|
|
"tags": [
|
|
["d", "chat"],
|
|
["description", "Chat with admin"],
|
|
["trigger", "dm"],
|
|
["filter", "{\"from\":\"admin\"}"],
|
|
["llm", "default"],
|
|
["requires_skill", "identity"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### `cron`
|
|
|
|
Fires on a schedule. `filter` is a standard 5-field cron expression: `minute hour day-of-month month day-of-week`.
|
|
|
|
```json
|
|
{
|
|
"kind": 31123,
|
|
"content": "{{identity}}\n\nCheck the readme at the configured URL. If changed, post it and DM admin.",
|
|
"tags": [
|
|
["d", "readme-monitor"],
|
|
["description", "Check readme for changes at noon"],
|
|
["trigger", "cron"],
|
|
["filter", "0 12 * * *"],
|
|
["llm", "openai/gpt-4o-mini, cheap"],
|
|
["max_tokens", "300"],
|
|
["requires_tool", "http_fetch"],
|
|
["requires_tool", "memory_read"],
|
|
["requires_tool", "memory_write"],
|
|
["requires_skill", "identity"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### `nostr-subscription`
|
|
|
|
Fires when a Nostr event matches a subscription filter. `filter` is a JSON-encoded Nostr subscription filter.
|
|
|
|
```json
|
|
{
|
|
"kind": 31123,
|
|
"content": "{{identity}}\n\nWhen the triggering event mentions Bitcoin or Lightning, summarize and DM admin.",
|
|
"tags": [
|
|
["d", "mention-monitor"],
|
|
["description", "Monitor mentions and summarize"],
|
|
["trigger", "nostr-subscription"],
|
|
["filter", "{\"#p\":[\"<admin_pubkey>\"],\"kinds\":[1]}"],
|
|
["llm", "openai/gpt-4o-mini, cheap"],
|
|
["temperature", "0"],
|
|
["requires_tool", "nostr_query"],
|
|
["requires_tool", "nostr_dm"],
|
|
["requires_skill", "identity"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### `webhook`
|
|
|
|
Fires when an HTTP request is received. `filter` can be `{}` (match all).
|
|
|
|
```json
|
|
{
|
|
"kind": 31123,
|
|
"content": "{{identity}}\n\nProcess the webhook payload and take appropriate action.",
|
|
"tags": [
|
|
["d", "webhook-handler"],
|
|
["description", "Process incoming webhook"],
|
|
["trigger", "webhook"],
|
|
["filter", "{}"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### `chain`
|
|
|
|
Fires when another skill completes execution. `filter` is the source skill's `d` tag.
|
|
|
|
```json
|
|
{
|
|
"kind": 31123,
|
|
"content": "{{identity}}\n\nReview the output from the previous skill and DM admin a summary.",
|
|
"tags": [
|
|
["d", "readme-reviewer"],
|
|
["description", "Review results from readme monitor"],
|
|
["trigger", "chain"],
|
|
["filter", "readme-monitor"],
|
|
["llm", "openai/gpt-4o-mini, cheap"],
|
|
["requires_skill", "identity"]
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Requirements Tags
|
|
|
|
Skills declare what they need to run. Apps use these tags to determine which skills are compatible with their available capabilities.
|
|
|
|
| Tag | Description |
|
|
| ------------------ | ---------------------------------------------------------------- |
|
|
| `requires_tool` | A tool that must be available for this skill to function |
|
|
| `requires_skill` | An adopted skill that must be present for `{{...}}` resolution |
|
|
| `optional_tool` | A tool that enhances the skill but is not required |
|
|
|
|
```json
|
|
["requires_tool", "http_fetch"],
|
|
["requires_tool", "memory_read"],
|
|
["requires_tool", "memory_write"],
|
|
["requires_tool", "nostr_post"],
|
|
["requires_skill", "identity"],
|
|
["optional_tool", "nostr_dm"]
|
|
```
|
|
|
|
### How Apps Use Requirements
|
|
|
|
```
|
|
App starts up
|
|
│
|
|
├─ Knows its available tools/capabilities
|
|
│
|
|
├─ Fetches user's adopted skills from 10123
|
|
│
|
|
├─ For each skill, checks requires_tool tags
|
|
│ ├─ All required tools available? → skill is usable
|
|
│ └─ Missing required tools? → skill is disabled
|
|
│
|
|
└─ Presents only usable skills to the user
|
|
```
|
|
|
|
Tool names in requirements tags are **capability names**, not implementation names. `http_fetch` is a capability — a C binary implements it with libcurl, a browser implements it with fetch(), a mobile app implements it with its HTTP library. The capability is the same; the implementation varies.
|
|
|
|
---
|
|
|
|
## Private Skill Encoding (`31124`)
|
|
|
|
Private skills use NIP-44 encryption on event `content`.
|
|
|
|
Rules for kind `31124`:
|
|
|
|
- Keep`d` tag exposed so the event stays addressable/replaceable.
|
|
- Move non-`d` metadata into plaintext payload before encryption.
|
|
- Encrypt full payload with NIP-44 and store ciphertext in event`content`.
|
|
- On receive: resolve by`d`, decrypt`content`, then read content + private tags.
|
|
|
|
### Private Skill Event (on relay)
|
|
|
|
```json
|
|
{
|
|
"kind": 31124,
|
|
"content": "<nip44-ciphertext>",
|
|
"tags": [
|
|
["d", "mention-monitor"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### Decrypted Private Payload (application-level JSON)
|
|
|
|
```json
|
|
{
|
|
"content": "{{identity}}\n\nWhen {{triggering_event}} includes Bitcoin or Lightning, summarize and DM admin.",
|
|
"private_tags": [
|
|
["description", "Monitor mentions and DM summaries"],
|
|
["scope", "private"],
|
|
["trigger", "nostr-subscription"],
|
|
["filter", "{\"#p\":[\"<admin_pubkey>\"],\"kinds\":[1]}"],
|
|
["llm", "openai/gpt-4o-mini, cheap"],
|
|
["temperature", "0"],
|
|
["requires_tool", "nostr_query"],
|
|
["requires_tool", "nostr_dm"],
|
|
["requires_skill", "identity"]
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Execution Flow
|
|
|
|
```
|
|
Trigger event occurs (DM, cron, subscription, webhook, chain)
|
|
│
|
|
├─ Walk adoption list (10123)
|
|
│ │
|
|
│ ├─ For each skill whose trigger matches this event:
|
|
│ │ ├─ Resolve template variables (tools + skill references)
|
|
│ │ └─ Add to context (layer 1)
|
|
│ │
|
|
│ └─ Skills whose trigger does NOT match: skip
|
|
│
|
|
├─ Append triggering event payload
|
|
│ └─ For DM triggers: always append raw message content
|
|
│
|
|
├─ Apply execution parameters (llm, temperature, max_tokens, tools)
|
|
│
|
|
└─ Send to LLM → multi-turn tool loop → response
|
|
```
|
|
|
|
---
|
|
|
|
## Limits and Safety
|
|
|
|
| Limit | Default | Description |
|
|
| ----------------------- | ------------- | ----------------------------- |
|
|
| Max concurrent triggers | 16 | Prevents resource exhaustion |
|
|
| Trigger cooldown | 60s per skill | Prevents rapid-fire execution |
|
|
| LLM action rate limit | 10/min | Prevents runaway LLM costs |
|
|
|
|
---
|
|
|
|
## Storage on Nostr
|
|
|
|
| Data | Storage |
|
|
| -------------------------------------- | ----------------------- |
|
|
| Skills | Kind 31123/31124 events |
|
|
| Adopted skills | Kind 10123 event |
|
|
| Trigger definitions + execution params | Tags on skill events |
|
|
| Requirements declarations | Tags on skill events |
|
|
|
|
---
|
|
|
|
## Portability
|
|
|
|
Skills are Nostr events. Any application that can read Nostr events and call a skill which will call an llm. Skills are not specific to Didactyl or any single runtime.
|
|
|
|
### Use Cases Beyond Didactyl
|
|
|
|
- **Word processor** — "Check spelling and grammar" button triggers a spellcheck skill
|
|
- **Browser extension** — Highlight text, run a summarization skill
|
|
- **Mobile app** — Voice input triggers a transcription skill
|
|
- **Browser-based agent** — Same agent, different runtime, different available tools
|
|
|
|
### Portability Guidelines
|
|
|
|
| Guideline | Rationale |
|
|
| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
| Use `{{message}}` for user input | Universal — every app has user input |
|
|
| Declare requirements via `requires_tool` / `requires_skill` tags | Lets apps filter to compatible skills |
|
|
| Put default execution params as top-level tags | Any app can read `llm`, `temperature`, etc. |
|
|
| Keep trigger tags as optional runtime hints | Apps without trigger systems ignore them |
|
|
| Resolve unknown variables to empty | Ensures graceful degradation |
|
|
| Prefer self-contained skills for maximum portability | Skills with `{{skill_d_tag}}` references need the adoption ecosystem |
|
|
| Treat tool names as capabilities, not implementations | `http_fetch` works in C, browser, mobile — same capability, different implementation |
|
|
|
|
A skill should still be useful even when some variables, tools, or referenced skills are unavailable.
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- Tool architecture and complete tool catalog:[TOOLS.md](TOOLS.md)
|
|
- Context assembly model:[CONTEXT.md](CONTEXT.md)
|
|
- Project overview/runtime behavior:[README.md](../README.md)
|
|
|