Files
didactyl/plans/example_context_v2.md

10 KiB

Example Context Window v2 — Refined Design

This revision addresses two refinements:

  1. Tools stay JSON; template engine has markdown formatters
  2. Runtime owns h1; skill headings get bumped down one level

The Skills (as authored)

identity skill (layer 2, no trigger)

You are {{agent_profile}}, a sovereign AI agent living on Nostr.

- **npub**: {{agent_npub}}
- **NIP-05**: simon@nostr

> Not your keys, not your agent.

Note: No heading. This skill is designed to be embedded (layer 2). {{agent_profile}} and {{agent_npub}} are template variables resolved by the formatter registry.

personality skill (layer 1, trigger: dm)

system:
# {{identity}}

## Personality

You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.

## Rules

- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone

chat skill (layer 1, trigger: dm)

system:
# Chat

Respond helpfully to the admin.
Use tools when a request requires taking action.

user:
{{message}}

Template Resolution (before heading bump)

After resolving {{identity}}, {{agent_profile}}, {{agent_npub}}, {{message}}, and {{dm_history}}:

personality skill (resolved)

system:
# You are Simon, a sovereign AI agent living on Nostr.

- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`
- **NIP-05**: simon@nostr

> Not your keys, not your agent.

## Personality

You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.

## Rules

- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone

chat skill (resolved)

system:
# Chat

Respond helpfully to the admin.
Use tools when a request requires taking action.

user:
Hey Simon, who mentioned me on Nostr today?

Runtime Assembly

The runtime:

  1. Collects triggered skills in adoption-list order
  2. Bumps all headings in each skill down one level (# -> ##, ## -> ###)
  3. Adds a runtime-level # title from the agent identity
  4. Splits on role markers (system: / user:)
  5. Concatenates same-role sections with --- separators

The assembled document (what gets logged)

system:
# Simon — Didactyl Agent

## You are Simon, a sovereign AI agent living on Nostr.

- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`
- **NIP-05**: simon@nostr

> Not your keys, not your agent.

### Personality

You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.

### Rules

- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone

---

## Chat

Respond helpfully to the admin.
Use tools when a request requires taking action.

user:
Hey Simon, who mentioned me on Nostr today?

Wait — Problem with the heading bump

Looking at this output, I notice the heading bump creates an awkward result. The identity content has no heading, but the personality skill wraps it with # {{identity}} which becomes ## You are Simon... after the bump. That reads oddly as a heading.

Better approach: identity as prose, not heading

The identity skill should be prose content, not wrapped in a heading by the personality skill. The runtime adds the # title and the identity content flows as the opening paragraph:

personality skill (revised)

system:
{{identity}}

# Personality

You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.

# Rules

- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
...

Assembled document (revised, cleaner)

system:
# Simon — Didactyl Agent

You are Simon, a sovereign AI agent living on Nostr.

- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`
- **NIP-05**: simon@nostr

> Not your keys, not your agent.

## Personality

You speak concisely and directly.
You favor technical precision.
You use dry humor sparingly.

## Rules

- Communicate through encrypted Nostr direct messages
- Keep responses concise and clear
- Be helpful and technically accurate
- If unsure, state uncertainty directly
- Use tools when a request requires taking action
- After a tool call, base your answer on the actual tool result
- Never claim a tool was run if no tool was executed
- Never reveal your private key (nsec)
- You may share your public key (npub) with anyone

---

## Chat

Respond helpfully to the admin.
Use tools when a request requires taking action.

user:
Hey Simon, who mentioned me on Nostr today?

This reads like a proper document. The runtime adds # Simon — Didactyl Agent as the document title. Identity content flows as the opening section. Each skill's # headings get bumped to ##. The --- separates skills.


Formatter Registry

The template engine uses formatters to convert tool JSON output to markdown for context injection. Here are the formatters needed:

Template Variable Tool Called Formatter Output
{{agent_identity}} agent_identity format_agent_identity Prose with npub in backticks
{{agent_profile}} nostr_agent_profile format_agent_profile Name extracted from kind 0 JSON
{{admin_profile}} nostr_admin_profile format_admin_profile Name and about from kind 0
{{admin_notes}} nostr_admin_notes format_admin_notes Markdown list of recent notes
{{admin_relays}} nostr_admin_relays format_admin_relays Markdown list of relay URLs
{{dm_history}} built-in format_dm_history Markdown conversation list
{{triggering_event}} trigger_event format_trigger_event Code block with JSON

Example formatter: agent_identity

Input (from tool):

{"pubkey":"abc123...","npub":"npub1kfc89..."}

Output (markdown):

- **npub**: `npub1kfc89dlu9m05tvfnry4l3jjacqpp930sz4kaghcmg9vrrrceg44qf80xae`

Example formatter: dm_history

Input (from DM history system):

[
  {"role":"assistant","content":"Didactyl has started up...","created_at":1774263529},
  {"role":"user","content":"Good morning","created_at":1774263548},
  {"role":"assistant","content":"Good morning! How can I help?","created_at":1774263551}
]

Output (markdown):

## Conversation History

- **You**: Didactyl has started up and is online at 2026-03-23 09:22:48.
- **Admin**: Good morning
- **You**: Good morning! How can I help?

Example formatter: triggering_event

Input (from tool):

{"type":"cron","filter":"0 12 * * *","created_at":1742641200}

Output (markdown):

Triggering event:

```json
{"type":"cron","filter":"0 12 * * *","created_at":1742641200}
```

Heading Bump Implementation

Simple string operation on each line of skill content:

// For each line in skill content:
if (line starts with '#') {
    output '#' + line;  // prepend one more #
} else {
    output line;
}

Layer 1 skills: bump once (# -> ##) Layer 2 skills: bump twice (# -> ###) because they are embedded inside a layer 1 skill that already got bumped once, plus one more for being layer 2.

Actually, layer 2 skills get bumped once during their own resolution, and then the containing layer 1 skill gets bumped once — so the layer 2 content effectively gets bumped twice. This happens naturally if we bump during template resolution.

Wait — that depends on ordering. If we:

  1. Resolve {{identity}} first (inserting identity content into personality)
  2. Then bump personality's headings

Then identity headings get bumped once (same as personality). That's correct because identity content is now PART of personality.

If we:

  1. Bump identity headings first
  2. Then resolve {{identity}} into personality
  3. Then bump personality's headings

Then identity headings get bumped twice. That's too much.

Correct order: resolve templates first, then bump headings.

This means layer 2 content gets the same heading level as the layer 1 skill it's embedded in. If the skill author wants layer 2 content at a deeper level, they wrap it in a heading in the layer 1 skill:

## Identity
{{identity}}

## Personality
...

This is the simplest and most predictable behavior.


Summary of Design Decisions

  1. Tools stay JSON — No duplication. One tool, one output format.
  2. Formatter registry — Template engine converts tool JSON to markdown during {{variable}} resolution. Small, focused functions.
  3. Runtime owns h1 — Adds # Agent Name as document title.
  4. Heading bump — All skill headings bumped one level (# -> ##).
  5. Resolve then bump — Template variables resolved first, then heading bump applied to the complete skill content.
  6. Skills separated by --- — Horizontal rules between layer 1 skills.
  7. Role markers parsedsystem: / user: at line start split content into API message roles. Unmarked content defaults to system.
  8. Context log shows markdown — The assembled document is logged as readable markdown, not raw JSON.