7.4 KiB
Didactyl — LLM Context
See also: SKILLS.md · TOOLS.md
What Is Context?
Every time Didactyl talks to an LLM, it sends a context — the complete package of information the model needs to reason and respond.
Context is not just a prompt string; it is the full request payload:
- Messages — system/user/assistant/tool history
- Tool schemas — JSON descriptions of callable tools
- Model parameters — model, temperature, max tokens, seed, etc.
The context window is composed of skills — blocks of markdown instructions stacked together. See SKILLS.md for the canonical skill specification.
OpenAI-Compatible Chat Format
Didactyl uses OpenAI-compatible chat completions.
{
"model": "claude-opus-4.6",
"messages": [
{"role": "system", "content": "..."},
{"role": "user", "content": "..."}
],
"tools": [
{
"type": "function",
"function": {
"name": "nostr_post",
"description": "Publish a Nostr event",
"parameters": {"type":"object"}
}
}
],
"temperature": 0.7,
"max_tokens": 512
}
Message Roles
| Role | Purpose |
|---|---|
system |
Instructions and injected context (from skills) |
user |
Input message or trigger payload |
assistant |
Model responses / tool call envelopes |
tool |
Tool execution results fed back to model |
Context Assembly — Two-Layer Model
Context is assembled using a two-layer model driven by triggers and the adoption list.
Layer 1: Triggered Skills
When a trigger event occurs (DM, cron, subscription, webhook, chain), Didactyl walks the 10123 adoption list and finds all skills whose trigger matches the current event. These skills form layer 1 of the context window, in adoption-list order.
Only triggered skills can be in layer 1 — the trigger system is what puts them there.
Layer 2: Referenced Skills
Within each layer 1 skill, {{skill_d_tag}} template variables resolve to adopted skills' content. These are embedded inline — the same way tool-based template variables are resolved.
Non-triggered skills (skills with no trigger tags) can only enter the context window via layer 2 references.
Assembly Steps
Trigger event occurs (DM, cron, subscription, webhook, chain)
│
├─ Walk adoption list (10123)
│ │
│ ├─ Skill has trigger matching this event?
│ │ ├─ YES → add to context (layer 1)
│ │ │ └─ Resolve {{...}} references (layer 2)
│ │ │ ├─ Known tool? → execute tool, convert JSON to markdown, insert
│ │ │ ├─ Adopted skill d-tag? → insert skill content
│ │ │ └─ Unknown? → resolve to empty
│ │ │
│ │ └─ NO → skip (not in this context)
│ │
│ └─ Continue to next skill in list
│
├─ Format Document
│ ├─ Add `# Agent Name` title
│ ├─ Bump all skill headings down one level (# -> ##)
│ └─ Concatenate skills with `---` separators
│
├─ Split Roles
│ └─ Parse `system:` and `user:` markers to build API messages array
│
├─ Attach tool schemas (filtered by skill requires_tool tags)
│
├─ Apply execution parameters (llm, temperature, max_tokens)
│ └─ Walk LLM fallback chain until usable model found
│
└─ Send to LLM
Visualization
The assembled context is a single, coherent markdown document before being split into API messages:
system:
# Didactyl Agent
- **npub**: `npub1...`
## Personality
You speak concisely and directly.
---
## Chat
Respond helpfully to the admin.
Use tools as needed.
user:
Who mentioned me today?
Why Order Matters
- Earlier skills in the adoption list appear first in the context window.
- Earlier instructions generally set broader tone/policy.
- Later instructions can narrow/specialize behavior.
- If instructions conflict, prompt-order effects apply.
Context Parts
| Part | Source | Description |
|---|---|---|
| Layer 1 skills | Triggered skills from adoption list | Skills whose trigger matches the current event, in adoption-list order |
| Layer 2 skills | {{skill_d_tag}} references |
Adopted skills embedded inside layer 1 skills |
| Resolved variables | Tool outputs | Runtime data inserted into templates via {{...}} |
| Triggering event | DM content / event payload | Current request — always appended after skills |
| Tool schemas | Tool registry, filtered by skill requires_tool tags |
Capability declaration for tool calling |
| Runtime params | Skill event tags + LLM fallback chain | Model, temperature, max_tokens, etc. |
Template Variable Resolution
When the engine encounters {{variable_name}} in a skill template:
- Check known tools — if it matches a tool name, execute the tool. The tool returns JSON, which the template engine automatically converts into readable markdown (bullet lists, bold keys) before inserting it into the document.
- Check adopted skills — if it matches an adopted skill's d-tag, insert that skill's content (layer 2)
- Neither — resolve to empty (for portability)
This means {{admin_profile}} calls the nostr_admin_profile tool and formats its JSON output as markdown, while {{identity}} inserts the adopted "identity" skill's content. The skill author doesn't need to know which is which — the resolution is transparent.
See SKILLS.md — Template Variables for the full variable table.
Execution Parameters
Execution parameters control the LLM call: which model, what temperature, how many tokens, which tools.
Resolution Order
- Start with agent defaults
- Apply top-level execution tags from the skill event
- Walk the
llmfallback chain until a usable model is found - Execute
- Restore defaults after the run
LLM Fallback Chain
The llm tag uses a CSS font-stack style fallback: provider/model, provider/model, ..., capability_keyword
["llm", "anthropic/claude-sonnet-4-20250514, openai/gpt-4o-mini, cheap"]
See SKILLS.md — LLM Fallback Chain for the full format and capability keywords.
Context Compaction
During long-running tool loops, the context window can grow as tool call/result pairs accumulate. When context approaches the model's token limit, compaction prevents overflow:
- Track approximate token usage of the messages array
- When approaching ~70% of the model's context window, inject a summarization request
- The LLM summarizes progress so far into a condensed form
- Replace detailed tool history with the summary
- Continue execution with the compacted context
This allows skills to run complex multi-step tasks without hitting context limits.
Token Budget
Context cost is controlled by:
- Number of triggered skills matching the event (layer 1 count)
- Size of referenced skills (layer 2 content)
- Tool call/result accumulation during execution
- Context compaction threshold (~70% of model window)
- Per-skill model/runtime parameter choices
Use runtime context inspection endpoints (GET /api/context/current, GET /api/context/parts) to see the exact payload before LLM calls.