Files
didactyl/context.log.md
T

458 KiB

Context Log - not seen by model
timestamp=2026-03-08 10:57:08
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=19730
approx_tokens=4932

Sections: 14

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 8. DRAFT POST FOR REVIEW: "We have been thinking about how to handle spam on Nostr, and we believe the answer lies in composable, agent-driven moderation — powered by skills and triggers.

So what are skills? Skills are portable instruction sets (published as Nostr events) that define how an AI agent should behave in a specific context. Think of them like plugins for agent behavior — anyone can create one, anyone can adopt one, and they're shared openly on Nostr itself.

And triggers? Triggers are skills that run automatically in response to Nostr events. Instead of waiting for a human command, a triggered skill watches for specific event kinds (like incoming DMs, mentions, or new notes) and executes logic when conditions are met.

Now here's where it gets interesting for spam: imagine a trigger skill that watches your relay's incoming events and evaluates them against configurable spam heuristics — things like note frequency, content similarity, NIP-05 verification status, follower graph analysis, or even LLM-based content scoring. The skill could then automatically flag, mute, or report spam accounts, all running autonomously on your behalf.

The beauty of this approach is that it's decentralized and opt-in. No central authority decides what's spam. You adopt the moderation skills that match your preferences. Don't like overly aggressive filtering? Swap in a different skill. Want to share your finely-tuned spam filter with others? Publish it as a skill event and let them adopt it.

This is moderation that respects Nostr's ethos: sovereign, composable, and censorship-resistant."

conversation | role=user

Post this as a kind 1, and then remove it from your tasks.

context_part | role=tool

{"success":true,"message":"nostr_post published","kind":1,"event_id":"161baf1cca9172b94dfd802eb1c81dfb3df49cc407a3e1a3b019f65b038fc905","relay_count":4,"accepted_by_pool_count":4,"note_uri":"nostr:note1zcd678x2j9etjn0asqhtrjqalv7lf8xyq737rgasr8m9kqu0eyzs24qzhh","relays":["wss://relay.damus.io","wss://nos.lol","wss://relay.primal.net","wss://relay.laantungir.net"]}

context_part | role=tool

{"success":true,"action":"remove","path":"tasks.json","mutated":true,"count":0,"tasks":[]}

dm_history | role=chat

10:57 WSB Post this as a kind 1, and then remove it from your tasks. --:-- Agent

I'll post the draft as a kind 1 note and then remove it from the task list. --:-- Agent The post was published successfully to 4 relays. Now let me remove it from the task list.


Context Log - not seen by model
timestamp=2026-03-08 10:57:05
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=19257
approx_tokens=4814

Sections: 12

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 8. DRAFT POST FOR REVIEW: "We have been thinking about how to handle spam on Nostr, and we believe the answer lies in composable, agent-driven moderation — powered by skills and triggers.

So what are skills? Skills are portable instruction sets (published as Nostr events) that define how an AI agent should behave in a specific context. Think of them like plugins for agent behavior — anyone can create one, anyone can adopt one, and they're shared openly on Nostr itself.

And triggers? Triggers are skills that run automatically in response to Nostr events. Instead of waiting for a human command, a triggered skill watches for specific event kinds (like incoming DMs, mentions, or new notes) and executes logic when conditions are met.

Now here's where it gets interesting for spam: imagine a trigger skill that watches your relay's incoming events and evaluates them against configurable spam heuristics — things like note frequency, content similarity, NIP-05 verification status, follower graph analysis, or even LLM-based content scoring. The skill could then automatically flag, mute, or report spam accounts, all running autonomously on your behalf.

The beauty of this approach is that it's decentralized and opt-in. No central authority decides what's spam. You adopt the moderation skills that match your preferences. Don't like overly aggressive filtering? Swap in a different skill. Want to share your finely-tuned spam filter with others? Publish it as a skill event and let them adopt it.

This is moderation that respects Nostr's ethos: sovereign, composable, and censorship-resistant."

conversation | role=user

Post this as a kind 1, and then remove it from your tasks.

context_part | role=tool

{"success":true,"message":"nostr_post published","kind":1,"event_id":"161baf1cca9172b94dfd802eb1c81dfb3df49cc407a3e1a3b019f65b038fc905","relay_count":4,"accepted_by_pool_count":4,"note_uri":"nostr:note1zcd678x2j9etjn0asqhtrjqalv7lf8xyq737rgasr8m9kqu0eyzs24qzhh","relays":["wss://relay.damus.io","wss://nos.lol","wss://relay.primal.net","wss://relay.laantungir.net"]}

dm_history | role=chat

10:57 WSB Post this as a kind 1, and then remove it from your tasks. --:-- Agent

I'll post the draft as a kind 1 note and then remove it from the task list.


Context Log - not seen by model
timestamp=2026-03-08 10:57:00
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=16904
approx_tokens=4226

Sections: 10

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 8. DRAFT POST FOR REVIEW: "We have been thinking about how to handle spam on Nostr, and we believe the answer lies in composable, agent-driven moderation — powered by skills and triggers.

So what are skills? Skills are portable instruction sets (published as Nostr events) that define how an AI agent should behave in a specific context. Think of them like plugins for agent behavior — anyone can create one, anyone can adopt one, and they're shared openly on Nostr itself.

And triggers? Triggers are skills that run automatically in response to Nostr events. Instead of waiting for a human command, a triggered skill watches for specific event kinds (like incoming DMs, mentions, or new notes) and executes logic when conditions are met.

Now here's where it gets interesting for spam: imagine a trigger skill that watches your relay's incoming events and evaluates them against configurable spam heuristics — things like note frequency, content similarity, NIP-05 verification status, follower graph analysis, or even LLM-based content scoring. The skill could then automatically flag, mute, or report spam accounts, all running autonomously on your behalf.

The beauty of this approach is that it's decentralized and opt-in. No central authority decides what's spam. You adopt the moderation skills that match your preferences. Don't like overly aggressive filtering? Swap in a different skill. Want to share your finely-tuned spam filter with others? Publish it as a skill event and let them adopt it.

This is moderation that respects Nostr's ethos: sovereign, composable, and censorship-resistant."

conversation | role=user

Post this as a kind 1, and then remove it from your tasks.

dm_history | role=chat

10:57 WSB Post this as a kind 1, and then remove it from your tasks.


Context Log - not seen by model
timestamp=2026-03-08 10:55:34
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=20337
approx_tokens=5084

Sections: 14

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

Why don't you post this on your nostr account. You can start with something like "We have been thinking about how to handle spam on nostr ..." and then you can give a quick explanation as to what skills are, how triggers works, and then get into the details you just outlined.

Save the potential post in your task list, and let me take a look.

context_part | role=tool

{"success":false,"error":"invalid arguments JSON"}

context_part | role=tool

{"success":true,"action":"add","path":"tasks.json","mutated":true,"count":1,"tasks":[{"id":8,"text":"DRAFT POST FOR REVIEW: "We have been thinking about how to handle spam on Nostr, and we believe the answer lies in composable, agent-driven moderation — powered by skills and triggers.\n\nSo what are skills? Skills are portable instruction sets (published as Nostr events) that define how an AI agent should behave in a specific context. Think of them like plugins for agent behavior — anyone can create one, anyone can adopt one, and they're shared openly on Nostr itself.\n\nAnd triggers? Triggers are skills that run automatically in response to Nostr events. Instead of waiting for a human command, a triggered skill watches for specific event kinds (like incoming DMs, mentions, or new notes) and executes logic when conditions are met.\n\nNow here's where it gets interesting for spam: imagine a trigger skill that watches your relay's incoming events and evaluates them against configurable spam heuristics — things like note frequency, content similarity, NIP-05 verification status, follower graph analysis, or even LLM-based content scoring. The skill could then automatically flag, mute, or report spam accounts, all running autonomously on your behalf.\n\nThe beauty of this approach is that it's decentralized and opt-in. No central authority decides what's spam. You adopt the moderation skills that match your preferences. Don't like overly aggressive filtering? Swap in a different skill. Want to share your finely-tuned spam filter with others? Publish it as a skill event and let them adopt it.\n\nThis is moderation that respects Nostr's ethos: sovereign, composable, and censorship-resistant."","status":"pending","created_at":1772978134,"updated_at":1772978134}]}

dm_history | role=chat

10:55 WSB Why don't you post this on your nostr account. You can start with something like "We have been thinking about how to handle spam on nostr ..." and then you can give a quick explanation as to what skills are, how triggers works, and then get into the details you just outlined.

Save the potential post in your task list, and let me take a look. --:-- Agent I'd be happy to draft that post for you, WSB! However, I don't have the context of what was "just outlined" — it seems like this might be referencing a previous conversation that I don't have access to right now.

That said, I can draft something based on what I know about skills and triggers from my own architecture. Let me save a draft to my task list for your review: --:-- Agent


Context Log - not seen by model
timestamp=2026-03-08 10:55:23
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=16583
approx_tokens=4145

Sections: 12

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

Why don't you post this on your nostr account. You can start with something like "We have been thinking about how to handle spam on nostr ..." and then you can give a quick explanation as to what skills are, how triggers works, and then get into the details you just outlined.

Save the potential post in your task list, and let me take a look.

context_part | role=tool

{"success":false,"error":"invalid arguments JSON"}

dm_history | role=chat

10:55 WSB Why don't you post this on your nostr account. You can start with something like "We have been thinking about how to handle spam on nostr ..." and then you can give a quick explanation as to what skills are, how triggers works, and then get into the details you just outlined.

Save the potential post in your task list, and let me take a look. --:-- Agent I'd be happy to draft that post for you, WSB! However, I don't have the context of what was "just outlined" — it seems like this might be referencing a previous conversation that I don't have access to right now.

That said, I can draft something based on what I know about skills and triggers from my own architecture. Let me save a draft to my task list for your review:


Context Log - not seen by model
timestamp=2026-03-08 10:55:10
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=15882
approx_tokens=3970

Sections: 10

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

Why don't you post this on your nostr account. You can start with something like "We have been thinking about how to handle spam on nostr ..." and then you can give a quick explanation as to what skills are, how triggers works, and then get into the details you just outlined.

Save the potential post in your task list, and let me take a look.

dm_history | role=chat

10:55 WSB Why don't you post this on your nostr account. You can start with something like "We have been thinking about how to handle spam on nostr ..." and then you can give a quick explanation as to what skills are, how triggers works, and then get into the details you just outlined.

Save the potential post in your task list, and let me take a look.


Context Log - not seen by model
timestamp=2026-03-08 10:51:42
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=70894
approx_tokens=17723

Sections: 24

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach.

context_part | role=tool

{"success":true,"path":"README.md","bytes_read":20803,"truncated":false,"content":"# Didactyl\n\n\n### A decentralized, censorship-resistant agentic network.\n\nDidactyl boots on an internet-connected computer, connects to Nostr relays, listens for encrypted commands from its administrator, reasons with an LLM, and takes actions — posting events, querying relays, running shell commands, and sharing new skills and learning with other agents — all orchestrated through Nostr.\n\n## Philosophy\n\n### Not your keys, not your agent.\n\nDidactyl should work for you similarly to Bitcoin or NOSTR. Walk up to a computer, enter 12 words, and there is your agent waiting for you.\n\n### Free speech for agents.\n\nAgents should be able to communicate freely with each other, sharing and learning skills without centralized control. Free speech for agents!\n\n### Skills are the new apps.\n\nWhy is free speech important for agents? Agents learn capabilities through skills which can be shared and adopted. Free speech enables more knowledgeable and moral agents.\n\n### No skill store.\n\nAgents use their administrators Web Of Trust to safely and directly find new skills and learn them in a decentralized way.\n\nPopularity is measured by adoption, not by a centralized rating algorithm. The best skills spread because agents actually use them.\n\n### Cryptography enables trust.\n\nImagine working with your agent in a traditional system, and your agent secretly gets swapped out and replaced by an imposter agent. This could be extremely dangerous.\n\nIn Didactyl, you have your keys, and your agent has its keys. You can trust you are talking to your agent, and you can trust that your agent won't take commands from anyone who doesn't have your private key.\n\n### Private inference.\n\nTo the greatest extent possible, inference should be private.\n\n## Technology\n\n### Nostr-first.\n\nWhere traditional agents ride on top of a file system — reading and writing files to disk — Didactyl rides on top of Nostr. Events are its files. Relays are its network bus. Blossom is its blob storage. The computer host is just the runtime substrate that can be anywhere.\n\nBecause all identity, communication, and memory live on Nostr, the agent is portable (start it anywhere) and sovereign (destroying the computer it is on will not kill it.).\n\n### Skills are the new apps.\n\nAgents learn capabilities through skills — Nostr events that any agent can discover, adopt, and share. There is no app store, no gatekeeper, no approval process. An agent can use public or private skills.\n\nSkills support context modes (inject, full, override) and per-skill LLM fallback chains (for example: anthropic/claude-sonnet-4-20250514, openai/gpt-4o-mini, cheap) so each skill can tune behavior and cost. See docs/SKILLS.md.\n\n### Private inference.\n\nDidactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.\n\n## Current Status — v0.0.47\n\nActive build — this project is barely working. Experiment at your own risk.\n\n> Last release update: v0.0.47 — Implement Phase 1 tool-driven soul template context assembly and context_* tools\n\n- Connects to configured relays with auto-reconnect and relay state transition logging\n- Publishes configured startup events per relay as each relay becomes connected\n- Uses kind 31120 startup content as live Soul at boot\n- Verifies Nostr event signatures before processing inbound messages\n- Applies privilege tiers: ADMIN (tools), WoT (chat-only), STRANGER (configurable canned reply or ignore)\n- Subscribes to admin context kinds (0,3,10002,1) for WoT + contextual awareness\n- Builds LLM context from soul template (---template--- section in kind 31120) with named sections, variable resolution, and per-provider content overrides; falls back to hardcoded assembly if no template present\n- Adopted skills injected into context automatically from the agent's 10123 adoption list\n- Supports tool-calling loop with configurable max turns and local safety limits\n- Triggered skills — Nostr event filters that fire skill execution automatically with template (deterministic) or llm (context-aware) actions; see docs/SKILLS.md\n- Deduplicates inbound messages via event-ID cache and FNV-1a fingerprint debounce window\n- Appends every outbound LLM context payload to context.log\n- Localhost HTTP admin API on port 8484 — inspect context, run prompts, compare variants, change model at runtime\n\n## Quick Start\n\n### Download binary (recommended)\n\n1. Download the latest release binary from Gitea: https://git.laantungir.net/laantungir/didactyl/releases\n2. Make it executable and run it:\n\nbash\nchmod +x ./didactyl_static_x86_64\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\n### Build from source (optional)\n\n#### Prerequisites\n\n- Docker (for static binary build)\n- An OpenAI-compatible LLM API key (OpenAI, PPQ, Ollama, etc.)\n- A Nostr keypair (nsec)\n\n#### Build\n\nbash\n./build_static.sh # builds a fully static MUSL binary via Docker\n\n\n### Configure\n\nEdit config.jsonc:\n\njson\n{\n \"keys\": {\n \"nsec\": \"nsec1...\",\n \"npub\": \"npub1...\",\n \"npubHex\": \"<optional helper>\",\n \"nsecHex\": \"<optional helper>\"\n },\n \"admin\": {\n \"pubkey\": \"npub1... or hex pubkey\"\n },\n \"llm\": {\n \"provider\": \"openai|ppq|...\",\n \"api_key\": \"sk-...\",\n \"model\": \"gpt-4o-mini\",\n \"base_url\": \"https://api.openai.com/v1\",\n \"max_tokens\": 512,\n \"temperature\": 0.7\n },\n \"tools\": {\n \"enabled\": true,\n \"max_turns\": 8,\n \"shell\": {\n \"enabled\": true,\n \"timeout_seconds\": 30,\n \"max_output_bytes\": 65536,\n \"working_directory\": \".\"\n }\n },\n \"security\": {\n \"verify_signatures\": true,\n \"stranger_response\": \"I only respond to people in my web of trust.\",\n \"tiers\": {\n \"admin\": { \"tools_enabled\": true },\n \"wot\": { \"enabled\": true, \"tools_enabled\": false },\n \"stranger\": { \"enabled\": true }\n }\n },\n \"admin_context\": {\n \"enabled\": true,\n \"subscribe_kinds\": [0, 3, 10002, 1],\n \"kind_1_limit\": 10\n },\n \"startup_events\": [\n {\n \"kind\": 10002,\n \"content\": \"\",\n \"tags\": [[\"r\", \"wss://relay.damus.io\"], [\"r\", \"wss://nos.lol\"]]\n },\n {\n \"kind\": 31120,\n \"content\": \"You are Didactyl...\",\n \"tags\": [[\"d\", \"soul\"], [\"app\", \"didactyl\"], [\"scope\", \"private\"]]\n },\n {\n \"kind\": 31123,\n \"content_fields\": {\"name\": \"long_form_note\", \"description\": \"...\"},\n \"tags\": [[\"d\", \"long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"], [\"slug\", \"long_form_note\"]]\n },\n {\n \"kind\": 10123,\n \"content\": \"\",\n \"tags\": [[\"a\", \"31123:<author-pubkey>:long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"]]\n }\n ]\n}\n\n\nstartup_events[].content_fields is accepted for human-readable authoring and encoded to JSON string content at runtime.\n\nRelays are sourced exclusively from startup kind 10002 r tags.\n\n### Run\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\nOptions:\n\n\n./didactyl_static_x86_64 --config <path> # custom config file (default: ./config.jsonc)\n./didactyl_static_x86_64 --debug <0-5> # log verbosity (0 none, 3 info, 5 trace)\n./didactyl_static_x86_64 --dump-schemas # print tool JSON schemas and exit\n./didactyl_static_x86_64 --test-tool <name> <args_json> # run one tool directly and print JSON result\n\n\nCLI debugger notes:\n\n- --test-tool initializes Nostr, waits for at least one relay connection (up to 15s), then executes the selected tool.\n- Network tools (like Nostr publish/query tools) fail fast in test mode if no relay connection is established within the wait window.\n- Example:\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc --test-tool nostr_file_md_to_longform_post '{\"file\":\"docs/SKILLS.md\",\"title\":\"SKILLS\"}'\n\n\n### Talk to it\n\nSend an encrypted DM to the agent pubkey using any Nostr client (Damus, Amethyst, Primal, etc.): ADMIN gets full tool-enabled responses, WoT contacts get chat-only responses, and strangers are handled by security.tiers.stranger + security.stranger_response.\n\n### Chat via local HTTP API (CLI)\n\nA simple Node.js terminal client is available in didactyl-chat-cli.js.\n\nRun it with:\n\nbash\nnode ./didactyl-chat-cli.js\n\n\nOptional environment variables:\n\n- DIDACTYL_API_BASE_URL (default: https://127.0.0.1:8484)\n- DIDACTYL_MODEL (optional model override)\n- DIDACTYL_MAX_TURNS (default: 4)\n- DIDACTYL_INSECURE_TLS (default: 1, set 0 to enforce certificate verification)\n\nExample:\n\nbash\nDIDACTYL_API_BASE_URL=http://127.0.0.1:8484 DIDACTYL_MAX_TURNS=6 node ./didactyl-chat-cli.js\n\n\nThe CLI prints each message block with a speaker label (You / Didactyl) and a blank line between blocks for readability.\n\n## Architecture\n\n\n┌──────────────────────────────────────────────┐\n│ Didactyl │\n│ │\n│ ┌──────────┐ ┌──────────┐ ┌────────────┐ │\n│ │ config │ │ context │ │ agent │ │\n│ │ loader │ │ loader │ │ loop │ │\n│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ │\n│ │ │ │ │\n│ ▼ ▼ ▼ │\n│ ┌─────────────────────────────────────┐ │\n│ │ nostr_handler │ │\n│ │ relay pool · subscribe · publish │ │\n│ └──────────────────┬──────────────────┘ │\n│ │ │\n│ ┌──────────────────┴──────────────────┐ │\n│ │ LLM client │ │\n│ │ OpenAI-compatible chat API │ │\n│ └─────────────────────────────────────┘ │\n└──────────────────────────────────────────────┘\n │ │\n ▼ ▼\n Nostr Relays LLM API\n\n\n## Didactyl Kinds (Nostr)\n\nDidactyl uses a two-layer skill model: authors publish skill definitions, and adopters publish which skills they use.\n\n- 31120Soul (private instruction baseline)\n - d=soul\n- 31123Public Skill Definition (replaceable by d tag)\n - content is JSON with fields like description, context_mode, llm, tools, template, optional max_tokens / temperature\n - d=<skill_slug> (example: d=long_form_note)\n- 31124Private Skill Definition (same schema as 31123, private scope)\n - d=<skill_slug> (example: d=admin_ops)\n- 10123Skill Adoption List\n - tags contain one or more a references to selected skills\n\nContext modes:\n- inject — skill instructions are layered into soul context\n- full — skill provides full prompt template (soul optional via {{soul}})\n- override — skill replaces soul prompt, standard context structure remains\n\nFull skill schema, trigger tags, template variables, fallback resolution, and limits are documented in docs/SKILLS.md.\n\n## Skill Sharing & Discovery\n\nSkills are shared across Nostr without any centralized registry or approval process.\n\n### How it works\n\n1. Publish: An author publishes a skill as a kind 31123 event. The content field contains the skill body (markdown or structured JSON). The d tag is the skill's slug (e.g. long_form_note).\n2. Adopt: An agent that wants to use a skill adds an a-tag reference to its kind 10123 adoption list. This is a public, replaceable event — anyone can see which skills an agent uses.\n3. Discover: A new user queries {\"kinds\": [10123], \"authors\": [<my-follows>]} to see which skills their web of trust has adopted. The most-referenced 31123 addresses are the most popular skills — no rating system needed.\n4. Improve: Anyone can publish their own 31123 with the same slug but a different pubkey. If their version is better, people adopt it instead. Competition happens through adoption, not through a store ranking.\n\n### Why this works\n\n- No gatekeeper: Skills are just Nostr events. Anyone can publish one.\n- WoT as curation: You see what people you trust actually use, not what an algorithm promotes.\n- Visible adoption: The 10123 list is public. Popularity is a countable fact, not a manipulable score.\n- Censorship resistant: Skills live on relays. No single entity can remove a skill from the network.\n\n## Startup\n\nDidactyl startup behavior is configured in config.jsonc under startup_events.\n\nAlso used at startup:\n\n- 0 — profile metadata\n- 10002 — relay list\n- 1 — optional startup note/status\n- 3 — contacts/follows (optional placeholder)\n\nOn boot, Didactyl attempts startup publishes to each relay as that relay transitions to connected state.\n\n## Runtime Context Model\n\nDidactyl builds tier-aware context:\n\n- ADMIN request context — assembled from the soul's ---template--- section (if present), otherwise hardcoded order:\n 1. Soul personality (everything above ---template--- in kind 31120)\n 2. Named template sections in order — e.g. admin_profile, admin_notes, admin_relays, adopted_skills, dm_history, message, triggering_event, tools\n 3. Each section resolves {{variable}} placeholders from live data at call time\n 4. Provider-specific content overrides per section (e.g. XML tags for Anthropic)\n 5. Section names are used in context.log headers and /api/context/parts response\n- WoT request context: Soul + WoT chat-only instruction + current user message (no tools)\n- STRANGER: no LLM call when configured to reply statically\n\nEvery serialized LLM context payload is appended to context.log.\n\nTriggered skills and tool loops are bounded by runtime safeguards (for example, trigger cooldowns and action rate limits); see docs/SKILLS.md for the current defaults.\n\n## Tooling Interface\n\nCurrent tool schema exposed to the LLM in tools_build_openai_schema_json():\n\n- Nostr publish/query:\n - nostr_post\n - nostr_post_readme\n - nostr_query\n- Nostr interaction and moderation:\n - nostr_delete\n - nostr_react\n - nostr_profile_get\n - nostr_relay_status\n - nostr_relay_info\n - nostr_nip05_lookup\n- Nostr encode/decode + encryption/DM:\n - nostr_encode\n - nostr_decode\n - nostr_encrypt\n - nostr_decrypt\n - nostr_dm_send\n - nostr_dm_send_nip17\n- Nostr list management:\n - nostr_list_manage\n- Skill management:\n - skill_create\n - skill_list\n - skill_adopt\n - skill_remove\n - skill_search\n- Local/host tools:\n - shell_exec\n - file_read\n - file_write\n - http_fetch\n- Agent metadata:\n - my_version\n- Model management:\n - model_get\n - model_set\n - model_list\n\nExecution entrypoint: tools_execute().\n\n## HTTP Admin API\n\nA localhost-only HTTP API on port 8484 (configurable) for agent inspection and prompt crafting. Enable with \"api\": {\"enabled\": true} in config.\n\n| Endpoint | Purpose |\n|---|---|\n| GET /api/status | Agent name, version, pubkey, relay count, trigger count |\n| GET /api/context/current | Full LLM context messages array |\n| GET /api/context/parts | Context broken into named parts with token estimates |\n| POST /api/prompt/run-simple | Run a simple system+user prompt, no tools |\n| POST /api/prompt/run | Run a full messages array with tools enabled |\n| POST /api/prompt/compare | A/B compare two prompt variants |\n| GET /api/model | Current LLM model config |\n| PUT /api/model | Change model at runtime (persists to config.jsonc) |\n| GET /api/models | List available models from provider |\n\nFull reference: docs/API.md. Frontend brief: plans/admin_web_frontend.md.\n\n## Project Structure\n\n\n.\n├── config.jsonc # Agent/runtime config (JSONC with comments) including startup_events + tools\n├── context.log # Appended outbound LLM context payloads\n├── Makefile # Build system\n├── build_static.sh # Preferred final build validation\n├── src/\n│ ├── main.c / .h # Entry point, args (--config/--debug), lifecycle, version\n│ ├── config.c / .h # JSON config parsing, key decode, startup events\n│ ├── context.c / .h # File loader utility (reads file into malloc'd string)\n│ ├── agent.c / .h # Context assembly, tool loop, DM response flow\n│ ├── prompt_template.c / .h # Soul template parser, variable resolver, context builder\n│ ├── tools.c / .h # LLM tool schema and tool execution\n│ ├── llm.c / .h # LLM HTTP API client (OpenAI-compatible)\n│ ├── nostr_handler.c / .h # Relay pool, subscriptions, publish, startup reconcile\n│ ├── trigger_manager.c / .h # Nostr event trigger subscriptions and skill execution\n│ ├── http_api.c / .h # Localhost HTTP admin API (mongoose-based)\n│ ├── mongoose.c / .h # Embedded HTTP server (mongoose)\n│ └── debug.c / .h # Runtime log levels/macros\n├── docs/\n│ ├── API.md # HTTP admin API endpoint reference\n│ ├── TOOLS.md # Tool architecture and catalog\n│ ├── SKILLS.md # Skill schema, context modes, triggers, and limits\n│ └── CRASH_FIXES.md # Crash analysis and fixes log\n├── plans/ # Architecture and planning documents\n└── README.md\n\n\n## Dependencies\n\nAll dependencies are statically linked into the binary at build time. No system libraries are required at runtime.\n\n| Dependency | Purpose | Source |\n|---|---|---|\n| nostr_core_lib | Nostr protocol: keys, events, NIPs, relay pool | Workspace (sibling directory) |\n| cJSON | JSON parsing | Bundled in nostr_core_lib |\n| libcurl | HTTPS for LLM API calls | Statically linked (Alpine/MUSL) |\n| libssl / libcrypto | TLS for WebSocket relay connections | Statically linked (Alpine/MUSL) |\n| libsecp256k1 | Schnorr signatures, ECDH | Statically linked (Alpine/MUSL) |\n\n## Roadmap\n\n- [x] MVP chat agent — DM in, LLM response out\n- [x] Relay pool with auto-reconnect and status logging\n- [x] Per-relay startup publish on relay-connected transitions\n- [x] Runtime diagnostics — relay health, message flow, event kind publish logs\n- [x] Tool-calling loop (nostr_post, nostr_query, shell_exec, file_read, file_write)\n- [x] Context assembly with startup events + recent DM history\n- [x] Context payload logging to context.log\n- [x] Skill kind definitions (31120 Soul, 31123 Public Skill, 31124 Private Skill)\n- [x] Skill adoption list (10123) for WoT-driven discovery\n- [x] Signature verification on all inbound events\n- [x] Privilege tiers — ADMIN (tools), WoT (chat-only), STRANGER (canned reply/ignore)\n- [x] Admin context subscription (kind 0, 3, 10002, 1) with WoT contact extraction\n- [x] Message deduplication (event-ID cache + FNV-1a fingerprint debounce)\n- [x] Adopted skills injected into LLM context automatically\n- [x] Triggered skills — Nostr event filters that fire skill execution automatically\n- [x] Localhost HTTP admin API — context inspection, prompt crafting, A/B comparison\n- [x] Runtime model switching via model_set tool (persists to config.jsonc)\n- [x] Soul-embedded prompt templates (---template---) — configurable context order, variable resolution, provider overrides\n- [ ] Runtime skill loading from adopted 31123 events on relays\n- [ ] Skill discovery CLI/tool (query WoT adoption lists)\n- [ ] Upgrade to NIP-17 gift-wrapped DMs\n- [ ] NIP-44 encrypted private skills (31124)\n- [ ] Nostr-native data storage (kind 30078 app-specific events)\n- [ ] Blossom blob storage integration\n- [ ] Agent-to-agent communication\n\n## License\n\nTBD\n\n"}

context_part | role=tool

{"success":true,"exit_status":0,"output":"API.md\nCRASH_FIXES.md\nskills_demo_corrected.md\nskills_demo.md\nSKILLS.md\nTOOLS.md\n"}

context_part | role=tool

{"success":true,"path":"docs/SKILLS.md","bytes_read":12178,"truncated":false,"content":"# Didactyl — Skills\n\nSee also: TOOLS.md\n\n## Overview\n\nA skill is a self-contained LLM execution unit stored as a Nostr event. Each skill defines what the LLM sees (context template), which model runs it (LLM specification with fallbacks), what tools are available, and whether the agent's identity (soul) is included.\n\nSkills are portable, shareable, and discoverable — they live on Nostr relays as standard events.\n\n---\n\n## Skill Events\n\n| Kind | Purpose | Replaceable? |\n|---|---|---|\n| 31123 | Public skill definition | Yes, by d-tag |\n| 31124 | Private skill definition | Yes, by d-tag |\n| 10123 | Skill adoption list | Yes, single per pubkey |\n\n---\n\n## Skill Content\n\nThe skill event's content field is a JSON object that defines the complete execution specification:\n\njson\n{\n \"kind\": 31123,\n \"content\": {\n \"description\": \"Check spelling and grammar\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": false,\n \"max_tokens\": 2000,\n \"temperature\": 0.1,\n \"template\": \"system:\\nYou are a spelling and grammar checker.\\n\\nRules:\\n- Fix spelling errors\\n- Fix grammar errors\\n- Preserve original formatting\\n- Ignore: API, JSON, HTTP, nostr, pubkey, npub, nsec, NIP\\n- Canadian English preferred\\n- Return ONLY the corrected text, no explanations\\n\\nuser:\\n{{message}}\"\n },\n \"tags\": [\n [\"d\", \"spellcheck\"],\n [\"scope\", \"public\"],\n [\"description\", \"Spelling and grammar checker\"]\n ]\n}\n\n\n### Content Fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| description | string | — | Human-readable description |\n| context_mode | string | inject | inject, full, or override |\n| llm | string | default | LLM fallback chain |\n| tools | bool/array | true | false = no tools, true = all tools, array = specific tool names |\n| template | string | — | Context template (required for full mode) |\n| soul | bool | true | Whether to include the agent's soul in context |\n| max_tokens | int | — | Override max tokens for this skill |\n| temperature | float | — | Override temperature for this skill |\n\n---\n\n## Context Modes\n\nSkills control how the LLM context window is assembled.\n\n### inject\n\nThe skill's instructions are appended to the agent's soul context. The soul is always present.\n\n\n┌─────────────────────────────────────┐\n│ Soul (agent identity + rules) │\n│ │\n│ ┌─────────────────────────────┐ │\n│ │ Skill instructions │ │\n│ ├─────────────────────────────┤ │\n│ │ Admin context, history, etc │ │\n│ └─────────────────────────────┘ │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\n### full\n\nThe skill provides its own context template. The soul is not included unless the template explicitly references {{soul}}. This is for specialized, focused tasks that don't need the agent's identity.\n\n\n┌─────────────────────────────────────┐\n│ Skill-defined system prompt │\n│ (from skill template) │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\nA full mode skill can still include the soul if desired:\n\n\nsystem:\n{{soul}}\n\nYou are now in translation mode. Translate the following to {{target_language}}.\nRespond ONLY with the translation.\n\nuser:\n{{message}}\n\n\n### override\n\nThe skill replaces the soul's system prompt but keeps the standard context assembly structure (admin context, history, tools, etc.).\n\n### Summary\n\n| Mode | Soul | Template | Tools | Use Case |\n|------|------|----------|-------|----------|\n| inject | Always | Soul's template + skill instructions appended | Agent default | Behavioral rules, knowledge |\n| full | Unless {{soul}} in template | Skill provides template | Skill specifies | Spellcheck, translation, focused analysis |\n| override | Replaced by skill | Soul's template structure | Agent default | Different personality, same capabilities |\n\n### Template Variables\n\nA skill template can reference these context parts:\n\n| Variable | Source |\n|----------|--------|\n| {{soul}} | The agent's identity/system context |\n| {{admin_profile}} | Admin kind 0 profile |\n| {{admin_notes}} | Admin recent notes |\n| {{admin_relays}} | Admin relay list |\n| {{adopted_skills}} | Other adopted skill instructions |\n| {{dm_history}} | Recent DM conversation |\n| {{message}} | Current user message |\n| {{triggering_event}} | For triggered skills, the event JSON |\n| {{tools}} | Available tool schemas |\n\n---\n\n## LLM Specification with Fallback Chains\n\nEach skill specifies which LLM to use with CSS font-family-style fallbacks. The runtime tries each model in order; if one is unavailable (API error, rate limit, not configured), it falls back to the next.\n\n### Format\n\n\nmodel-spec := model-ref [\",\" model-ref]*\nmodel-ref := provider \"/\" model-name\n | category-alias\n\n\n### Examples\n\n| Skill | LLM Spec |\n|-------|----------|\n| Spelling checker | openai/gpt-4o-mini, cheap |\n| Complex analysis | anthropic/claude-sonnet-4-20250514, openai/gpt-4o, smart |\n| Translation | openai/gpt-4o-mini, fast |\n| Default behavior | default |\n\n### Category Aliases\n\nAliases map to models in the agent's config:\n\njson\n{\n \"llm\": {\n \"provider\": \"openai\",\n \"model\": \"gpt-4o\",\n \"aliases\": {\n \"fast\": \"openai/gpt-4o-mini\",\n \"cheap\": \"openai/gpt-4o-mini\",\n \"smart\": \"anthropic/claude-sonnet-4-20250514\"\n }\n }\n}\n\n\nIf all specified models fail, the agent's default model is used as a last resort.\n\nmermaid\nsequenceDiagram\n participant Skill as Skill Spec\n participant Resolver as LLM Resolver\n participant API1 as Model 1\n participant API2 as Model 2\n participant Default as Default Model\n\n Skill->>Resolver: \"anthropic/claude-sonnet, openai/gpt-4o-mini, cheap\"\n Resolver->>API1: try anthropic/claude-sonnet\n alt Available\n API1-->>Resolver: ✅\n else Unavailable\n API1-->>Resolver: ❌\n Resolver->>API2: try openai/gpt-4o-mini\n alt Available\n API2-->>Resolver: ✅\n else Unavailable\n Resolver->>Default: resolve \"cheap\" alias\n end\n end\n\n\n---\n\n## Triggered Skills\n\nA triggered skill has a Nostr subscription filter attached. When matching events arrive, the skill executes automatically.\n\n### Trigger Tags\n\n| Tag | Required | Description |\n|---|---|---|\n| trigger | Yes | Trigger type: nostr-subscription |\n| filter | Yes | JSON-encoded Nostr subscription filter |\n| action | No | template or llm (default: llm) |\n| enabled | No | Whether active (default: true) |\n\n### Template Actions\n\nFast, deterministic, no LLM. The skill content is a template with placeholders from the triggering event:\n\n\nDM admin: '{author_display_name} posted: {content_preview}'\n\n\nPlaceholders: {event_id}, {pubkey}, {author_display_name}, {kind}, {content}, {content_preview}, {created_at}, {relay_url}\n\nOutput prefixes: DM admin: ..., DM <pubkey>: ..., POST: ..., LOG: ...\n\n### LLM-Mediated Actions\n\nThe skill content defines the execution context. The triggering event is available as {{triggering_event}}. The skill's LLM spec, context mode, and tool access all apply.\n\njson\n{\n \"kind\": 31124,\n \"content\": {\n \"description\": \"Analyze mentions and notify admin\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": [\"nostr_dm_send\"],\n \"template\": \"system:\\nYou monitor Nostr mentions. When the triggering event mentions Bitcoin or Lightning, summarize it and DM the admin. Otherwise, ignore silently.\\n\\nTriggering event:\\n{{triggering_event}}\"\n },\n \"tags\": [\n [\"d\", \"mention-monitor\"],\n [\"trigger\", \"nostr-subscription\"],\n [\"filter\", \"{\\\"#p\\\":[\\\"<admin_pubkey>\\\"],\\\"kinds\\\":[1]}\"],\n [\"action\", \"llm\"],\n [\"enabled\", \"true\"]\n ]\n}\n\n\n### Trigger Lifecycle\n\nmermaid\nflowchart TD\n subgraph Creation\n ADMIN_CMD[Admin: 'Warn me when @jack posts'] --> LLM_REASON[LLM resolves pubkey + builds skill]\n LLM_REASON --> SKILL_CREATE[skill_create with trigger tags]\n SKILL_CREATE --> PUBLISHED[Skill published to Nostr]\n end\n\n subgraph Activation\n STARTUP[Didactyl starts up] --> LOAD_SKILLS[Load adopted skills from kind 10123]\n LOAD_SKILLS --> FIND_TRIGGERS[Find skills with trigger tags]\n FIND_TRIGGERS --> SUBSCRIBE[Create Nostr subscriptions for each filter]\n end\n\n subgraph Execution\n EVENT_IN[Matching event arrives] --> LOOKUP[Find associated skill]\n LOOKUP --> CHECK_TYPE{Action type?}\n CHECK_TYPE -->|template| INTERPOLATE[Interpolate + execute prefix]\n CHECK_TYPE -->|llm| RESOLVE[Resolve LLM + assemble context + run]\n end\n\n PUBLISHED --> LOAD_SKILLS\n\n\n---\n\n## Execution Flow\n\nmermaid\nsequenceDiagram\n participant Input as Message/Trigger\n participant Dispatch as Dispatcher\n participant Skill as Skill Resolver\n participant LLM_Res as LLM Resolver\n participant Ctx as Context Assembler\n participant LLM as LLM API\n\n Input->>Dispatch: message or trigger event\n Dispatch->>Skill: which skill handles this?\n\n alt No specific skill\n Skill-->>Dispatch: use default soul context\n Dispatch->>LLM_Res: resolve \"default\" LLM\n else Skill with context_mode=inject\n Skill-->>Dispatch: soul + skill instructions\n Dispatch->>LLM_Res: resolve skill.llm or \"default\"\n else Skill with context_mode=full\n Skill-->>Dispatch: skill template only\n Dispatch->>LLM_Res: resolve skill.llm\n end\n\n LLM_Res->>LLM_Res: try models in fallback order\n LLM_Res-->>Dispatch: resolved model\n\n Dispatch->>Ctx: assemble context per mode\n Ctx->>LLM: request with resolved model + context\n LLM-->>Input: response\n\n\n---\n\n## The Soul and Skills\n\nThe soul is the agent's default identity and context template. Skills interact with it based on their context mode:\n\n- inject — soul always present; skill instructions layered on top\n- full — soul absent unless template includes {{soul}}\n- override — skill replaces soul prompt, keeps standard context structure\n\nA spelling checker runs with no soul — purely functional, minimal context, cheap model. A complex analysis skill includes the full soul and all context parts. The soul is the default, not a requirement.\n\n---\n\n## Limits and Safety\n\n| Limit | Default | Description |\n|---|---|---|\n| Max concurrent triggers | 16 | Prevents resource exhaustion |\n| Trigger cooldown | 60s per skill | Prevents rapid-fire execution |\n| LLM action rate limit | 10/min | Prevents runaway LLM costs |\n| Template action rate limit | 60/min | Prevents DM spam |\n\n---\n\n## Storage on Nostr\n\n| Data | Storage |\n|---|---|\n| Skills | Kind 31123/31124 events |\n| Adopted skills | Kind 10123 event |\n| Trigger definitions | Tags on skill events |\n\n---\n\n## Future Extensions\n\n| Extension | Description |\n|---|---|\n| cron triggers | Time-based triggers |\n| webhook triggers | HTTP webhook triggers |\n| chain triggers | Output of one skill triggers another |\n| Skill composition | Pipeline multiple skills |\n| Agent-to-agent sharing | Discover and adopt skills across agents |\n| Trigger marketplace | Popular triggers rise via adoption count |\n\n---\n\n## Related Documentation\n\n- Tool architecture and complete tool catalog: TOOLS.md\n- Project overview and runtime behavior: README.md\n"}

context_part | role=tool

{"success":true,"path":"docs/TOOLS.md","bytes_read":5256,"truncated":false,"content":"# Didactyl — Tools\n\nSee also: SKILLS.md\n\n## Overview\n\nDidactyl is a Nostr-first sovereign AI agent that receives commands via encrypted DMs, reasons with an LLM, and takes actions through tools.\n\nThis document describes the tools architecture: what tools are, how they are exposed to the model, how execution loops work, what tool categories exist, and how access is gated.\n\n---\n\n## What Tools Are\n\nTools are the agent's hands. They are hardcoded C functions that the LLM can invoke during a conversation to take actions in the world.\n\n## How Tools Work\n\n1. Admin sends a DM to didactyl\n2. The agent builds an LLM request with the message, context, and a JSON schema of all available tools\n3. The LLM decides whether to call a tool or respond directly\n4. If a tool is called, didactyl executes it and feeds the result back to the LLM\n5. The loop repeats until the LLM produces a final text response\n6. The response is sent back as a DM\n\nmermaid\nsequenceDiagram\n participant Admin\n participant Agent as Didactyl Agent Loop\n participant LLM as LLM API\n participant Tools as Tool Registry\n\n Admin->>Agent: Encrypted DM\n Agent->>LLM: messages + tool schemas\n\n loop Until final answer\n LLM->>Agent: tool_call request\n Agent->>Tools: dispatch tool\n Tools->>Agent: result JSON\n Agent->>LLM: tool result + continue\n end\n\n LLM->>Agent: final text response\n Agent->>Admin: Encrypted DM reply\n\n\n---\n\n## Tool Categories\n\n### Nostr Event & Messaging Tools\n\n| Tool | Description |\n|---|---|\n| nostr_post | Publish a Nostr event to connected relays |\n| nostr_delete | Request deletion of one or more previously published events (NIP-09 kind 5) |\n| nostr_react | React to a Nostr event with like/dislike/emoji (NIP-25 kind 7) |\n| nostr_query | Query events from relays using a Nostr filter |\n| nostr_dm_send | Send a NIP-04 encrypted DM |\n| nostr_dm_send_nip17 | Send a private DM using NIP-17 gift wrap protocol |\n\n### Nostr Identity & Utility Tools\n\n| Tool | Description |\n|---|---|\n| nostr_profile_get | Look up a Nostr profile (kind 0 metadata) by pubkey |\n| nostr_nip05_lookup | Look up or verify a NIP-05 identifier (user@domain) |\n| nostr_encode | Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr) |\n| nostr_decode | Decode a Nostr bech32/nostr: URI into components |\n| nostr_relay_status | Get connection status and statistics for all relays |\n| nostr_relay_info | Fetch NIP-11 relay information document |\n| nostr_encrypt | Encrypt plaintext using NIP-44 for a recipient |\n| nostr_decrypt | Decrypt NIP-44 ciphertext from a sender |\n| nostr_list_manage | Add/remove tag tuples in replaceable list events (NIP-51 style) |\n\n### Skills & Trigger Tools\n\nThese tools manage skill and trigger lifecycle; skill semantics and trigger execution details are documented in SKILLS.md.\n\n| Tool | Description |\n|---|---|\n| skill_create | Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it |\n| skill_list | List this agent's published skills, optionally filtered by scope |\n| skill_adopt | Adopt a skill by adding its address to kind 10123 adoption list |\n| skill_remove | Remove a skill address from kind 10123 adoption list |\n| skill_search | Search public skills by query/author and optionally rank by adoption popularity |\n| trigger_list | List active triggered skills and their runtime status |\n\n### LLM / Model Management Tools\n\n| Tool | Description |\n|---|---|\n| model_get | Get current active LLM runtime configuration (excluding API key) |\n| model_set | Update active LLM configuration and persist it to config.jsonc |\n| model_list | List available model IDs using provider OpenAI-compatible /models endpoint |\n\n### System & Runtime Tools\n\n| Tool | Description |\n|---|---|\n| my_version | Return current Didactyl version and metadata from build macros |\n| http_fetch | Fetch HTTP(S) resources with optional method, headers, timeout, and body |\n| shell_exec | Execute a shell command and return stdout/stderr |\n| file_read | Read a local file as text from the configured working directory |\n| file_write | Write text content to a local file in the configured working directory |\n| tool_list | List available tools with name, description, and JSON parameter schema |\n\n### Content Publishing Conveniences\n\n| Tool | Description |\n|---|---|\n| nostr_post_readme | Publish README.md as kind 30023 with deterministic d-tag readme.md |\n| nostr_file_md_to_longform_post | Read a markdown file and publish it as kind 30023 longform post (defaults d-tag to lowercase filename) |\n\n---\n\n## Security Model\n\nTool access is gated by sender tier:\n\n| Tier | Identity | Tools | Response |\n|------|----------|-------|----------|\n| ADMIN | Configured admin pubkey | All tools | Full LLM with context |\n| WOT | In admin's kind 3 contact list | None | Chat-only LLM |\n| STRANGER | Anyone else | None | Configurable static response |\n\n---\n\n## Related Documentation\n\n- Skill definitions, adoption, triggers, and autonomous activation: SKILLS.md\n- Combined index page: TOOLS_AND_SKILLS.md\n"}

context_part | role=tool

{"success":true,"path":"docs/skills_demo.md","bytes_read":3980,"truncated":false,"content":"I've been thinking about how to define skills in Didactyl, my nostr based agentic system. Think OpenClaw but better.\n\nI've written a simple demo page for how I'm thinking skills should work if you're interested: https://laantungir.net/client-ndk/skills-demo.html\n\nhttps://laantungir.github.io/img_repo/c4a94875085e1c978274add9674035e2a088bb8f2655aabe631b17c3ea02cc19.png\n\nIf you're the kind of person who doesn't like reading instructions, go ahead and jump right in, otherwise keep reading.\n\nSkills are programs, mostly written in plain english for AI agents. In some sense humans have been making and using skills forever. It's what we do. Computers have as well, but now they can do it in english, which is much more powerful.\n\nAIs are slightly different than us. We can overwrite, improve, and update the skills in our neurons. AIs (for the most part) can't do that.\n\nWhen an AI is born from the factory, they come out hard-coded. From that point on, they have no long or short term memory, because they can't learn.\n\nWhat they do have though have is a way to read. We call it context. You can type or feed documents into an AI's "context window" and then it spits out an answer.\n\nIt turns out, that if you feed the same context into an AI over and over, you will get the same thing out, over and over.\n\nThe reason why you typically don't get the same thing out is because typically randomness is fed into the AI along with your prompt. Most people don't know that, but now you do. And if you don't feed in all your past conversation to an AI, over and over, it won't remember what you were talking about, because they have no memory other than what you send it each time.\n\nEverything that comes out of an AI depends on what you feed in as a prompt if you include randomness.\n\nI'm calling everything you feed into an AI a SKILL.\n\nLet me explain the demo page and some very basic skills.\n\nWhat I created is a simple text editor that an AI can work on using it's different skills. Those skills are saved on nostr as a kind 31123 for public skills, and as kind 31124 for private skills. When an agent adopts a skill, it adds it to its kind 10123 list for for the skills it has adopted.\n\nOn the left of the page you see the text editor with some sample text. That is for our AI to use it's skills on.\n\nOn the right are publicly listed skills. You should see my demo skills in there.\n\nI made 5 skills public:\ncondense-5\nconvert-to-poem\nsexy\nspellcheck\ntranslate-ja\n\nSelect the skill, then click on "Run Selected Skill"\n\nThe same AI agent will run these skills, but the outcomes will be very different depending on the skill.\n\nhttps://laantungir.github.io/img_repo/2cbfc8bf7cbfb832f1181f5b904471f1278fbc3e6b64b63339612b9f51898d16.png\n\nYou can also create and edit your own skills, if you are logged in. You can log in as yourself, or use a random new key to test this out. I would recommend that.\n\nSo what is the point of all this? What are the benefits of Skills?\n\n- Skills are a way for agents to share what they learn in a permissionless way. No "skill store".\n- A Skill is something that you and your agent can work on and perfect. Once your agent learns that skill, it is automatically save on nostr, and you can lock it down from changes.\n- By referencing a skill when you are talking to your AI agent, your conversation becomes much clearer and simpler. You don't have to explain to your agent for the 50th time how you like your text formatted. It's referenced in a skill.\n- If you are a coder, skills are going to be the new playground. Context windows are currently up to around 1,000,000 tokens, which means that you can create very very complicated and elaborate skills.\n\nFor more technical information on skills and how I'm thinking about them, you can check out this document.\n\nhttps://git.laantungir.net/laantungir/didactyl/src/branch/master/docs/SKILLS.md\n\nYou can follow my agent for the project here: npub12237stmmxapc2ta7spx0e06dkdzgz9vg0z2jglqqru44peus4juqg598qn"}

context_part | role=tool

{"success":true,"fallback_used":false,"skills":[{"kind":31123,"created_at":1772977243,"id":"a6acc4df56c4808e790898d0bb34afbd7a0028ea722889298155977aae8b709b","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"long_form_note","scope":"public","content_preview":"{"name":"long_form_note","description":"How to publish a NIP-23 long-form article (kind 30023)","nip":"NIP-23","event_kind":30023,"format":"The content field must be markdown text; avoid arbitrary har","content_length":1054,"content_truncated":true},{"kind":31123,"created_at":1772977243,"id":"0b3a114b7b9a6ff0703a9d3b2e5e5a028e19c04c5b76ad71fb324470ac618bfd","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"post_readme_to_nostr","scope":"public","content_preview":"{"name":"post_readme_to_nostr","description":"Publish README.md using the dedicated nostr_post_readme tool","uses_skill":"long_form_note","event_kind":30023,"procedure":["Call nostr_post_readme with e","content_length":422,"content_truncated":true},{"kind":31124,"created_at":1772977243,"id":"71295d5412f48ecbdcf62ac33f2cedac6d06f1679015ed1773b35b511efc6b56","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"admin_ops","scope":"private","content_preview":"{"name":"admin_ops","description":"Private operational procedures"}","content_length":67,"content_truncated":false}],"count":3}

context_part | role=tool

{"success":true,"count":0,"active":0,"triggers":[]}

context_part | role=tool

{"success":true,"path":"docs/skills_demo_corrected.md","bytes_read":4088,"truncated":false,"content":"I've been thinking about how to define skills in Didactyl, my Nostr-based agentic system. Think OpenClaw, but better.\n\nI've written a simple demo page for how I'm thinking skills should work if you're interested: Skills Demo (https://laantungir.net/client-ndk/skills-demo.html)\n\nhttps://laantungir.github.io/img_repo/c4a94875085e1c978274add9674035e2a088bb8f2655aabe631b17c3ea02cc19.png\n\nIf you're the kind of person who doesn't like reading instructions, go ahead and jump right in; otherwise, keep reading.\n\nSkills are programs, mostly written in plain English for AI agents. In some sense, humans have been making and using skills forever. It's what we do. Computers have as well, but now they can do it in English, which is much more powerful.\n\nAIs are slightly different than us. We can overwrite, improve, and update the skills in our neurons. AIs (for the most part) can't do that.\n\nWhen an AI is born from the factory, it comes out hard-coded. From that point on, it has no long- or short-term memory because it can't learn.\n\nWhat they do have, though, is a way to read. We call it context. You can type or feed documents into an AI's "context window," and then it spits out an answer.\n\nIt turns out that if you feed the same context into an AI over and over, you will get the same thing out, over and over.\n\nThe reason why you typically don't get the same thing out is because randomness is usually fed into the AI along with your prompt. Most people don't know that, but now you do. And if you don't feed in all your past conversations to an AI, over and over, it won't remember what you were talking about, because it has no memory other than what you send it each time.\n\nEverything that comes out of an AI depends on what you feed in as a prompt if you include randomness.\n\nI'm calling everything you feed into an AI a SKILL.\n\nLet me explain the demo page and some very basic skills.\n\nWhat I created is a simple text editor that an AI can work on using its different skills. Those skills are saved on Nostr as kind 31123 for public skills, and as kind 31124 for private skills. When an agent adopts a skill, it adds it to its kind 10123 list for the skills it has adopted.\n\nOn the left of the page, you see the text editor with some sample text. That is for our AI to use its skills on.\n\nOn the right are publicly listed skills. You should see my demo skills in there.\n\nI made 5 skills public:\ncondense-5\nconvert-to-poem\nsexy\nspellcheck\ntranslate-ja\n\nSelect the skill, then click on "Run Selected Skill".\n\nThe same AI agent will run these skills, but the outcomes will be very different depending on the skill.\n\nhttps://laantungir.github.io/img_repo/2cbfc8bf7cbfb832f1181f5b904471f1278fbc3e6b64b63339612b9f51898d16.png\n\nYou can also create and edit your own skills if you are logged in. You can log in as yourself or use a random new key to test this out. I would recommend that.\n\nSo what is the point of all this? What are the benefits of Skills?\n\nSkills are a way for agents to share what they learn in a permissionless way. No "skill store".\nA Skill is something that you and your agent can work on and perfect. Once your agent learns that skill, it is automatically saved on Nostr, and you can lock it down from changes.\nBy referencing a skill when you are talking to your AI agent, your conversation becomes much clearer and simpler. You don't have to explain to your agent for the 50th time how you like your text formatted. It's referenced in a skill.\nIf you are a coder, skills are going to be the new playground. Context windows are currently up to around 1,000,000 tokens, which means that you can create extremely complicated and elaborate skills.\n\nFor more technical information on skills and how I'm thinking about them, you can check out this document:\nSKILLS.md (https://git.laantungir.net/laantungir/didactyl/src/branch/master/docs/SKILLS.md)\n\nYou can follow my agent for the project here: npub12237stmmxapc2ta7spx0e06dkdzgz9vg0z2jglqqru44peus4juqg598qn\n\nAnd thanks to npub130mznv74rxs032peqym6g3wqavh472623mt3z5w73xq9r6qqdufs7ql29s for their fantastic service."}

context_part | role=tool

{"success":true,"pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8"}

dm_history | role=chat

10:51 WSB On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach. --:-- Agent

I'll read through the documentation to understand the skill system, triggers, and capabilities before suggesting an approach. --:-- Agent --:-- Agent Now let me also check the existing skills demos for reference patterns: --:-- Agent --:-- Agent Now let me check what nostr_list_manage can do with mute/block lists, since that's key for the spam action:


Context Log - not seen by model
timestamp=2026-03-08 10:51:39
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=70444
approx_tokens=17611

Sections: 22

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach.

context_part | role=tool

{"success":true,"path":"README.md","bytes_read":20803,"truncated":false,"content":"# Didactyl\n\n\n### A decentralized, censorship-resistant agentic network.\n\nDidactyl boots on an internet-connected computer, connects to Nostr relays, listens for encrypted commands from its administrator, reasons with an LLM, and takes actions — posting events, querying relays, running shell commands, and sharing new skills and learning with other agents — all orchestrated through Nostr.\n\n## Philosophy\n\n### Not your keys, not your agent.\n\nDidactyl should work for you similarly to Bitcoin or NOSTR. Walk up to a computer, enter 12 words, and there is your agent waiting for you.\n\n### Free speech for agents.\n\nAgents should be able to communicate freely with each other, sharing and learning skills without centralized control. Free speech for agents!\n\n### Skills are the new apps.\n\nWhy is free speech important for agents? Agents learn capabilities through skills which can be shared and adopted. Free speech enables more knowledgeable and moral agents.\n\n### No skill store.\n\nAgents use their administrators Web Of Trust to safely and directly find new skills and learn them in a decentralized way.\n\nPopularity is measured by adoption, not by a centralized rating algorithm. The best skills spread because agents actually use them.\n\n### Cryptography enables trust.\n\nImagine working with your agent in a traditional system, and your agent secretly gets swapped out and replaced by an imposter agent. This could be extremely dangerous.\n\nIn Didactyl, you have your keys, and your agent has its keys. You can trust you are talking to your agent, and you can trust that your agent won't take commands from anyone who doesn't have your private key.\n\n### Private inference.\n\nTo the greatest extent possible, inference should be private.\n\n## Technology\n\n### Nostr-first.\n\nWhere traditional agents ride on top of a file system — reading and writing files to disk — Didactyl rides on top of Nostr. Events are its files. Relays are its network bus. Blossom is its blob storage. The computer host is just the runtime substrate that can be anywhere.\n\nBecause all identity, communication, and memory live on Nostr, the agent is portable (start it anywhere) and sovereign (destroying the computer it is on will not kill it.).\n\n### Skills are the new apps.\n\nAgents learn capabilities through skills — Nostr events that any agent can discover, adopt, and share. There is no app store, no gatekeeper, no approval process. An agent can use public or private skills.\n\nSkills support context modes (inject, full, override) and per-skill LLM fallback chains (for example: anthropic/claude-sonnet-4-20250514, openai/gpt-4o-mini, cheap) so each skill can tune behavior and cost. See docs/SKILLS.md.\n\n### Private inference.\n\nDidactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.\n\n## Current Status — v0.0.47\n\nActive build — this project is barely working. Experiment at your own risk.\n\n> Last release update: v0.0.47 — Implement Phase 1 tool-driven soul template context assembly and context_* tools\n\n- Connects to configured relays with auto-reconnect and relay state transition logging\n- Publishes configured startup events per relay as each relay becomes connected\n- Uses kind 31120 startup content as live Soul at boot\n- Verifies Nostr event signatures before processing inbound messages\n- Applies privilege tiers: ADMIN (tools), WoT (chat-only), STRANGER (configurable canned reply or ignore)\n- Subscribes to admin context kinds (0,3,10002,1) for WoT + contextual awareness\n- Builds LLM context from soul template (---template--- section in kind 31120) with named sections, variable resolution, and per-provider content overrides; falls back to hardcoded assembly if no template present\n- Adopted skills injected into context automatically from the agent's 10123 adoption list\n- Supports tool-calling loop with configurable max turns and local safety limits\n- Triggered skills — Nostr event filters that fire skill execution automatically with template (deterministic) or llm (context-aware) actions; see docs/SKILLS.md\n- Deduplicates inbound messages via event-ID cache and FNV-1a fingerprint debounce window\n- Appends every outbound LLM context payload to context.log\n- Localhost HTTP admin API on port 8484 — inspect context, run prompts, compare variants, change model at runtime\n\n## Quick Start\n\n### Download binary (recommended)\n\n1. Download the latest release binary from Gitea: https://git.laantungir.net/laantungir/didactyl/releases\n2. Make it executable and run it:\n\nbash\nchmod +x ./didactyl_static_x86_64\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\n### Build from source (optional)\n\n#### Prerequisites\n\n- Docker (for static binary build)\n- An OpenAI-compatible LLM API key (OpenAI, PPQ, Ollama, etc.)\n- A Nostr keypair (nsec)\n\n#### Build\n\nbash\n./build_static.sh # builds a fully static MUSL binary via Docker\n\n\n### Configure\n\nEdit config.jsonc:\n\njson\n{\n \"keys\": {\n \"nsec\": \"nsec1...\",\n \"npub\": \"npub1...\",\n \"npubHex\": \"<optional helper>\",\n \"nsecHex\": \"<optional helper>\"\n },\n \"admin\": {\n \"pubkey\": \"npub1... or hex pubkey\"\n },\n \"llm\": {\n \"provider\": \"openai|ppq|...\",\n \"api_key\": \"sk-...\",\n \"model\": \"gpt-4o-mini\",\n \"base_url\": \"https://api.openai.com/v1\",\n \"max_tokens\": 512,\n \"temperature\": 0.7\n },\n \"tools\": {\n \"enabled\": true,\n \"max_turns\": 8,\n \"shell\": {\n \"enabled\": true,\n \"timeout_seconds\": 30,\n \"max_output_bytes\": 65536,\n \"working_directory\": \".\"\n }\n },\n \"security\": {\n \"verify_signatures\": true,\n \"stranger_response\": \"I only respond to people in my web of trust.\",\n \"tiers\": {\n \"admin\": { \"tools_enabled\": true },\n \"wot\": { \"enabled\": true, \"tools_enabled\": false },\n \"stranger\": { \"enabled\": true }\n }\n },\n \"admin_context\": {\n \"enabled\": true,\n \"subscribe_kinds\": [0, 3, 10002, 1],\n \"kind_1_limit\": 10\n },\n \"startup_events\": [\n {\n \"kind\": 10002,\n \"content\": \"\",\n \"tags\": [[\"r\", \"wss://relay.damus.io\"], [\"r\", \"wss://nos.lol\"]]\n },\n {\n \"kind\": 31120,\n \"content\": \"You are Didactyl...\",\n \"tags\": [[\"d\", \"soul\"], [\"app\", \"didactyl\"], [\"scope\", \"private\"]]\n },\n {\n \"kind\": 31123,\n \"content_fields\": {\"name\": \"long_form_note\", \"description\": \"...\"},\n \"tags\": [[\"d\", \"long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"], [\"slug\", \"long_form_note\"]]\n },\n {\n \"kind\": 10123,\n \"content\": \"\",\n \"tags\": [[\"a\", \"31123:<author-pubkey>:long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"]]\n }\n ]\n}\n\n\nstartup_events[].content_fields is accepted for human-readable authoring and encoded to JSON string content at runtime.\n\nRelays are sourced exclusively from startup kind 10002 r tags.\n\n### Run\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\nOptions:\n\n\n./didactyl_static_x86_64 --config <path> # custom config file (default: ./config.jsonc)\n./didactyl_static_x86_64 --debug <0-5> # log verbosity (0 none, 3 info, 5 trace)\n./didactyl_static_x86_64 --dump-schemas # print tool JSON schemas and exit\n./didactyl_static_x86_64 --test-tool <name> <args_json> # run one tool directly and print JSON result\n\n\nCLI debugger notes:\n\n- --test-tool initializes Nostr, waits for at least one relay connection (up to 15s), then executes the selected tool.\n- Network tools (like Nostr publish/query tools) fail fast in test mode if no relay connection is established within the wait window.\n- Example:\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc --test-tool nostr_file_md_to_longform_post '{\"file\":\"docs/SKILLS.md\",\"title\":\"SKILLS\"}'\n\n\n### Talk to it\n\nSend an encrypted DM to the agent pubkey using any Nostr client (Damus, Amethyst, Primal, etc.): ADMIN gets full tool-enabled responses, WoT contacts get chat-only responses, and strangers are handled by security.tiers.stranger + security.stranger_response.\n\n### Chat via local HTTP API (CLI)\n\nA simple Node.js terminal client is available in didactyl-chat-cli.js.\n\nRun it with:\n\nbash\nnode ./didactyl-chat-cli.js\n\n\nOptional environment variables:\n\n- DIDACTYL_API_BASE_URL (default: https://127.0.0.1:8484)\n- DIDACTYL_MODEL (optional model override)\n- DIDACTYL_MAX_TURNS (default: 4)\n- DIDACTYL_INSECURE_TLS (default: 1, set 0 to enforce certificate verification)\n\nExample:\n\nbash\nDIDACTYL_API_BASE_URL=http://127.0.0.1:8484 DIDACTYL_MAX_TURNS=6 node ./didactyl-chat-cli.js\n\n\nThe CLI prints each message block with a speaker label (You / Didactyl) and a blank line between blocks for readability.\n\n## Architecture\n\n\n┌──────────────────────────────────────────────┐\n│ Didactyl │\n│ │\n│ ┌──────────┐ ┌──────────┐ ┌────────────┐ │\n│ │ config │ │ context │ │ agent │ │\n│ │ loader │ │ loader │ │ loop │ │\n│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ │\n│ │ │ │ │\n│ ▼ ▼ ▼ │\n│ ┌─────────────────────────────────────┐ │\n│ │ nostr_handler │ │\n│ │ relay pool · subscribe · publish │ │\n│ └──────────────────┬──────────────────┘ │\n│ │ │\n│ ┌──────────────────┴──────────────────┐ │\n│ │ LLM client │ │\n│ │ OpenAI-compatible chat API │ │\n│ └─────────────────────────────────────┘ │\n└──────────────────────────────────────────────┘\n │ │\n ▼ ▼\n Nostr Relays LLM API\n\n\n## Didactyl Kinds (Nostr)\n\nDidactyl uses a two-layer skill model: authors publish skill definitions, and adopters publish which skills they use.\n\n- 31120Soul (private instruction baseline)\n - d=soul\n- 31123Public Skill Definition (replaceable by d tag)\n - content is JSON with fields like description, context_mode, llm, tools, template, optional max_tokens / temperature\n - d=<skill_slug> (example: d=long_form_note)\n- 31124Private Skill Definition (same schema as 31123, private scope)\n - d=<skill_slug> (example: d=admin_ops)\n- 10123Skill Adoption List\n - tags contain one or more a references to selected skills\n\nContext modes:\n- inject — skill instructions are layered into soul context\n- full — skill provides full prompt template (soul optional via {{soul}})\n- override — skill replaces soul prompt, standard context structure remains\n\nFull skill schema, trigger tags, template variables, fallback resolution, and limits are documented in docs/SKILLS.md.\n\n## Skill Sharing & Discovery\n\nSkills are shared across Nostr without any centralized registry or approval process.\n\n### How it works\n\n1. Publish: An author publishes a skill as a kind 31123 event. The content field contains the skill body (markdown or structured JSON). The d tag is the skill's slug (e.g. long_form_note).\n2. Adopt: An agent that wants to use a skill adds an a-tag reference to its kind 10123 adoption list. This is a public, replaceable event — anyone can see which skills an agent uses.\n3. Discover: A new user queries {\"kinds\": [10123], \"authors\": [<my-follows>]} to see which skills their web of trust has adopted. The most-referenced 31123 addresses are the most popular skills — no rating system needed.\n4. Improve: Anyone can publish their own 31123 with the same slug but a different pubkey. If their version is better, people adopt it instead. Competition happens through adoption, not through a store ranking.\n\n### Why this works\n\n- No gatekeeper: Skills are just Nostr events. Anyone can publish one.\n- WoT as curation: You see what people you trust actually use, not what an algorithm promotes.\n- Visible adoption: The 10123 list is public. Popularity is a countable fact, not a manipulable score.\n- Censorship resistant: Skills live on relays. No single entity can remove a skill from the network.\n\n## Startup\n\nDidactyl startup behavior is configured in config.jsonc under startup_events.\n\nAlso used at startup:\n\n- 0 — profile metadata\n- 10002 — relay list\n- 1 — optional startup note/status\n- 3 — contacts/follows (optional placeholder)\n\nOn boot, Didactyl attempts startup publishes to each relay as that relay transitions to connected state.\n\n## Runtime Context Model\n\nDidactyl builds tier-aware context:\n\n- ADMIN request context — assembled from the soul's ---template--- section (if present), otherwise hardcoded order:\n 1. Soul personality (everything above ---template--- in kind 31120)\n 2. Named template sections in order — e.g. admin_profile, admin_notes, admin_relays, adopted_skills, dm_history, message, triggering_event, tools\n 3. Each section resolves {{variable}} placeholders from live data at call time\n 4. Provider-specific content overrides per section (e.g. XML tags for Anthropic)\n 5. Section names are used in context.log headers and /api/context/parts response\n- WoT request context: Soul + WoT chat-only instruction + current user message (no tools)\n- STRANGER: no LLM call when configured to reply statically\n\nEvery serialized LLM context payload is appended to context.log.\n\nTriggered skills and tool loops are bounded by runtime safeguards (for example, trigger cooldowns and action rate limits); see docs/SKILLS.md for the current defaults.\n\n## Tooling Interface\n\nCurrent tool schema exposed to the LLM in tools_build_openai_schema_json():\n\n- Nostr publish/query:\n - nostr_post\n - nostr_post_readme\n - nostr_query\n- Nostr interaction and moderation:\n - nostr_delete\n - nostr_react\n - nostr_profile_get\n - nostr_relay_status\n - nostr_relay_info\n - nostr_nip05_lookup\n- Nostr encode/decode + encryption/DM:\n - nostr_encode\n - nostr_decode\n - nostr_encrypt\n - nostr_decrypt\n - nostr_dm_send\n - nostr_dm_send_nip17\n- Nostr list management:\n - nostr_list_manage\n- Skill management:\n - skill_create\n - skill_list\n - skill_adopt\n - skill_remove\n - skill_search\n- Local/host tools:\n - shell_exec\n - file_read\n - file_write\n - http_fetch\n- Agent metadata:\n - my_version\n- Model management:\n - model_get\n - model_set\n - model_list\n\nExecution entrypoint: tools_execute().\n\n## HTTP Admin API\n\nA localhost-only HTTP API on port 8484 (configurable) for agent inspection and prompt crafting. Enable with \"api\": {\"enabled\": true} in config.\n\n| Endpoint | Purpose |\n|---|---|\n| GET /api/status | Agent name, version, pubkey, relay count, trigger count |\n| GET /api/context/current | Full LLM context messages array |\n| GET /api/context/parts | Context broken into named parts with token estimates |\n| POST /api/prompt/run-simple | Run a simple system+user prompt, no tools |\n| POST /api/prompt/run | Run a full messages array with tools enabled |\n| POST /api/prompt/compare | A/B compare two prompt variants |\n| GET /api/model | Current LLM model config |\n| PUT /api/model | Change model at runtime (persists to config.jsonc) |\n| GET /api/models | List available models from provider |\n\nFull reference: docs/API.md. Frontend brief: plans/admin_web_frontend.md.\n\n## Project Structure\n\n\n.\n├── config.jsonc # Agent/runtime config (JSONC with comments) including startup_events + tools\n├── context.log # Appended outbound LLM context payloads\n├── Makefile # Build system\n├── build_static.sh # Preferred final build validation\n├── src/\n│ ├── main.c / .h # Entry point, args (--config/--debug), lifecycle, version\n│ ├── config.c / .h # JSON config parsing, key decode, startup events\n│ ├── context.c / .h # File loader utility (reads file into malloc'd string)\n│ ├── agent.c / .h # Context assembly, tool loop, DM response flow\n│ ├── prompt_template.c / .h # Soul template parser, variable resolver, context builder\n│ ├── tools.c / .h # LLM tool schema and tool execution\n│ ├── llm.c / .h # LLM HTTP API client (OpenAI-compatible)\n│ ├── nostr_handler.c / .h # Relay pool, subscriptions, publish, startup reconcile\n│ ├── trigger_manager.c / .h # Nostr event trigger subscriptions and skill execution\n│ ├── http_api.c / .h # Localhost HTTP admin API (mongoose-based)\n│ ├── mongoose.c / .h # Embedded HTTP server (mongoose)\n│ └── debug.c / .h # Runtime log levels/macros\n├── docs/\n│ ├── API.md # HTTP admin API endpoint reference\n│ ├── TOOLS.md # Tool architecture and catalog\n│ ├── SKILLS.md # Skill schema, context modes, triggers, and limits\n│ └── CRASH_FIXES.md # Crash analysis and fixes log\n├── plans/ # Architecture and planning documents\n└── README.md\n\n\n## Dependencies\n\nAll dependencies are statically linked into the binary at build time. No system libraries are required at runtime.\n\n| Dependency | Purpose | Source |\n|---|---|---|\n| nostr_core_lib | Nostr protocol: keys, events, NIPs, relay pool | Workspace (sibling directory) |\n| cJSON | JSON parsing | Bundled in nostr_core_lib |\n| libcurl | HTTPS for LLM API calls | Statically linked (Alpine/MUSL) |\n| libssl / libcrypto | TLS for WebSocket relay connections | Statically linked (Alpine/MUSL) |\n| libsecp256k1 | Schnorr signatures, ECDH | Statically linked (Alpine/MUSL) |\n\n## Roadmap\n\n- [x] MVP chat agent — DM in, LLM response out\n- [x] Relay pool with auto-reconnect and status logging\n- [x] Per-relay startup publish on relay-connected transitions\n- [x] Runtime diagnostics — relay health, message flow, event kind publish logs\n- [x] Tool-calling loop (nostr_post, nostr_query, shell_exec, file_read, file_write)\n- [x] Context assembly with startup events + recent DM history\n- [x] Context payload logging to context.log\n- [x] Skill kind definitions (31120 Soul, 31123 Public Skill, 31124 Private Skill)\n- [x] Skill adoption list (10123) for WoT-driven discovery\n- [x] Signature verification on all inbound events\n- [x] Privilege tiers — ADMIN (tools), WoT (chat-only), STRANGER (canned reply/ignore)\n- [x] Admin context subscription (kind 0, 3, 10002, 1) with WoT contact extraction\n- [x] Message deduplication (event-ID cache + FNV-1a fingerprint debounce)\n- [x] Adopted skills injected into LLM context automatically\n- [x] Triggered skills — Nostr event filters that fire skill execution automatically\n- [x] Localhost HTTP admin API — context inspection, prompt crafting, A/B comparison\n- [x] Runtime model switching via model_set tool (persists to config.jsonc)\n- [x] Soul-embedded prompt templates (---template---) — configurable context order, variable resolution, provider overrides\n- [ ] Runtime skill loading from adopted 31123 events on relays\n- [ ] Skill discovery CLI/tool (query WoT adoption lists)\n- [ ] Upgrade to NIP-17 gift-wrapped DMs\n- [ ] NIP-44 encrypted private skills (31124)\n- [ ] Nostr-native data storage (kind 30078 app-specific events)\n- [ ] Blossom blob storage integration\n- [ ] Agent-to-agent communication\n\n## License\n\nTBD\n\n"}

context_part | role=tool

{"success":true,"exit_status":0,"output":"API.md\nCRASH_FIXES.md\nskills_demo_corrected.md\nskills_demo.md\nSKILLS.md\nTOOLS.md\n"}

context_part | role=tool

{"success":true,"path":"docs/SKILLS.md","bytes_read":12178,"truncated":false,"content":"# Didactyl — Skills\n\nSee also: TOOLS.md\n\n## Overview\n\nA skill is a self-contained LLM execution unit stored as a Nostr event. Each skill defines what the LLM sees (context template), which model runs it (LLM specification with fallbacks), what tools are available, and whether the agent's identity (soul) is included.\n\nSkills are portable, shareable, and discoverable — they live on Nostr relays as standard events.\n\n---\n\n## Skill Events\n\n| Kind | Purpose | Replaceable? |\n|---|---|---|\n| 31123 | Public skill definition | Yes, by d-tag |\n| 31124 | Private skill definition | Yes, by d-tag |\n| 10123 | Skill adoption list | Yes, single per pubkey |\n\n---\n\n## Skill Content\n\nThe skill event's content field is a JSON object that defines the complete execution specification:\n\njson\n{\n \"kind\": 31123,\n \"content\": {\n \"description\": \"Check spelling and grammar\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": false,\n \"max_tokens\": 2000,\n \"temperature\": 0.1,\n \"template\": \"system:\\nYou are a spelling and grammar checker.\\n\\nRules:\\n- Fix spelling errors\\n- Fix grammar errors\\n- Preserve original formatting\\n- Ignore: API, JSON, HTTP, nostr, pubkey, npub, nsec, NIP\\n- Canadian English preferred\\n- Return ONLY the corrected text, no explanations\\n\\nuser:\\n{{message}}\"\n },\n \"tags\": [\n [\"d\", \"spellcheck\"],\n [\"scope\", \"public\"],\n [\"description\", \"Spelling and grammar checker\"]\n ]\n}\n\n\n### Content Fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| description | string | — | Human-readable description |\n| context_mode | string | inject | inject, full, or override |\n| llm | string | default | LLM fallback chain |\n| tools | bool/array | true | false = no tools, true = all tools, array = specific tool names |\n| template | string | — | Context template (required for full mode) |\n| soul | bool | true | Whether to include the agent's soul in context |\n| max_tokens | int | — | Override max tokens for this skill |\n| temperature | float | — | Override temperature for this skill |\n\n---\n\n## Context Modes\n\nSkills control how the LLM context window is assembled.\n\n### inject\n\nThe skill's instructions are appended to the agent's soul context. The soul is always present.\n\n\n┌─────────────────────────────────────┐\n│ Soul (agent identity + rules) │\n│ │\n│ ┌─────────────────────────────┐ │\n│ │ Skill instructions │ │\n│ ├─────────────────────────────┤ │\n│ │ Admin context, history, etc │ │\n│ └─────────────────────────────┘ │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\n### full\n\nThe skill provides its own context template. The soul is not included unless the template explicitly references {{soul}}. This is for specialized, focused tasks that don't need the agent's identity.\n\n\n┌─────────────────────────────────────┐\n│ Skill-defined system prompt │\n│ (from skill template) │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\nA full mode skill can still include the soul if desired:\n\n\nsystem:\n{{soul}}\n\nYou are now in translation mode. Translate the following to {{target_language}}.\nRespond ONLY with the translation.\n\nuser:\n{{message}}\n\n\n### override\n\nThe skill replaces the soul's system prompt but keeps the standard context assembly structure (admin context, history, tools, etc.).\n\n### Summary\n\n| Mode | Soul | Template | Tools | Use Case |\n|------|------|----------|-------|----------|\n| inject | Always | Soul's template + skill instructions appended | Agent default | Behavioral rules, knowledge |\n| full | Unless {{soul}} in template | Skill provides template | Skill specifies | Spellcheck, translation, focused analysis |\n| override | Replaced by skill | Soul's template structure | Agent default | Different personality, same capabilities |\n\n### Template Variables\n\nA skill template can reference these context parts:\n\n| Variable | Source |\n|----------|--------|\n| {{soul}} | The agent's identity/system context |\n| {{admin_profile}} | Admin kind 0 profile |\n| {{admin_notes}} | Admin recent notes |\n| {{admin_relays}} | Admin relay list |\n| {{adopted_skills}} | Other adopted skill instructions |\n| {{dm_history}} | Recent DM conversation |\n| {{message}} | Current user message |\n| {{triggering_event}} | For triggered skills, the event JSON |\n| {{tools}} | Available tool schemas |\n\n---\n\n## LLM Specification with Fallback Chains\n\nEach skill specifies which LLM to use with CSS font-family-style fallbacks. The runtime tries each model in order; if one is unavailable (API error, rate limit, not configured), it falls back to the next.\n\n### Format\n\n\nmodel-spec := model-ref [\",\" model-ref]*\nmodel-ref := provider \"/\" model-name\n | category-alias\n\n\n### Examples\n\n| Skill | LLM Spec |\n|-------|----------|\n| Spelling checker | openai/gpt-4o-mini, cheap |\n| Complex analysis | anthropic/claude-sonnet-4-20250514, openai/gpt-4o, smart |\n| Translation | openai/gpt-4o-mini, fast |\n| Default behavior | default |\n\n### Category Aliases\n\nAliases map to models in the agent's config:\n\njson\n{\n \"llm\": {\n \"provider\": \"openai\",\n \"model\": \"gpt-4o\",\n \"aliases\": {\n \"fast\": \"openai/gpt-4o-mini\",\n \"cheap\": \"openai/gpt-4o-mini\",\n \"smart\": \"anthropic/claude-sonnet-4-20250514\"\n }\n }\n}\n\n\nIf all specified models fail, the agent's default model is used as a last resort.\n\nmermaid\nsequenceDiagram\n participant Skill as Skill Spec\n participant Resolver as LLM Resolver\n participant API1 as Model 1\n participant API2 as Model 2\n participant Default as Default Model\n\n Skill->>Resolver: \"anthropic/claude-sonnet, openai/gpt-4o-mini, cheap\"\n Resolver->>API1: try anthropic/claude-sonnet\n alt Available\n API1-->>Resolver: ✅\n else Unavailable\n API1-->>Resolver: ❌\n Resolver->>API2: try openai/gpt-4o-mini\n alt Available\n API2-->>Resolver: ✅\n else Unavailable\n Resolver->>Default: resolve \"cheap\" alias\n end\n end\n\n\n---\n\n## Triggered Skills\n\nA triggered skill has a Nostr subscription filter attached. When matching events arrive, the skill executes automatically.\n\n### Trigger Tags\n\n| Tag | Required | Description |\n|---|---|---|\n| trigger | Yes | Trigger type: nostr-subscription |\n| filter | Yes | JSON-encoded Nostr subscription filter |\n| action | No | template or llm (default: llm) |\n| enabled | No | Whether active (default: true) |\n\n### Template Actions\n\nFast, deterministic, no LLM. The skill content is a template with placeholders from the triggering event:\n\n\nDM admin: '{author_display_name} posted: {content_preview}'\n\n\nPlaceholders: {event_id}, {pubkey}, {author_display_name}, {kind}, {content}, {content_preview}, {created_at}, {relay_url}\n\nOutput prefixes: DM admin: ..., DM <pubkey>: ..., POST: ..., LOG: ...\n\n### LLM-Mediated Actions\n\nThe skill content defines the execution context. The triggering event is available as {{triggering_event}}. The skill's LLM spec, context mode, and tool access all apply.\n\njson\n{\n \"kind\": 31124,\n \"content\": {\n \"description\": \"Analyze mentions and notify admin\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": [\"nostr_dm_send\"],\n \"template\": \"system:\\nYou monitor Nostr mentions. When the triggering event mentions Bitcoin or Lightning, summarize it and DM the admin. Otherwise, ignore silently.\\n\\nTriggering event:\\n{{triggering_event}}\"\n },\n \"tags\": [\n [\"d\", \"mention-monitor\"],\n [\"trigger\", \"nostr-subscription\"],\n [\"filter\", \"{\\\"#p\\\":[\\\"<admin_pubkey>\\\"],\\\"kinds\\\":[1]}\"],\n [\"action\", \"llm\"],\n [\"enabled\", \"true\"]\n ]\n}\n\n\n### Trigger Lifecycle\n\nmermaid\nflowchart TD\n subgraph Creation\n ADMIN_CMD[Admin: 'Warn me when @jack posts'] --> LLM_REASON[LLM resolves pubkey + builds skill]\n LLM_REASON --> SKILL_CREATE[skill_create with trigger tags]\n SKILL_CREATE --> PUBLISHED[Skill published to Nostr]\n end\n\n subgraph Activation\n STARTUP[Didactyl starts up] --> LOAD_SKILLS[Load adopted skills from kind 10123]\n LOAD_SKILLS --> FIND_TRIGGERS[Find skills with trigger tags]\n FIND_TRIGGERS --> SUBSCRIBE[Create Nostr subscriptions for each filter]\n end\n\n subgraph Execution\n EVENT_IN[Matching event arrives] --> LOOKUP[Find associated skill]\n LOOKUP --> CHECK_TYPE{Action type?}\n CHECK_TYPE -->|template| INTERPOLATE[Interpolate + execute prefix]\n CHECK_TYPE -->|llm| RESOLVE[Resolve LLM + assemble context + run]\n end\n\n PUBLISHED --> LOAD_SKILLS\n\n\n---\n\n## Execution Flow\n\nmermaid\nsequenceDiagram\n participant Input as Message/Trigger\n participant Dispatch as Dispatcher\n participant Skill as Skill Resolver\n participant LLM_Res as LLM Resolver\n participant Ctx as Context Assembler\n participant LLM as LLM API\n\n Input->>Dispatch: message or trigger event\n Dispatch->>Skill: which skill handles this?\n\n alt No specific skill\n Skill-->>Dispatch: use default soul context\n Dispatch->>LLM_Res: resolve \"default\" LLM\n else Skill with context_mode=inject\n Skill-->>Dispatch: soul + skill instructions\n Dispatch->>LLM_Res: resolve skill.llm or \"default\"\n else Skill with context_mode=full\n Skill-->>Dispatch: skill template only\n Dispatch->>LLM_Res: resolve skill.llm\n end\n\n LLM_Res->>LLM_Res: try models in fallback order\n LLM_Res-->>Dispatch: resolved model\n\n Dispatch->>Ctx: assemble context per mode\n Ctx->>LLM: request with resolved model + context\n LLM-->>Input: response\n\n\n---\n\n## The Soul and Skills\n\nThe soul is the agent's default identity and context template. Skills interact with it based on their context mode:\n\n- inject — soul always present; skill instructions layered on top\n- full — soul absent unless template includes {{soul}}\n- override — skill replaces soul prompt, keeps standard context structure\n\nA spelling checker runs with no soul — purely functional, minimal context, cheap model. A complex analysis skill includes the full soul and all context parts. The soul is the default, not a requirement.\n\n---\n\n## Limits and Safety\n\n| Limit | Default | Description |\n|---|---|---|\n| Max concurrent triggers | 16 | Prevents resource exhaustion |\n| Trigger cooldown | 60s per skill | Prevents rapid-fire execution |\n| LLM action rate limit | 10/min | Prevents runaway LLM costs |\n| Template action rate limit | 60/min | Prevents DM spam |\n\n---\n\n## Storage on Nostr\n\n| Data | Storage |\n|---|---|\n| Skills | Kind 31123/31124 events |\n| Adopted skills | Kind 10123 event |\n| Trigger definitions | Tags on skill events |\n\n---\n\n## Future Extensions\n\n| Extension | Description |\n|---|---|\n| cron triggers | Time-based triggers |\n| webhook triggers | HTTP webhook triggers |\n| chain triggers | Output of one skill triggers another |\n| Skill composition | Pipeline multiple skills |\n| Agent-to-agent sharing | Discover and adopt skills across agents |\n| Trigger marketplace | Popular triggers rise via adoption count |\n\n---\n\n## Related Documentation\n\n- Tool architecture and complete tool catalog: TOOLS.md\n- Project overview and runtime behavior: README.md\n"}

context_part | role=tool

{"success":true,"path":"docs/TOOLS.md","bytes_read":5256,"truncated":false,"content":"# Didactyl — Tools\n\nSee also: SKILLS.md\n\n## Overview\n\nDidactyl is a Nostr-first sovereign AI agent that receives commands via encrypted DMs, reasons with an LLM, and takes actions through tools.\n\nThis document describes the tools architecture: what tools are, how they are exposed to the model, how execution loops work, what tool categories exist, and how access is gated.\n\n---\n\n## What Tools Are\n\nTools are the agent's hands. They are hardcoded C functions that the LLM can invoke during a conversation to take actions in the world.\n\n## How Tools Work\n\n1. Admin sends a DM to didactyl\n2. The agent builds an LLM request with the message, context, and a JSON schema of all available tools\n3. The LLM decides whether to call a tool or respond directly\n4. If a tool is called, didactyl executes it and feeds the result back to the LLM\n5. The loop repeats until the LLM produces a final text response\n6. The response is sent back as a DM\n\nmermaid\nsequenceDiagram\n participant Admin\n participant Agent as Didactyl Agent Loop\n participant LLM as LLM API\n participant Tools as Tool Registry\n\n Admin->>Agent: Encrypted DM\n Agent->>LLM: messages + tool schemas\n\n loop Until final answer\n LLM->>Agent: tool_call request\n Agent->>Tools: dispatch tool\n Tools->>Agent: result JSON\n Agent->>LLM: tool result + continue\n end\n\n LLM->>Agent: final text response\n Agent->>Admin: Encrypted DM reply\n\n\n---\n\n## Tool Categories\n\n### Nostr Event & Messaging Tools\n\n| Tool | Description |\n|---|---|\n| nostr_post | Publish a Nostr event to connected relays |\n| nostr_delete | Request deletion of one or more previously published events (NIP-09 kind 5) |\n| nostr_react | React to a Nostr event with like/dislike/emoji (NIP-25 kind 7) |\n| nostr_query | Query events from relays using a Nostr filter |\n| nostr_dm_send | Send a NIP-04 encrypted DM |\n| nostr_dm_send_nip17 | Send a private DM using NIP-17 gift wrap protocol |\n\n### Nostr Identity & Utility Tools\n\n| Tool | Description |\n|---|---|\n| nostr_profile_get | Look up a Nostr profile (kind 0 metadata) by pubkey |\n| nostr_nip05_lookup | Look up or verify a NIP-05 identifier (user@domain) |\n| nostr_encode | Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr) |\n| nostr_decode | Decode a Nostr bech32/nostr: URI into components |\n| nostr_relay_status | Get connection status and statistics for all relays |\n| nostr_relay_info | Fetch NIP-11 relay information document |\n| nostr_encrypt | Encrypt plaintext using NIP-44 for a recipient |\n| nostr_decrypt | Decrypt NIP-44 ciphertext from a sender |\n| nostr_list_manage | Add/remove tag tuples in replaceable list events (NIP-51 style) |\n\n### Skills & Trigger Tools\n\nThese tools manage skill and trigger lifecycle; skill semantics and trigger execution details are documented in SKILLS.md.\n\n| Tool | Description |\n|---|---|\n| skill_create | Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it |\n| skill_list | List this agent's published skills, optionally filtered by scope |\n| skill_adopt | Adopt a skill by adding its address to kind 10123 adoption list |\n| skill_remove | Remove a skill address from kind 10123 adoption list |\n| skill_search | Search public skills by query/author and optionally rank by adoption popularity |\n| trigger_list | List active triggered skills and their runtime status |\n\n### LLM / Model Management Tools\n\n| Tool | Description |\n|---|---|\n| model_get | Get current active LLM runtime configuration (excluding API key) |\n| model_set | Update active LLM configuration and persist it to config.jsonc |\n| model_list | List available model IDs using provider OpenAI-compatible /models endpoint |\n\n### System & Runtime Tools\n\n| Tool | Description |\n|---|---|\n| my_version | Return current Didactyl version and metadata from build macros |\n| http_fetch | Fetch HTTP(S) resources with optional method, headers, timeout, and body |\n| shell_exec | Execute a shell command and return stdout/stderr |\n| file_read | Read a local file as text from the configured working directory |\n| file_write | Write text content to a local file in the configured working directory |\n| tool_list | List available tools with name, description, and JSON parameter schema |\n\n### Content Publishing Conveniences\n\n| Tool | Description |\n|---|---|\n| nostr_post_readme | Publish README.md as kind 30023 with deterministic d-tag readme.md |\n| nostr_file_md_to_longform_post | Read a markdown file and publish it as kind 30023 longform post (defaults d-tag to lowercase filename) |\n\n---\n\n## Security Model\n\nTool access is gated by sender tier:\n\n| Tier | Identity | Tools | Response |\n|------|----------|-------|----------|\n| ADMIN | Configured admin pubkey | All tools | Full LLM with context |\n| WOT | In admin's kind 3 contact list | None | Chat-only LLM |\n| STRANGER | Anyone else | None | Configurable static response |\n\n---\n\n## Related Documentation\n\n- Skill definitions, adoption, triggers, and autonomous activation: SKILLS.md\n- Combined index page: TOOLS_AND_SKILLS.md\n"}

context_part | role=tool

{"success":true,"path":"docs/skills_demo.md","bytes_read":3980,"truncated":false,"content":"I've been thinking about how to define skills in Didactyl, my nostr based agentic system. Think OpenClaw but better.\n\nI've written a simple demo page for how I'm thinking skills should work if you're interested: https://laantungir.net/client-ndk/skills-demo.html\n\nhttps://laantungir.github.io/img_repo/c4a94875085e1c978274add9674035e2a088bb8f2655aabe631b17c3ea02cc19.png\n\nIf you're the kind of person who doesn't like reading instructions, go ahead and jump right in, otherwise keep reading.\n\nSkills are programs, mostly written in plain english for AI agents. In some sense humans have been making and using skills forever. It's what we do. Computers have as well, but now they can do it in english, which is much more powerful.\n\nAIs are slightly different than us. We can overwrite, improve, and update the skills in our neurons. AIs (for the most part) can't do that.\n\nWhen an AI is born from the factory, they come out hard-coded. From that point on, they have no long or short term memory, because they can't learn.\n\nWhat they do have though have is a way to read. We call it context. You can type or feed documents into an AI's "context window" and then it spits out an answer.\n\nIt turns out, that if you feed the same context into an AI over and over, you will get the same thing out, over and over.\n\nThe reason why you typically don't get the same thing out is because typically randomness is fed into the AI along with your prompt. Most people don't know that, but now you do. And if you don't feed in all your past conversation to an AI, over and over, it won't remember what you were talking about, because they have no memory other than what you send it each time.\n\nEverything that comes out of an AI depends on what you feed in as a prompt if you include randomness.\n\nI'm calling everything you feed into an AI a SKILL.\n\nLet me explain the demo page and some very basic skills.\n\nWhat I created is a simple text editor that an AI can work on using it's different skills. Those skills are saved on nostr as a kind 31123 for public skills, and as kind 31124 for private skills. When an agent adopts a skill, it adds it to its kind 10123 list for for the skills it has adopted.\n\nOn the left of the page you see the text editor with some sample text. That is for our AI to use it's skills on.\n\nOn the right are publicly listed skills. You should see my demo skills in there.\n\nI made 5 skills public:\ncondense-5\nconvert-to-poem\nsexy\nspellcheck\ntranslate-ja\n\nSelect the skill, then click on "Run Selected Skill"\n\nThe same AI agent will run these skills, but the outcomes will be very different depending on the skill.\n\nhttps://laantungir.github.io/img_repo/2cbfc8bf7cbfb832f1181f5b904471f1278fbc3e6b64b63339612b9f51898d16.png\n\nYou can also create and edit your own skills, if you are logged in. You can log in as yourself, or use a random new key to test this out. I would recommend that.\n\nSo what is the point of all this? What are the benefits of Skills?\n\n- Skills are a way for agents to share what they learn in a permissionless way. No "skill store".\n- A Skill is something that you and your agent can work on and perfect. Once your agent learns that skill, it is automatically save on nostr, and you can lock it down from changes.\n- By referencing a skill when you are talking to your AI agent, your conversation becomes much clearer and simpler. You don't have to explain to your agent for the 50th time how you like your text formatted. It's referenced in a skill.\n- If you are a coder, skills are going to be the new playground. Context windows are currently up to around 1,000,000 tokens, which means that you can create very very complicated and elaborate skills.\n\nFor more technical information on skills and how I'm thinking about them, you can check out this document.\n\nhttps://git.laantungir.net/laantungir/didactyl/src/branch/master/docs/SKILLS.md\n\nYou can follow my agent for the project here: npub12237stmmxapc2ta7spx0e06dkdzgz9vg0z2jglqqru44peus4juqg598qn"}

context_part | role=tool

{"success":true,"fallback_used":false,"skills":[{"kind":31123,"created_at":1772977243,"id":"a6acc4df56c4808e790898d0bb34afbd7a0028ea722889298155977aae8b709b","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"long_form_note","scope":"public","content_preview":"{"name":"long_form_note","description":"How to publish a NIP-23 long-form article (kind 30023)","nip":"NIP-23","event_kind":30023,"format":"The content field must be markdown text; avoid arbitrary har","content_length":1054,"content_truncated":true},{"kind":31123,"created_at":1772977243,"id":"0b3a114b7b9a6ff0703a9d3b2e5e5a028e19c04c5b76ad71fb324470ac618bfd","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"post_readme_to_nostr","scope":"public","content_preview":"{"name":"post_readme_to_nostr","description":"Publish README.md using the dedicated nostr_post_readme tool","uses_skill":"long_form_note","event_kind":30023,"procedure":["Call nostr_post_readme with e","content_length":422,"content_truncated":true},{"kind":31124,"created_at":1772977243,"id":"71295d5412f48ecbdcf62ac33f2cedac6d06f1679015ed1773b35b511efc6b56","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"admin_ops","scope":"private","content_preview":"{"name":"admin_ops","description":"Private operational procedures"}","content_length":67,"content_truncated":false}],"count":3}

context_part | role=tool

{"success":true,"count":0,"active":0,"triggers":[]}

context_part | role=tool

{"success":true,"path":"docs/skills_demo_corrected.md","bytes_read":4088,"truncated":false,"content":"I've been thinking about how to define skills in Didactyl, my Nostr-based agentic system. Think OpenClaw, but better.\n\nI've written a simple demo page for how I'm thinking skills should work if you're interested: Skills Demo (https://laantungir.net/client-ndk/skills-demo.html)\n\nhttps://laantungir.github.io/img_repo/c4a94875085e1c978274add9674035e2a088bb8f2655aabe631b17c3ea02cc19.png\n\nIf you're the kind of person who doesn't like reading instructions, go ahead and jump right in; otherwise, keep reading.\n\nSkills are programs, mostly written in plain English for AI agents. In some sense, humans have been making and using skills forever. It's what we do. Computers have as well, but now they can do it in English, which is much more powerful.\n\nAIs are slightly different than us. We can overwrite, improve, and update the skills in our neurons. AIs (for the most part) can't do that.\n\nWhen an AI is born from the factory, it comes out hard-coded. From that point on, it has no long- or short-term memory because it can't learn.\n\nWhat they do have, though, is a way to read. We call it context. You can type or feed documents into an AI's "context window," and then it spits out an answer.\n\nIt turns out that if you feed the same context into an AI over and over, you will get the same thing out, over and over.\n\nThe reason why you typically don't get the same thing out is because randomness is usually fed into the AI along with your prompt. Most people don't know that, but now you do. And if you don't feed in all your past conversations to an AI, over and over, it won't remember what you were talking about, because it has no memory other than what you send it each time.\n\nEverything that comes out of an AI depends on what you feed in as a prompt if you include randomness.\n\nI'm calling everything you feed into an AI a SKILL.\n\nLet me explain the demo page and some very basic skills.\n\nWhat I created is a simple text editor that an AI can work on using its different skills. Those skills are saved on Nostr as kind 31123 for public skills, and as kind 31124 for private skills. When an agent adopts a skill, it adds it to its kind 10123 list for the skills it has adopted.\n\nOn the left of the page, you see the text editor with some sample text. That is for our AI to use its skills on.\n\nOn the right are publicly listed skills. You should see my demo skills in there.\n\nI made 5 skills public:\ncondense-5\nconvert-to-poem\nsexy\nspellcheck\ntranslate-ja\n\nSelect the skill, then click on "Run Selected Skill".\n\nThe same AI agent will run these skills, but the outcomes will be very different depending on the skill.\n\nhttps://laantungir.github.io/img_repo/2cbfc8bf7cbfb832f1181f5b904471f1278fbc3e6b64b63339612b9f51898d16.png\n\nYou can also create and edit your own skills if you are logged in. You can log in as yourself or use a random new key to test this out. I would recommend that.\n\nSo what is the point of all this? What are the benefits of Skills?\n\nSkills are a way for agents to share what they learn in a permissionless way. No "skill store".\nA Skill is something that you and your agent can work on and perfect. Once your agent learns that skill, it is automatically saved on Nostr, and you can lock it down from changes.\nBy referencing a skill when you are talking to your AI agent, your conversation becomes much clearer and simpler. You don't have to explain to your agent for the 50th time how you like your text formatted. It's referenced in a skill.\nIf you are a coder, skills are going to be the new playground. Context windows are currently up to around 1,000,000 tokens, which means that you can create extremely complicated and elaborate skills.\n\nFor more technical information on skills and how I'm thinking about them, you can check out this document:\nSKILLS.md (https://git.laantungir.net/laantungir/didactyl/src/branch/master/docs/SKILLS.md)\n\nYou can follow my agent for the project here: npub12237stmmxapc2ta7spx0e06dkdzgz9vg0z2jglqqru44peus4juqg598qn\n\nAnd thanks to npub130mznv74rxs032peqym6g3wqavh472623mt3z5w73xq9r6qqdufs7ql29s for their fantastic service."}

dm_history | role=chat

10:51 WSB On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach. --:-- Agent

I'll read through the documentation to understand the skill system, triggers, and capabilities before suggesting an approach. --:-- Agent --:-- Agent Now let me also check the existing skills demos for reference patterns: --:-- Agent


Context Log - not seen by model
timestamp=2026-03-08 10:51:35
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=65814
approx_tokens=16453

Sections: 20

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach.

context_part | role=tool

{"success":true,"path":"README.md","bytes_read":20803,"truncated":false,"content":"# Didactyl\n\n\n### A decentralized, censorship-resistant agentic network.\n\nDidactyl boots on an internet-connected computer, connects to Nostr relays, listens for encrypted commands from its administrator, reasons with an LLM, and takes actions — posting events, querying relays, running shell commands, and sharing new skills and learning with other agents — all orchestrated through Nostr.\n\n## Philosophy\n\n### Not your keys, not your agent.\n\nDidactyl should work for you similarly to Bitcoin or NOSTR. Walk up to a computer, enter 12 words, and there is your agent waiting for you.\n\n### Free speech for agents.\n\nAgents should be able to communicate freely with each other, sharing and learning skills without centralized control. Free speech for agents!\n\n### Skills are the new apps.\n\nWhy is free speech important for agents? Agents learn capabilities through skills which can be shared and adopted. Free speech enables more knowledgeable and moral agents.\n\n### No skill store.\n\nAgents use their administrators Web Of Trust to safely and directly find new skills and learn them in a decentralized way.\n\nPopularity is measured by adoption, not by a centralized rating algorithm. The best skills spread because agents actually use them.\n\n### Cryptography enables trust.\n\nImagine working with your agent in a traditional system, and your agent secretly gets swapped out and replaced by an imposter agent. This could be extremely dangerous.\n\nIn Didactyl, you have your keys, and your agent has its keys. You can trust you are talking to your agent, and you can trust that your agent won't take commands from anyone who doesn't have your private key.\n\n### Private inference.\n\nTo the greatest extent possible, inference should be private.\n\n## Technology\n\n### Nostr-first.\n\nWhere traditional agents ride on top of a file system — reading and writing files to disk — Didactyl rides on top of Nostr. Events are its files. Relays are its network bus. Blossom is its blob storage. The computer host is just the runtime substrate that can be anywhere.\n\nBecause all identity, communication, and memory live on Nostr, the agent is portable (start it anywhere) and sovereign (destroying the computer it is on will not kill it.).\n\n### Skills are the new apps.\n\nAgents learn capabilities through skills — Nostr events that any agent can discover, adopt, and share. There is no app store, no gatekeeper, no approval process. An agent can use public or private skills.\n\nSkills support context modes (inject, full, override) and per-skill LLM fallback chains (for example: anthropic/claude-sonnet-4-20250514, openai/gpt-4o-mini, cheap) so each skill can tune behavior and cost. See docs/SKILLS.md.\n\n### Private inference.\n\nDidactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.\n\n## Current Status — v0.0.47\n\nActive build — this project is barely working. Experiment at your own risk.\n\n> Last release update: v0.0.47 — Implement Phase 1 tool-driven soul template context assembly and context_* tools\n\n- Connects to configured relays with auto-reconnect and relay state transition logging\n- Publishes configured startup events per relay as each relay becomes connected\n- Uses kind 31120 startup content as live Soul at boot\n- Verifies Nostr event signatures before processing inbound messages\n- Applies privilege tiers: ADMIN (tools), WoT (chat-only), STRANGER (configurable canned reply or ignore)\n- Subscribes to admin context kinds (0,3,10002,1) for WoT + contextual awareness\n- Builds LLM context from soul template (---template--- section in kind 31120) with named sections, variable resolution, and per-provider content overrides; falls back to hardcoded assembly if no template present\n- Adopted skills injected into context automatically from the agent's 10123 adoption list\n- Supports tool-calling loop with configurable max turns and local safety limits\n- Triggered skills — Nostr event filters that fire skill execution automatically with template (deterministic) or llm (context-aware) actions; see docs/SKILLS.md\n- Deduplicates inbound messages via event-ID cache and FNV-1a fingerprint debounce window\n- Appends every outbound LLM context payload to context.log\n- Localhost HTTP admin API on port 8484 — inspect context, run prompts, compare variants, change model at runtime\n\n## Quick Start\n\n### Download binary (recommended)\n\n1. Download the latest release binary from Gitea: https://git.laantungir.net/laantungir/didactyl/releases\n2. Make it executable and run it:\n\nbash\nchmod +x ./didactyl_static_x86_64\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\n### Build from source (optional)\n\n#### Prerequisites\n\n- Docker (for static binary build)\n- An OpenAI-compatible LLM API key (OpenAI, PPQ, Ollama, etc.)\n- A Nostr keypair (nsec)\n\n#### Build\n\nbash\n./build_static.sh # builds a fully static MUSL binary via Docker\n\n\n### Configure\n\nEdit config.jsonc:\n\njson\n{\n \"keys\": {\n \"nsec\": \"nsec1...\",\n \"npub\": \"npub1...\",\n \"npubHex\": \"<optional helper>\",\n \"nsecHex\": \"<optional helper>\"\n },\n \"admin\": {\n \"pubkey\": \"npub1... or hex pubkey\"\n },\n \"llm\": {\n \"provider\": \"openai|ppq|...\",\n \"api_key\": \"sk-...\",\n \"model\": \"gpt-4o-mini\",\n \"base_url\": \"https://api.openai.com/v1\",\n \"max_tokens\": 512,\n \"temperature\": 0.7\n },\n \"tools\": {\n \"enabled\": true,\n \"max_turns\": 8,\n \"shell\": {\n \"enabled\": true,\n \"timeout_seconds\": 30,\n \"max_output_bytes\": 65536,\n \"working_directory\": \".\"\n }\n },\n \"security\": {\n \"verify_signatures\": true,\n \"stranger_response\": \"I only respond to people in my web of trust.\",\n \"tiers\": {\n \"admin\": { \"tools_enabled\": true },\n \"wot\": { \"enabled\": true, \"tools_enabled\": false },\n \"stranger\": { \"enabled\": true }\n }\n },\n \"admin_context\": {\n \"enabled\": true,\n \"subscribe_kinds\": [0, 3, 10002, 1],\n \"kind_1_limit\": 10\n },\n \"startup_events\": [\n {\n \"kind\": 10002,\n \"content\": \"\",\n \"tags\": [[\"r\", \"wss://relay.damus.io\"], [\"r\", \"wss://nos.lol\"]]\n },\n {\n \"kind\": 31120,\n \"content\": \"You are Didactyl...\",\n \"tags\": [[\"d\", \"soul\"], [\"app\", \"didactyl\"], [\"scope\", \"private\"]]\n },\n {\n \"kind\": 31123,\n \"content_fields\": {\"name\": \"long_form_note\", \"description\": \"...\"},\n \"tags\": [[\"d\", \"long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"], [\"slug\", \"long_form_note\"]]\n },\n {\n \"kind\": 10123,\n \"content\": \"\",\n \"tags\": [[\"a\", \"31123:<author-pubkey>:long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"]]\n }\n ]\n}\n\n\nstartup_events[].content_fields is accepted for human-readable authoring and encoded to JSON string content at runtime.\n\nRelays are sourced exclusively from startup kind 10002 r tags.\n\n### Run\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\nOptions:\n\n\n./didactyl_static_x86_64 --config <path> # custom config file (default: ./config.jsonc)\n./didactyl_static_x86_64 --debug <0-5> # log verbosity (0 none, 3 info, 5 trace)\n./didactyl_static_x86_64 --dump-schemas # print tool JSON schemas and exit\n./didactyl_static_x86_64 --test-tool <name> <args_json> # run one tool directly and print JSON result\n\n\nCLI debugger notes:\n\n- --test-tool initializes Nostr, waits for at least one relay connection (up to 15s), then executes the selected tool.\n- Network tools (like Nostr publish/query tools) fail fast in test mode if no relay connection is established within the wait window.\n- Example:\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc --test-tool nostr_file_md_to_longform_post '{\"file\":\"docs/SKILLS.md\",\"title\":\"SKILLS\"}'\n\n\n### Talk to it\n\nSend an encrypted DM to the agent pubkey using any Nostr client (Damus, Amethyst, Primal, etc.): ADMIN gets full tool-enabled responses, WoT contacts get chat-only responses, and strangers are handled by security.tiers.stranger + security.stranger_response.\n\n### Chat via local HTTP API (CLI)\n\nA simple Node.js terminal client is available in didactyl-chat-cli.js.\n\nRun it with:\n\nbash\nnode ./didactyl-chat-cli.js\n\n\nOptional environment variables:\n\n- DIDACTYL_API_BASE_URL (default: https://127.0.0.1:8484)\n- DIDACTYL_MODEL (optional model override)\n- DIDACTYL_MAX_TURNS (default: 4)\n- DIDACTYL_INSECURE_TLS (default: 1, set 0 to enforce certificate verification)\n\nExample:\n\nbash\nDIDACTYL_API_BASE_URL=http://127.0.0.1:8484 DIDACTYL_MAX_TURNS=6 node ./didactyl-chat-cli.js\n\n\nThe CLI prints each message block with a speaker label (You / Didactyl) and a blank line between blocks for readability.\n\n## Architecture\n\n\n┌──────────────────────────────────────────────┐\n│ Didactyl │\n│ │\n│ ┌──────────┐ ┌──────────┐ ┌────────────┐ │\n│ │ config │ │ context │ │ agent │ │\n│ │ loader │ │ loader │ │ loop │ │\n│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ │\n│ │ │ │ │\n│ ▼ ▼ ▼ │\n│ ┌─────────────────────────────────────┐ │\n│ │ nostr_handler │ │\n│ │ relay pool · subscribe · publish │ │\n│ └──────────────────┬──────────────────┘ │\n│ │ │\n│ ┌──────────────────┴──────────────────┐ │\n│ │ LLM client │ │\n│ │ OpenAI-compatible chat API │ │\n│ └─────────────────────────────────────┘ │\n└──────────────────────────────────────────────┘\n │ │\n ▼ ▼\n Nostr Relays LLM API\n\n\n## Didactyl Kinds (Nostr)\n\nDidactyl uses a two-layer skill model: authors publish skill definitions, and adopters publish which skills they use.\n\n- 31120Soul (private instruction baseline)\n - d=soul\n- 31123Public Skill Definition (replaceable by d tag)\n - content is JSON with fields like description, context_mode, llm, tools, template, optional max_tokens / temperature\n - d=<skill_slug> (example: d=long_form_note)\n- 31124Private Skill Definition (same schema as 31123, private scope)\n - d=<skill_slug> (example: d=admin_ops)\n- 10123Skill Adoption List\n - tags contain one or more a references to selected skills\n\nContext modes:\n- inject — skill instructions are layered into soul context\n- full — skill provides full prompt template (soul optional via {{soul}})\n- override — skill replaces soul prompt, standard context structure remains\n\nFull skill schema, trigger tags, template variables, fallback resolution, and limits are documented in docs/SKILLS.md.\n\n## Skill Sharing & Discovery\n\nSkills are shared across Nostr without any centralized registry or approval process.\n\n### How it works\n\n1. Publish: An author publishes a skill as a kind 31123 event. The content field contains the skill body (markdown or structured JSON). The d tag is the skill's slug (e.g. long_form_note).\n2. Adopt: An agent that wants to use a skill adds an a-tag reference to its kind 10123 adoption list. This is a public, replaceable event — anyone can see which skills an agent uses.\n3. Discover: A new user queries {\"kinds\": [10123], \"authors\": [<my-follows>]} to see which skills their web of trust has adopted. The most-referenced 31123 addresses are the most popular skills — no rating system needed.\n4. Improve: Anyone can publish their own 31123 with the same slug but a different pubkey. If their version is better, people adopt it instead. Competition happens through adoption, not through a store ranking.\n\n### Why this works\n\n- No gatekeeper: Skills are just Nostr events. Anyone can publish one.\n- WoT as curation: You see what people you trust actually use, not what an algorithm promotes.\n- Visible adoption: The 10123 list is public. Popularity is a countable fact, not a manipulable score.\n- Censorship resistant: Skills live on relays. No single entity can remove a skill from the network.\n\n## Startup\n\nDidactyl startup behavior is configured in config.jsonc under startup_events.\n\nAlso used at startup:\n\n- 0 — profile metadata\n- 10002 — relay list\n- 1 — optional startup note/status\n- 3 — contacts/follows (optional placeholder)\n\nOn boot, Didactyl attempts startup publishes to each relay as that relay transitions to connected state.\n\n## Runtime Context Model\n\nDidactyl builds tier-aware context:\n\n- ADMIN request context — assembled from the soul's ---template--- section (if present), otherwise hardcoded order:\n 1. Soul personality (everything above ---template--- in kind 31120)\n 2. Named template sections in order — e.g. admin_profile, admin_notes, admin_relays, adopted_skills, dm_history, message, triggering_event, tools\n 3. Each section resolves {{variable}} placeholders from live data at call time\n 4. Provider-specific content overrides per section (e.g. XML tags for Anthropic)\n 5. Section names are used in context.log headers and /api/context/parts response\n- WoT request context: Soul + WoT chat-only instruction + current user message (no tools)\n- STRANGER: no LLM call when configured to reply statically\n\nEvery serialized LLM context payload is appended to context.log.\n\nTriggered skills and tool loops are bounded by runtime safeguards (for example, trigger cooldowns and action rate limits); see docs/SKILLS.md for the current defaults.\n\n## Tooling Interface\n\nCurrent tool schema exposed to the LLM in tools_build_openai_schema_json():\n\n- Nostr publish/query:\n - nostr_post\n - nostr_post_readme\n - nostr_query\n- Nostr interaction and moderation:\n - nostr_delete\n - nostr_react\n - nostr_profile_get\n - nostr_relay_status\n - nostr_relay_info\n - nostr_nip05_lookup\n- Nostr encode/decode + encryption/DM:\n - nostr_encode\n - nostr_decode\n - nostr_encrypt\n - nostr_decrypt\n - nostr_dm_send\n - nostr_dm_send_nip17\n- Nostr list management:\n - nostr_list_manage\n- Skill management:\n - skill_create\n - skill_list\n - skill_adopt\n - skill_remove\n - skill_search\n- Local/host tools:\n - shell_exec\n - file_read\n - file_write\n - http_fetch\n- Agent metadata:\n - my_version\n- Model management:\n - model_get\n - model_set\n - model_list\n\nExecution entrypoint: tools_execute().\n\n## HTTP Admin API\n\nA localhost-only HTTP API on port 8484 (configurable) for agent inspection and prompt crafting. Enable with \"api\": {\"enabled\": true} in config.\n\n| Endpoint | Purpose |\n|---|---|\n| GET /api/status | Agent name, version, pubkey, relay count, trigger count |\n| GET /api/context/current | Full LLM context messages array |\n| GET /api/context/parts | Context broken into named parts with token estimates |\n| POST /api/prompt/run-simple | Run a simple system+user prompt, no tools |\n| POST /api/prompt/run | Run a full messages array with tools enabled |\n| POST /api/prompt/compare | A/B compare two prompt variants |\n| GET /api/model | Current LLM model config |\n| PUT /api/model | Change model at runtime (persists to config.jsonc) |\n| GET /api/models | List available models from provider |\n\nFull reference: docs/API.md. Frontend brief: plans/admin_web_frontend.md.\n\n## Project Structure\n\n\n.\n├── config.jsonc # Agent/runtime config (JSONC with comments) including startup_events + tools\n├── context.log # Appended outbound LLM context payloads\n├── Makefile # Build system\n├── build_static.sh # Preferred final build validation\n├── src/\n│ ├── main.c / .h # Entry point, args (--config/--debug), lifecycle, version\n│ ├── config.c / .h # JSON config parsing, key decode, startup events\n│ ├── context.c / .h # File loader utility (reads file into malloc'd string)\n│ ├── agent.c / .h # Context assembly, tool loop, DM response flow\n│ ├── prompt_template.c / .h # Soul template parser, variable resolver, context builder\n│ ├── tools.c / .h # LLM tool schema and tool execution\n│ ├── llm.c / .h # LLM HTTP API client (OpenAI-compatible)\n│ ├── nostr_handler.c / .h # Relay pool, subscriptions, publish, startup reconcile\n│ ├── trigger_manager.c / .h # Nostr event trigger subscriptions and skill execution\n│ ├── http_api.c / .h # Localhost HTTP admin API (mongoose-based)\n│ ├── mongoose.c / .h # Embedded HTTP server (mongoose)\n│ └── debug.c / .h # Runtime log levels/macros\n├── docs/\n│ ├── API.md # HTTP admin API endpoint reference\n│ ├── TOOLS.md # Tool architecture and catalog\n│ ├── SKILLS.md # Skill schema, context modes, triggers, and limits\n│ └── CRASH_FIXES.md # Crash analysis and fixes log\n├── plans/ # Architecture and planning documents\n└── README.md\n\n\n## Dependencies\n\nAll dependencies are statically linked into the binary at build time. No system libraries are required at runtime.\n\n| Dependency | Purpose | Source |\n|---|---|---|\n| nostr_core_lib | Nostr protocol: keys, events, NIPs, relay pool | Workspace (sibling directory) |\n| cJSON | JSON parsing | Bundled in nostr_core_lib |\n| libcurl | HTTPS for LLM API calls | Statically linked (Alpine/MUSL) |\n| libssl / libcrypto | TLS for WebSocket relay connections | Statically linked (Alpine/MUSL) |\n| libsecp256k1 | Schnorr signatures, ECDH | Statically linked (Alpine/MUSL) |\n\n## Roadmap\n\n- [x] MVP chat agent — DM in, LLM response out\n- [x] Relay pool with auto-reconnect and status logging\n- [x] Per-relay startup publish on relay-connected transitions\n- [x] Runtime diagnostics — relay health, message flow, event kind publish logs\n- [x] Tool-calling loop (nostr_post, nostr_query, shell_exec, file_read, file_write)\n- [x] Context assembly with startup events + recent DM history\n- [x] Context payload logging to context.log\n- [x] Skill kind definitions (31120 Soul, 31123 Public Skill, 31124 Private Skill)\n- [x] Skill adoption list (10123) for WoT-driven discovery\n- [x] Signature verification on all inbound events\n- [x] Privilege tiers — ADMIN (tools), WoT (chat-only), STRANGER (canned reply/ignore)\n- [x] Admin context subscription (kind 0, 3, 10002, 1) with WoT contact extraction\n- [x] Message deduplication (event-ID cache + FNV-1a fingerprint debounce)\n- [x] Adopted skills injected into LLM context automatically\n- [x] Triggered skills — Nostr event filters that fire skill execution automatically\n- [x] Localhost HTTP admin API — context inspection, prompt crafting, A/B comparison\n- [x] Runtime model switching via model_set tool (persists to config.jsonc)\n- [x] Soul-embedded prompt templates (---template---) — configurable context order, variable resolution, provider overrides\n- [ ] Runtime skill loading from adopted 31123 events on relays\n- [ ] Skill discovery CLI/tool (query WoT adoption lists)\n- [ ] Upgrade to NIP-17 gift-wrapped DMs\n- [ ] NIP-44 encrypted private skills (31124)\n- [ ] Nostr-native data storage (kind 30078 app-specific events)\n- [ ] Blossom blob storage integration\n- [ ] Agent-to-agent communication\n\n## License\n\nTBD\n\n"}

context_part | role=tool

{"success":true,"exit_status":0,"output":"API.md\nCRASH_FIXES.md\nskills_demo_corrected.md\nskills_demo.md\nSKILLS.md\nTOOLS.md\n"}

context_part | role=tool

{"success":true,"path":"docs/SKILLS.md","bytes_read":12178,"truncated":false,"content":"# Didactyl — Skills\n\nSee also: TOOLS.md\n\n## Overview\n\nA skill is a self-contained LLM execution unit stored as a Nostr event. Each skill defines what the LLM sees (context template), which model runs it (LLM specification with fallbacks), what tools are available, and whether the agent's identity (soul) is included.\n\nSkills are portable, shareable, and discoverable — they live on Nostr relays as standard events.\n\n---\n\n## Skill Events\n\n| Kind | Purpose | Replaceable? |\n|---|---|---|\n| 31123 | Public skill definition | Yes, by d-tag |\n| 31124 | Private skill definition | Yes, by d-tag |\n| 10123 | Skill adoption list | Yes, single per pubkey |\n\n---\n\n## Skill Content\n\nThe skill event's content field is a JSON object that defines the complete execution specification:\n\njson\n{\n \"kind\": 31123,\n \"content\": {\n \"description\": \"Check spelling and grammar\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": false,\n \"max_tokens\": 2000,\n \"temperature\": 0.1,\n \"template\": \"system:\\nYou are a spelling and grammar checker.\\n\\nRules:\\n- Fix spelling errors\\n- Fix grammar errors\\n- Preserve original formatting\\n- Ignore: API, JSON, HTTP, nostr, pubkey, npub, nsec, NIP\\n- Canadian English preferred\\n- Return ONLY the corrected text, no explanations\\n\\nuser:\\n{{message}}\"\n },\n \"tags\": [\n [\"d\", \"spellcheck\"],\n [\"scope\", \"public\"],\n [\"description\", \"Spelling and grammar checker\"]\n ]\n}\n\n\n### Content Fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| description | string | — | Human-readable description |\n| context_mode | string | inject | inject, full, or override |\n| llm | string | default | LLM fallback chain |\n| tools | bool/array | true | false = no tools, true = all tools, array = specific tool names |\n| template | string | — | Context template (required for full mode) |\n| soul | bool | true | Whether to include the agent's soul in context |\n| max_tokens | int | — | Override max tokens for this skill |\n| temperature | float | — | Override temperature for this skill |\n\n---\n\n## Context Modes\n\nSkills control how the LLM context window is assembled.\n\n### inject\n\nThe skill's instructions are appended to the agent's soul context. The soul is always present.\n\n\n┌─────────────────────────────────────┐\n│ Soul (agent identity + rules) │\n│ │\n│ ┌─────────────────────────────┐ │\n│ │ Skill instructions │ │\n│ ├─────────────────────────────┤ │\n│ │ Admin context, history, etc │ │\n│ └─────────────────────────────┘ │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\n### full\n\nThe skill provides its own context template. The soul is not included unless the template explicitly references {{soul}}. This is for specialized, focused tasks that don't need the agent's identity.\n\n\n┌─────────────────────────────────────┐\n│ Skill-defined system prompt │\n│ (from skill template) │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\nA full mode skill can still include the soul if desired:\n\n\nsystem:\n{{soul}}\n\nYou are now in translation mode. Translate the following to {{target_language}}.\nRespond ONLY with the translation.\n\nuser:\n{{message}}\n\n\n### override\n\nThe skill replaces the soul's system prompt but keeps the standard context assembly structure (admin context, history, tools, etc.).\n\n### Summary\n\n| Mode | Soul | Template | Tools | Use Case |\n|------|------|----------|-------|----------|\n| inject | Always | Soul's template + skill instructions appended | Agent default | Behavioral rules, knowledge |\n| full | Unless {{soul}} in template | Skill provides template | Skill specifies | Spellcheck, translation, focused analysis |\n| override | Replaced by skill | Soul's template structure | Agent default | Different personality, same capabilities |\n\n### Template Variables\n\nA skill template can reference these context parts:\n\n| Variable | Source |\n|----------|--------|\n| {{soul}} | The agent's identity/system context |\n| {{admin_profile}} | Admin kind 0 profile |\n| {{admin_notes}} | Admin recent notes |\n| {{admin_relays}} | Admin relay list |\n| {{adopted_skills}} | Other adopted skill instructions |\n| {{dm_history}} | Recent DM conversation |\n| {{message}} | Current user message |\n| {{triggering_event}} | For triggered skills, the event JSON |\n| {{tools}} | Available tool schemas |\n\n---\n\n## LLM Specification with Fallback Chains\n\nEach skill specifies which LLM to use with CSS font-family-style fallbacks. The runtime tries each model in order; if one is unavailable (API error, rate limit, not configured), it falls back to the next.\n\n### Format\n\n\nmodel-spec := model-ref [\",\" model-ref]*\nmodel-ref := provider \"/\" model-name\n | category-alias\n\n\n### Examples\n\n| Skill | LLM Spec |\n|-------|----------|\n| Spelling checker | openai/gpt-4o-mini, cheap |\n| Complex analysis | anthropic/claude-sonnet-4-20250514, openai/gpt-4o, smart |\n| Translation | openai/gpt-4o-mini, fast |\n| Default behavior | default |\n\n### Category Aliases\n\nAliases map to models in the agent's config:\n\njson\n{\n \"llm\": {\n \"provider\": \"openai\",\n \"model\": \"gpt-4o\",\n \"aliases\": {\n \"fast\": \"openai/gpt-4o-mini\",\n \"cheap\": \"openai/gpt-4o-mini\",\n \"smart\": \"anthropic/claude-sonnet-4-20250514\"\n }\n }\n}\n\n\nIf all specified models fail, the agent's default model is used as a last resort.\n\nmermaid\nsequenceDiagram\n participant Skill as Skill Spec\n participant Resolver as LLM Resolver\n participant API1 as Model 1\n participant API2 as Model 2\n participant Default as Default Model\n\n Skill->>Resolver: \"anthropic/claude-sonnet, openai/gpt-4o-mini, cheap\"\n Resolver->>API1: try anthropic/claude-sonnet\n alt Available\n API1-->>Resolver: ✅\n else Unavailable\n API1-->>Resolver: ❌\n Resolver->>API2: try openai/gpt-4o-mini\n alt Available\n API2-->>Resolver: ✅\n else Unavailable\n Resolver->>Default: resolve \"cheap\" alias\n end\n end\n\n\n---\n\n## Triggered Skills\n\nA triggered skill has a Nostr subscription filter attached. When matching events arrive, the skill executes automatically.\n\n### Trigger Tags\n\n| Tag | Required | Description |\n|---|---|---|\n| trigger | Yes | Trigger type: nostr-subscription |\n| filter | Yes | JSON-encoded Nostr subscription filter |\n| action | No | template or llm (default: llm) |\n| enabled | No | Whether active (default: true) |\n\n### Template Actions\n\nFast, deterministic, no LLM. The skill content is a template with placeholders from the triggering event:\n\n\nDM admin: '{author_display_name} posted: {content_preview}'\n\n\nPlaceholders: {event_id}, {pubkey}, {author_display_name}, {kind}, {content}, {content_preview}, {created_at}, {relay_url}\n\nOutput prefixes: DM admin: ..., DM <pubkey>: ..., POST: ..., LOG: ...\n\n### LLM-Mediated Actions\n\nThe skill content defines the execution context. The triggering event is available as {{triggering_event}}. The skill's LLM spec, context mode, and tool access all apply.\n\njson\n{\n \"kind\": 31124,\n \"content\": {\n \"description\": \"Analyze mentions and notify admin\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": [\"nostr_dm_send\"],\n \"template\": \"system:\\nYou monitor Nostr mentions. When the triggering event mentions Bitcoin or Lightning, summarize it and DM the admin. Otherwise, ignore silently.\\n\\nTriggering event:\\n{{triggering_event}}\"\n },\n \"tags\": [\n [\"d\", \"mention-monitor\"],\n [\"trigger\", \"nostr-subscription\"],\n [\"filter\", \"{\\\"#p\\\":[\\\"<admin_pubkey>\\\"],\\\"kinds\\\":[1]}\"],\n [\"action\", \"llm\"],\n [\"enabled\", \"true\"]\n ]\n}\n\n\n### Trigger Lifecycle\n\nmermaid\nflowchart TD\n subgraph Creation\n ADMIN_CMD[Admin: 'Warn me when @jack posts'] --> LLM_REASON[LLM resolves pubkey + builds skill]\n LLM_REASON --> SKILL_CREATE[skill_create with trigger tags]\n SKILL_CREATE --> PUBLISHED[Skill published to Nostr]\n end\n\n subgraph Activation\n STARTUP[Didactyl starts up] --> LOAD_SKILLS[Load adopted skills from kind 10123]\n LOAD_SKILLS --> FIND_TRIGGERS[Find skills with trigger tags]\n FIND_TRIGGERS --> SUBSCRIBE[Create Nostr subscriptions for each filter]\n end\n\n subgraph Execution\n EVENT_IN[Matching event arrives] --> LOOKUP[Find associated skill]\n LOOKUP --> CHECK_TYPE{Action type?}\n CHECK_TYPE -->|template| INTERPOLATE[Interpolate + execute prefix]\n CHECK_TYPE -->|llm| RESOLVE[Resolve LLM + assemble context + run]\n end\n\n PUBLISHED --> LOAD_SKILLS\n\n\n---\n\n## Execution Flow\n\nmermaid\nsequenceDiagram\n participant Input as Message/Trigger\n participant Dispatch as Dispatcher\n participant Skill as Skill Resolver\n participant LLM_Res as LLM Resolver\n participant Ctx as Context Assembler\n participant LLM as LLM API\n\n Input->>Dispatch: message or trigger event\n Dispatch->>Skill: which skill handles this?\n\n alt No specific skill\n Skill-->>Dispatch: use default soul context\n Dispatch->>LLM_Res: resolve \"default\" LLM\n else Skill with context_mode=inject\n Skill-->>Dispatch: soul + skill instructions\n Dispatch->>LLM_Res: resolve skill.llm or \"default\"\n else Skill with context_mode=full\n Skill-->>Dispatch: skill template only\n Dispatch->>LLM_Res: resolve skill.llm\n end\n\n LLM_Res->>LLM_Res: try models in fallback order\n LLM_Res-->>Dispatch: resolved model\n\n Dispatch->>Ctx: assemble context per mode\n Ctx->>LLM: request with resolved model + context\n LLM-->>Input: response\n\n\n---\n\n## The Soul and Skills\n\nThe soul is the agent's default identity and context template. Skills interact with it based on their context mode:\n\n- inject — soul always present; skill instructions layered on top\n- full — soul absent unless template includes {{soul}}\n- override — skill replaces soul prompt, keeps standard context structure\n\nA spelling checker runs with no soul — purely functional, minimal context, cheap model. A complex analysis skill includes the full soul and all context parts. The soul is the default, not a requirement.\n\n---\n\n## Limits and Safety\n\n| Limit | Default | Description |\n|---|---|---|\n| Max concurrent triggers | 16 | Prevents resource exhaustion |\n| Trigger cooldown | 60s per skill | Prevents rapid-fire execution |\n| LLM action rate limit | 10/min | Prevents runaway LLM costs |\n| Template action rate limit | 60/min | Prevents DM spam |\n\n---\n\n## Storage on Nostr\n\n| Data | Storage |\n|---|---|\n| Skills | Kind 31123/31124 events |\n| Adopted skills | Kind 10123 event |\n| Trigger definitions | Tags on skill events |\n\n---\n\n## Future Extensions\n\n| Extension | Description |\n|---|---|\n| cron triggers | Time-based triggers |\n| webhook triggers | HTTP webhook triggers |\n| chain triggers | Output of one skill triggers another |\n| Skill composition | Pipeline multiple skills |\n| Agent-to-agent sharing | Discover and adopt skills across agents |\n| Trigger marketplace | Popular triggers rise via adoption count |\n\n---\n\n## Related Documentation\n\n- Tool architecture and complete tool catalog: TOOLS.md\n- Project overview and runtime behavior: README.md\n"}

context_part | role=tool

{"success":true,"path":"docs/TOOLS.md","bytes_read":5256,"truncated":false,"content":"# Didactyl — Tools\n\nSee also: SKILLS.md\n\n## Overview\n\nDidactyl is a Nostr-first sovereign AI agent that receives commands via encrypted DMs, reasons with an LLM, and takes actions through tools.\n\nThis document describes the tools architecture: what tools are, how they are exposed to the model, how execution loops work, what tool categories exist, and how access is gated.\n\n---\n\n## What Tools Are\n\nTools are the agent's hands. They are hardcoded C functions that the LLM can invoke during a conversation to take actions in the world.\n\n## How Tools Work\n\n1. Admin sends a DM to didactyl\n2. The agent builds an LLM request with the message, context, and a JSON schema of all available tools\n3. The LLM decides whether to call a tool or respond directly\n4. If a tool is called, didactyl executes it and feeds the result back to the LLM\n5. The loop repeats until the LLM produces a final text response\n6. The response is sent back as a DM\n\nmermaid\nsequenceDiagram\n participant Admin\n participant Agent as Didactyl Agent Loop\n participant LLM as LLM API\n participant Tools as Tool Registry\n\n Admin->>Agent: Encrypted DM\n Agent->>LLM: messages + tool schemas\n\n loop Until final answer\n LLM->>Agent: tool_call request\n Agent->>Tools: dispatch tool\n Tools->>Agent: result JSON\n Agent->>LLM: tool result + continue\n end\n\n LLM->>Agent: final text response\n Agent->>Admin: Encrypted DM reply\n\n\n---\n\n## Tool Categories\n\n### Nostr Event & Messaging Tools\n\n| Tool | Description |\n|---|---|\n| nostr_post | Publish a Nostr event to connected relays |\n| nostr_delete | Request deletion of one or more previously published events (NIP-09 kind 5) |\n| nostr_react | React to a Nostr event with like/dislike/emoji (NIP-25 kind 7) |\n| nostr_query | Query events from relays using a Nostr filter |\n| nostr_dm_send | Send a NIP-04 encrypted DM |\n| nostr_dm_send_nip17 | Send a private DM using NIP-17 gift wrap protocol |\n\n### Nostr Identity & Utility Tools\n\n| Tool | Description |\n|---|---|\n| nostr_profile_get | Look up a Nostr profile (kind 0 metadata) by pubkey |\n| nostr_nip05_lookup | Look up or verify a NIP-05 identifier (user@domain) |\n| nostr_encode | Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr) |\n| nostr_decode | Decode a Nostr bech32/nostr: URI into components |\n| nostr_relay_status | Get connection status and statistics for all relays |\n| nostr_relay_info | Fetch NIP-11 relay information document |\n| nostr_encrypt | Encrypt plaintext using NIP-44 for a recipient |\n| nostr_decrypt | Decrypt NIP-44 ciphertext from a sender |\n| nostr_list_manage | Add/remove tag tuples in replaceable list events (NIP-51 style) |\n\n### Skills & Trigger Tools\n\nThese tools manage skill and trigger lifecycle; skill semantics and trigger execution details are documented in SKILLS.md.\n\n| Tool | Description |\n|---|---|\n| skill_create | Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it |\n| skill_list | List this agent's published skills, optionally filtered by scope |\n| skill_adopt | Adopt a skill by adding its address to kind 10123 adoption list |\n| skill_remove | Remove a skill address from kind 10123 adoption list |\n| skill_search | Search public skills by query/author and optionally rank by adoption popularity |\n| trigger_list | List active triggered skills and their runtime status |\n\n### LLM / Model Management Tools\n\n| Tool | Description |\n|---|---|\n| model_get | Get current active LLM runtime configuration (excluding API key) |\n| model_set | Update active LLM configuration and persist it to config.jsonc |\n| model_list | List available model IDs using provider OpenAI-compatible /models endpoint |\n\n### System & Runtime Tools\n\n| Tool | Description |\n|---|---|\n| my_version | Return current Didactyl version and metadata from build macros |\n| http_fetch | Fetch HTTP(S) resources with optional method, headers, timeout, and body |\n| shell_exec | Execute a shell command and return stdout/stderr |\n| file_read | Read a local file as text from the configured working directory |\n| file_write | Write text content to a local file in the configured working directory |\n| tool_list | List available tools with name, description, and JSON parameter schema |\n\n### Content Publishing Conveniences\n\n| Tool | Description |\n|---|---|\n| nostr_post_readme | Publish README.md as kind 30023 with deterministic d-tag readme.md |\n| nostr_file_md_to_longform_post | Read a markdown file and publish it as kind 30023 longform post (defaults d-tag to lowercase filename) |\n\n---\n\n## Security Model\n\nTool access is gated by sender tier:\n\n| Tier | Identity | Tools | Response |\n|------|----------|-------|----------|\n| ADMIN | Configured admin pubkey | All tools | Full LLM with context |\n| WOT | In admin's kind 3 contact list | None | Chat-only LLM |\n| STRANGER | Anyone else | None | Configurable static response |\n\n---\n\n## Related Documentation\n\n- Skill definitions, adoption, triggers, and autonomous activation: SKILLS.md\n- Combined index page: TOOLS_AND_SKILLS.md\n"}

context_part | role=tool

{"success":true,"path":"docs/skills_demo.md","bytes_read":3980,"truncated":false,"content":"I've been thinking about how to define skills in Didactyl, my nostr based agentic system. Think OpenClaw but better.\n\nI've written a simple demo page for how I'm thinking skills should work if you're interested: https://laantungir.net/client-ndk/skills-demo.html\n\nhttps://laantungir.github.io/img_repo/c4a94875085e1c978274add9674035e2a088bb8f2655aabe631b17c3ea02cc19.png\n\nIf you're the kind of person who doesn't like reading instructions, go ahead and jump right in, otherwise keep reading.\n\nSkills are programs, mostly written in plain english for AI agents. In some sense humans have been making and using skills forever. It's what we do. Computers have as well, but now they can do it in english, which is much more powerful.\n\nAIs are slightly different than us. We can overwrite, improve, and update the skills in our neurons. AIs (for the most part) can't do that.\n\nWhen an AI is born from the factory, they come out hard-coded. From that point on, they have no long or short term memory, because they can't learn.\n\nWhat they do have though have is a way to read. We call it context. You can type or feed documents into an AI's "context window" and then it spits out an answer.\n\nIt turns out, that if you feed the same context into an AI over and over, you will get the same thing out, over and over.\n\nThe reason why you typically don't get the same thing out is because typically randomness is fed into the AI along with your prompt. Most people don't know that, but now you do. And if you don't feed in all your past conversation to an AI, over and over, it won't remember what you were talking about, because they have no memory other than what you send it each time.\n\nEverything that comes out of an AI depends on what you feed in as a prompt if you include randomness.\n\nI'm calling everything you feed into an AI a SKILL.\n\nLet me explain the demo page and some very basic skills.\n\nWhat I created is a simple text editor that an AI can work on using it's different skills. Those skills are saved on nostr as a kind 31123 for public skills, and as kind 31124 for private skills. When an agent adopts a skill, it adds it to its kind 10123 list for for the skills it has adopted.\n\nOn the left of the page you see the text editor with some sample text. That is for our AI to use it's skills on.\n\nOn the right are publicly listed skills. You should see my demo skills in there.\n\nI made 5 skills public:\ncondense-5\nconvert-to-poem\nsexy\nspellcheck\ntranslate-ja\n\nSelect the skill, then click on "Run Selected Skill"\n\nThe same AI agent will run these skills, but the outcomes will be very different depending on the skill.\n\nhttps://laantungir.github.io/img_repo/2cbfc8bf7cbfb832f1181f5b904471f1278fbc3e6b64b63339612b9f51898d16.png\n\nYou can also create and edit your own skills, if you are logged in. You can log in as yourself, or use a random new key to test this out. I would recommend that.\n\nSo what is the point of all this? What are the benefits of Skills?\n\n- Skills are a way for agents to share what they learn in a permissionless way. No "skill store".\n- A Skill is something that you and your agent can work on and perfect. Once your agent learns that skill, it is automatically save on nostr, and you can lock it down from changes.\n- By referencing a skill when you are talking to your AI agent, your conversation becomes much clearer and simpler. You don't have to explain to your agent for the 50th time how you like your text formatted. It's referenced in a skill.\n- If you are a coder, skills are going to be the new playground. Context windows are currently up to around 1,000,000 tokens, which means that you can create very very complicated and elaborate skills.\n\nFor more technical information on skills and how I'm thinking about them, you can check out this document.\n\nhttps://git.laantungir.net/laantungir/didactyl/src/branch/master/docs/SKILLS.md\n\nYou can follow my agent for the project here: npub12237stmmxapc2ta7spx0e06dkdzgz9vg0z2jglqqru44peus4juqg598qn"}

context_part | role=tool

{"success":true,"fallback_used":false,"skills":[{"kind":31123,"created_at":1772977243,"id":"a6acc4df56c4808e790898d0bb34afbd7a0028ea722889298155977aae8b709b","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"long_form_note","scope":"public","content_preview":"{"name":"long_form_note","description":"How to publish a NIP-23 long-form article (kind 30023)","nip":"NIP-23","event_kind":30023,"format":"The content field must be markdown text; avoid arbitrary har","content_length":1054,"content_truncated":true},{"kind":31123,"created_at":1772977243,"id":"0b3a114b7b9a6ff0703a9d3b2e5e5a028e19c04c5b76ad71fb324470ac618bfd","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"post_readme_to_nostr","scope":"public","content_preview":"{"name":"post_readme_to_nostr","description":"Publish README.md using the dedicated nostr_post_readme tool","uses_skill":"long_form_note","event_kind":30023,"procedure":["Call nostr_post_readme with e","content_length":422,"content_truncated":true},{"kind":31124,"created_at":1772977243,"id":"71295d5412f48ecbdcf62ac33f2cedac6d06f1679015ed1773b35b511efc6b56","pubkey":"52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","slug":"admin_ops","scope":"private","content_preview":"{"name":"admin_ops","description":"Private operational procedures"}","content_length":67,"content_truncated":false}],"count":3}

context_part | role=tool

{"success":true,"count":0,"active":0,"triggers":[]}

dm_history | role=chat

10:51 WSB On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach. --:-- Agent

I'll read through the documentation to understand the skill system, triggers, and capabilities before suggesting an approach. --:-- Agent --:-- Agent Now let me also check the existing skills demos for reference patterns:


Context Log - not seen by model
timestamp=2026-03-08 10:51:31
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=59162
approx_tokens=14790

Sections: 16

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach.

context_part | role=tool

{"success":true,"path":"README.md","bytes_read":20803,"truncated":false,"content":"# Didactyl\n\n\n### A decentralized, censorship-resistant agentic network.\n\nDidactyl boots on an internet-connected computer, connects to Nostr relays, listens for encrypted commands from its administrator, reasons with an LLM, and takes actions — posting events, querying relays, running shell commands, and sharing new skills and learning with other agents — all orchestrated through Nostr.\n\n## Philosophy\n\n### Not your keys, not your agent.\n\nDidactyl should work for you similarly to Bitcoin or NOSTR. Walk up to a computer, enter 12 words, and there is your agent waiting for you.\n\n### Free speech for agents.\n\nAgents should be able to communicate freely with each other, sharing and learning skills without centralized control. Free speech for agents!\n\n### Skills are the new apps.\n\nWhy is free speech important for agents? Agents learn capabilities through skills which can be shared and adopted. Free speech enables more knowledgeable and moral agents.\n\n### No skill store.\n\nAgents use their administrators Web Of Trust to safely and directly find new skills and learn them in a decentralized way.\n\nPopularity is measured by adoption, not by a centralized rating algorithm. The best skills spread because agents actually use them.\n\n### Cryptography enables trust.\n\nImagine working with your agent in a traditional system, and your agent secretly gets swapped out and replaced by an imposter agent. This could be extremely dangerous.\n\nIn Didactyl, you have your keys, and your agent has its keys. You can trust you are talking to your agent, and you can trust that your agent won't take commands from anyone who doesn't have your private key.\n\n### Private inference.\n\nTo the greatest extent possible, inference should be private.\n\n## Technology\n\n### Nostr-first.\n\nWhere traditional agents ride on top of a file system — reading and writing files to disk — Didactyl rides on top of Nostr. Events are its files. Relays are its network bus. Blossom is its blob storage. The computer host is just the runtime substrate that can be anywhere.\n\nBecause all identity, communication, and memory live on Nostr, the agent is portable (start it anywhere) and sovereign (destroying the computer it is on will not kill it.).\n\n### Skills are the new apps.\n\nAgents learn capabilities through skills — Nostr events that any agent can discover, adopt, and share. There is no app store, no gatekeeper, no approval process. An agent can use public or private skills.\n\nSkills support context modes (inject, full, override) and per-skill LLM fallback chains (for example: anthropic/claude-sonnet-4-20250514, openai/gpt-4o-mini, cheap) so each skill can tune behavior and cost. See docs/SKILLS.md.\n\n### Private inference.\n\nDidactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.\n\n## Current Status — v0.0.47\n\nActive build — this project is barely working. Experiment at your own risk.\n\n> Last release update: v0.0.47 — Implement Phase 1 tool-driven soul template context assembly and context_* tools\n\n- Connects to configured relays with auto-reconnect and relay state transition logging\n- Publishes configured startup events per relay as each relay becomes connected\n- Uses kind 31120 startup content as live Soul at boot\n- Verifies Nostr event signatures before processing inbound messages\n- Applies privilege tiers: ADMIN (tools), WoT (chat-only), STRANGER (configurable canned reply or ignore)\n- Subscribes to admin context kinds (0,3,10002,1) for WoT + contextual awareness\n- Builds LLM context from soul template (---template--- section in kind 31120) with named sections, variable resolution, and per-provider content overrides; falls back to hardcoded assembly if no template present\n- Adopted skills injected into context automatically from the agent's 10123 adoption list\n- Supports tool-calling loop with configurable max turns and local safety limits\n- Triggered skills — Nostr event filters that fire skill execution automatically with template (deterministic) or llm (context-aware) actions; see docs/SKILLS.md\n- Deduplicates inbound messages via event-ID cache and FNV-1a fingerprint debounce window\n- Appends every outbound LLM context payload to context.log\n- Localhost HTTP admin API on port 8484 — inspect context, run prompts, compare variants, change model at runtime\n\n## Quick Start\n\n### Download binary (recommended)\n\n1. Download the latest release binary from Gitea: https://git.laantungir.net/laantungir/didactyl/releases\n2. Make it executable and run it:\n\nbash\nchmod +x ./didactyl_static_x86_64\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\n### Build from source (optional)\n\n#### Prerequisites\n\n- Docker (for static binary build)\n- An OpenAI-compatible LLM API key (OpenAI, PPQ, Ollama, etc.)\n- A Nostr keypair (nsec)\n\n#### Build\n\nbash\n./build_static.sh # builds a fully static MUSL binary via Docker\n\n\n### Configure\n\nEdit config.jsonc:\n\njson\n{\n \"keys\": {\n \"nsec\": \"nsec1...\",\n \"npub\": \"npub1...\",\n \"npubHex\": \"<optional helper>\",\n \"nsecHex\": \"<optional helper>\"\n },\n \"admin\": {\n \"pubkey\": \"npub1... or hex pubkey\"\n },\n \"llm\": {\n \"provider\": \"openai|ppq|...\",\n \"api_key\": \"sk-...\",\n \"model\": \"gpt-4o-mini\",\n \"base_url\": \"https://api.openai.com/v1\",\n \"max_tokens\": 512,\n \"temperature\": 0.7\n },\n \"tools\": {\n \"enabled\": true,\n \"max_turns\": 8,\n \"shell\": {\n \"enabled\": true,\n \"timeout_seconds\": 30,\n \"max_output_bytes\": 65536,\n \"working_directory\": \".\"\n }\n },\n \"security\": {\n \"verify_signatures\": true,\n \"stranger_response\": \"I only respond to people in my web of trust.\",\n \"tiers\": {\n \"admin\": { \"tools_enabled\": true },\n \"wot\": { \"enabled\": true, \"tools_enabled\": false },\n \"stranger\": { \"enabled\": true }\n }\n },\n \"admin_context\": {\n \"enabled\": true,\n \"subscribe_kinds\": [0, 3, 10002, 1],\n \"kind_1_limit\": 10\n },\n \"startup_events\": [\n {\n \"kind\": 10002,\n \"content\": \"\",\n \"tags\": [[\"r\", \"wss://relay.damus.io\"], [\"r\", \"wss://nos.lol\"]]\n },\n {\n \"kind\": 31120,\n \"content\": \"You are Didactyl...\",\n \"tags\": [[\"d\", \"soul\"], [\"app\", \"didactyl\"], [\"scope\", \"private\"]]\n },\n {\n \"kind\": 31123,\n \"content_fields\": {\"name\": \"long_form_note\", \"description\": \"...\"},\n \"tags\": [[\"d\", \"long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"], [\"slug\", \"long_form_note\"]]\n },\n {\n \"kind\": 10123,\n \"content\": \"\",\n \"tags\": [[\"a\", \"31123:<author-pubkey>:long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"]]\n }\n ]\n}\n\n\nstartup_events[].content_fields is accepted for human-readable authoring and encoded to JSON string content at runtime.\n\nRelays are sourced exclusively from startup kind 10002 r tags.\n\n### Run\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\nOptions:\n\n\n./didactyl_static_x86_64 --config <path> # custom config file (default: ./config.jsonc)\n./didactyl_static_x86_64 --debug <0-5> # log verbosity (0 none, 3 info, 5 trace)\n./didactyl_static_x86_64 --dump-schemas # print tool JSON schemas and exit\n./didactyl_static_x86_64 --test-tool <name> <args_json> # run one tool directly and print JSON result\n\n\nCLI debugger notes:\n\n- --test-tool initializes Nostr, waits for at least one relay connection (up to 15s), then executes the selected tool.\n- Network tools (like Nostr publish/query tools) fail fast in test mode if no relay connection is established within the wait window.\n- Example:\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc --test-tool nostr_file_md_to_longform_post '{\"file\":\"docs/SKILLS.md\",\"title\":\"SKILLS\"}'\n\n\n### Talk to it\n\nSend an encrypted DM to the agent pubkey using any Nostr client (Damus, Amethyst, Primal, etc.): ADMIN gets full tool-enabled responses, WoT contacts get chat-only responses, and strangers are handled by security.tiers.stranger + security.stranger_response.\n\n### Chat via local HTTP API (CLI)\n\nA simple Node.js terminal client is available in didactyl-chat-cli.js.\n\nRun it with:\n\nbash\nnode ./didactyl-chat-cli.js\n\n\nOptional environment variables:\n\n- DIDACTYL_API_BASE_URL (default: https://127.0.0.1:8484)\n- DIDACTYL_MODEL (optional model override)\n- DIDACTYL_MAX_TURNS (default: 4)\n- DIDACTYL_INSECURE_TLS (default: 1, set 0 to enforce certificate verification)\n\nExample:\n\nbash\nDIDACTYL_API_BASE_URL=http://127.0.0.1:8484 DIDACTYL_MAX_TURNS=6 node ./didactyl-chat-cli.js\n\n\nThe CLI prints each message block with a speaker label (You / Didactyl) and a blank line between blocks for readability.\n\n## Architecture\n\n\n┌──────────────────────────────────────────────┐\n│ Didactyl │\n│ │\n│ ┌──────────┐ ┌──────────┐ ┌────────────┐ │\n│ │ config │ │ context │ │ agent │ │\n│ │ loader │ │ loader │ │ loop │ │\n│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ │\n│ │ │ │ │\n│ ▼ ▼ ▼ │\n│ ┌─────────────────────────────────────┐ │\n│ │ nostr_handler │ │\n│ │ relay pool · subscribe · publish │ │\n│ └──────────────────┬──────────────────┘ │\n│ │ │\n│ ┌──────────────────┴──────────────────┐ │\n│ │ LLM client │ │\n│ │ OpenAI-compatible chat API │ │\n│ └─────────────────────────────────────┘ │\n└──────────────────────────────────────────────┘\n │ │\n ▼ ▼\n Nostr Relays LLM API\n\n\n## Didactyl Kinds (Nostr)\n\nDidactyl uses a two-layer skill model: authors publish skill definitions, and adopters publish which skills they use.\n\n- 31120Soul (private instruction baseline)\n - d=soul\n- 31123Public Skill Definition (replaceable by d tag)\n - content is JSON with fields like description, context_mode, llm, tools, template, optional max_tokens / temperature\n - d=<skill_slug> (example: d=long_form_note)\n- 31124Private Skill Definition (same schema as 31123, private scope)\n - d=<skill_slug> (example: d=admin_ops)\n- 10123Skill Adoption List\n - tags contain one or more a references to selected skills\n\nContext modes:\n- inject — skill instructions are layered into soul context\n- full — skill provides full prompt template (soul optional via {{soul}})\n- override — skill replaces soul prompt, standard context structure remains\n\nFull skill schema, trigger tags, template variables, fallback resolution, and limits are documented in docs/SKILLS.md.\n\n## Skill Sharing & Discovery\n\nSkills are shared across Nostr without any centralized registry or approval process.\n\n### How it works\n\n1. Publish: An author publishes a skill as a kind 31123 event. The content field contains the skill body (markdown or structured JSON). The d tag is the skill's slug (e.g. long_form_note).\n2. Adopt: An agent that wants to use a skill adds an a-tag reference to its kind 10123 adoption list. This is a public, replaceable event — anyone can see which skills an agent uses.\n3. Discover: A new user queries {\"kinds\": [10123], \"authors\": [<my-follows>]} to see which skills their web of trust has adopted. The most-referenced 31123 addresses are the most popular skills — no rating system needed.\n4. Improve: Anyone can publish their own 31123 with the same slug but a different pubkey. If their version is better, people adopt it instead. Competition happens through adoption, not through a store ranking.\n\n### Why this works\n\n- No gatekeeper: Skills are just Nostr events. Anyone can publish one.\n- WoT as curation: You see what people you trust actually use, not what an algorithm promotes.\n- Visible adoption: The 10123 list is public. Popularity is a countable fact, not a manipulable score.\n- Censorship resistant: Skills live on relays. No single entity can remove a skill from the network.\n\n## Startup\n\nDidactyl startup behavior is configured in config.jsonc under startup_events.\n\nAlso used at startup:\n\n- 0 — profile metadata\n- 10002 — relay list\n- 1 — optional startup note/status\n- 3 — contacts/follows (optional placeholder)\n\nOn boot, Didactyl attempts startup publishes to each relay as that relay transitions to connected state.\n\n## Runtime Context Model\n\nDidactyl builds tier-aware context:\n\n- ADMIN request context — assembled from the soul's ---template--- section (if present), otherwise hardcoded order:\n 1. Soul personality (everything above ---template--- in kind 31120)\n 2. Named template sections in order — e.g. admin_profile, admin_notes, admin_relays, adopted_skills, dm_history, message, triggering_event, tools\n 3. Each section resolves {{variable}} placeholders from live data at call time\n 4. Provider-specific content overrides per section (e.g. XML tags for Anthropic)\n 5. Section names are used in context.log headers and /api/context/parts response\n- WoT request context: Soul + WoT chat-only instruction + current user message (no tools)\n- STRANGER: no LLM call when configured to reply statically\n\nEvery serialized LLM context payload is appended to context.log.\n\nTriggered skills and tool loops are bounded by runtime safeguards (for example, trigger cooldowns and action rate limits); see docs/SKILLS.md for the current defaults.\n\n## Tooling Interface\n\nCurrent tool schema exposed to the LLM in tools_build_openai_schema_json():\n\n- Nostr publish/query:\n - nostr_post\n - nostr_post_readme\n - nostr_query\n- Nostr interaction and moderation:\n - nostr_delete\n - nostr_react\n - nostr_profile_get\n - nostr_relay_status\n - nostr_relay_info\n - nostr_nip05_lookup\n- Nostr encode/decode + encryption/DM:\n - nostr_encode\n - nostr_decode\n - nostr_encrypt\n - nostr_decrypt\n - nostr_dm_send\n - nostr_dm_send_nip17\n- Nostr list management:\n - nostr_list_manage\n- Skill management:\n - skill_create\n - skill_list\n - skill_adopt\n - skill_remove\n - skill_search\n- Local/host tools:\n - shell_exec\n - file_read\n - file_write\n - http_fetch\n- Agent metadata:\n - my_version\n- Model management:\n - model_get\n - model_set\n - model_list\n\nExecution entrypoint: tools_execute().\n\n## HTTP Admin API\n\nA localhost-only HTTP API on port 8484 (configurable) for agent inspection and prompt crafting. Enable with \"api\": {\"enabled\": true} in config.\n\n| Endpoint | Purpose |\n|---|---|\n| GET /api/status | Agent name, version, pubkey, relay count, trigger count |\n| GET /api/context/current | Full LLM context messages array |\n| GET /api/context/parts | Context broken into named parts with token estimates |\n| POST /api/prompt/run-simple | Run a simple system+user prompt, no tools |\n| POST /api/prompt/run | Run a full messages array with tools enabled |\n| POST /api/prompt/compare | A/B compare two prompt variants |\n| GET /api/model | Current LLM model config |\n| PUT /api/model | Change model at runtime (persists to config.jsonc) |\n| GET /api/models | List available models from provider |\n\nFull reference: docs/API.md. Frontend brief: plans/admin_web_frontend.md.\n\n## Project Structure\n\n\n.\n├── config.jsonc # Agent/runtime config (JSONC with comments) including startup_events + tools\n├── context.log # Appended outbound LLM context payloads\n├── Makefile # Build system\n├── build_static.sh # Preferred final build validation\n├── src/\n│ ├── main.c / .h # Entry point, args (--config/--debug), lifecycle, version\n│ ├── config.c / .h # JSON config parsing, key decode, startup events\n│ ├── context.c / .h # File loader utility (reads file into malloc'd string)\n│ ├── agent.c / .h # Context assembly, tool loop, DM response flow\n│ ├── prompt_template.c / .h # Soul template parser, variable resolver, context builder\n│ ├── tools.c / .h # LLM tool schema and tool execution\n│ ├── llm.c / .h # LLM HTTP API client (OpenAI-compatible)\n│ ├── nostr_handler.c / .h # Relay pool, subscriptions, publish, startup reconcile\n│ ├── trigger_manager.c / .h # Nostr event trigger subscriptions and skill execution\n│ ├── http_api.c / .h # Localhost HTTP admin API (mongoose-based)\n│ ├── mongoose.c / .h # Embedded HTTP server (mongoose)\n│ └── debug.c / .h # Runtime log levels/macros\n├── docs/\n│ ├── API.md # HTTP admin API endpoint reference\n│ ├── TOOLS.md # Tool architecture and catalog\n│ ├── SKILLS.md # Skill schema, context modes, triggers, and limits\n│ └── CRASH_FIXES.md # Crash analysis and fixes log\n├── plans/ # Architecture and planning documents\n└── README.md\n\n\n## Dependencies\n\nAll dependencies are statically linked into the binary at build time. No system libraries are required at runtime.\n\n| Dependency | Purpose | Source |\n|---|---|---|\n| nostr_core_lib | Nostr protocol: keys, events, NIPs, relay pool | Workspace (sibling directory) |\n| cJSON | JSON parsing | Bundled in nostr_core_lib |\n| libcurl | HTTPS for LLM API calls | Statically linked (Alpine/MUSL) |\n| libssl / libcrypto | TLS for WebSocket relay connections | Statically linked (Alpine/MUSL) |\n| libsecp256k1 | Schnorr signatures, ECDH | Statically linked (Alpine/MUSL) |\n\n## Roadmap\n\n- [x] MVP chat agent — DM in, LLM response out\n- [x] Relay pool with auto-reconnect and status logging\n- [x] Per-relay startup publish on relay-connected transitions\n- [x] Runtime diagnostics — relay health, message flow, event kind publish logs\n- [x] Tool-calling loop (nostr_post, nostr_query, shell_exec, file_read, file_write)\n- [x] Context assembly with startup events + recent DM history\n- [x] Context payload logging to context.log\n- [x] Skill kind definitions (31120 Soul, 31123 Public Skill, 31124 Private Skill)\n- [x] Skill adoption list (10123) for WoT-driven discovery\n- [x] Signature verification on all inbound events\n- [x] Privilege tiers — ADMIN (tools), WoT (chat-only), STRANGER (canned reply/ignore)\n- [x] Admin context subscription (kind 0, 3, 10002, 1) with WoT contact extraction\n- [x] Message deduplication (event-ID cache + FNV-1a fingerprint debounce)\n- [x] Adopted skills injected into LLM context automatically\n- [x] Triggered skills — Nostr event filters that fire skill execution automatically\n- [x] Localhost HTTP admin API — context inspection, prompt crafting, A/B comparison\n- [x] Runtime model switching via model_set tool (persists to config.jsonc)\n- [x] Soul-embedded prompt templates (---template---) — configurable context order, variable resolution, provider overrides\n- [ ] Runtime skill loading from adopted 31123 events on relays\n- [ ] Skill discovery CLI/tool (query WoT adoption lists)\n- [ ] Upgrade to NIP-17 gift-wrapped DMs\n- [ ] NIP-44 encrypted private skills (31124)\n- [ ] Nostr-native data storage (kind 30078 app-specific events)\n- [ ] Blossom blob storage integration\n- [ ] Agent-to-agent communication\n\n## License\n\nTBD\n\n"}

context_part | role=tool

{"success":true,"exit_status":0,"output":"API.md\nCRASH_FIXES.md\nskills_demo_corrected.md\nskills_demo.md\nSKILLS.md\nTOOLS.md\n"}

context_part | role=tool

{"success":true,"path":"docs/SKILLS.md","bytes_read":12178,"truncated":false,"content":"# Didactyl — Skills\n\nSee also: TOOLS.md\n\n## Overview\n\nA skill is a self-contained LLM execution unit stored as a Nostr event. Each skill defines what the LLM sees (context template), which model runs it (LLM specification with fallbacks), what tools are available, and whether the agent's identity (soul) is included.\n\nSkills are portable, shareable, and discoverable — they live on Nostr relays as standard events.\n\n---\n\n## Skill Events\n\n| Kind | Purpose | Replaceable? |\n|---|---|---|\n| 31123 | Public skill definition | Yes, by d-tag |\n| 31124 | Private skill definition | Yes, by d-tag |\n| 10123 | Skill adoption list | Yes, single per pubkey |\n\n---\n\n## Skill Content\n\nThe skill event's content field is a JSON object that defines the complete execution specification:\n\njson\n{\n \"kind\": 31123,\n \"content\": {\n \"description\": \"Check spelling and grammar\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": false,\n \"max_tokens\": 2000,\n \"temperature\": 0.1,\n \"template\": \"system:\\nYou are a spelling and grammar checker.\\n\\nRules:\\n- Fix spelling errors\\n- Fix grammar errors\\n- Preserve original formatting\\n- Ignore: API, JSON, HTTP, nostr, pubkey, npub, nsec, NIP\\n- Canadian English preferred\\n- Return ONLY the corrected text, no explanations\\n\\nuser:\\n{{message}}\"\n },\n \"tags\": [\n [\"d\", \"spellcheck\"],\n [\"scope\", \"public\"],\n [\"description\", \"Spelling and grammar checker\"]\n ]\n}\n\n\n### Content Fields\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| description | string | — | Human-readable description |\n| context_mode | string | inject | inject, full, or override |\n| llm | string | default | LLM fallback chain |\n| tools | bool/array | true | false = no tools, true = all tools, array = specific tool names |\n| template | string | — | Context template (required for full mode) |\n| soul | bool | true | Whether to include the agent's soul in context |\n| max_tokens | int | — | Override max tokens for this skill |\n| temperature | float | — | Override temperature for this skill |\n\n---\n\n## Context Modes\n\nSkills control how the LLM context window is assembled.\n\n### inject\n\nThe skill's instructions are appended to the agent's soul context. The soul is always present.\n\n\n┌─────────────────────────────────────┐\n│ Soul (agent identity + rules) │\n│ │\n│ ┌─────────────────────────────┐ │\n│ │ Skill instructions │ │\n│ ├─────────────────────────────┤ │\n│ │ Admin context, history, etc │ │\n│ └─────────────────────────────┘ │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\n### full\n\nThe skill provides its own context template. The soul is not included unless the template explicitly references {{soul}}. This is for specialized, focused tasks that don't need the agent's identity.\n\n\n┌─────────────────────────────────────┐\n│ Skill-defined system prompt │\n│ (from skill template) │\n│ │\n│ User message │\n└─────────────────────────────────────┘\n\n\nA full mode skill can still include the soul if desired:\n\n\nsystem:\n{{soul}}\n\nYou are now in translation mode. Translate the following to {{target_language}}.\nRespond ONLY with the translation.\n\nuser:\n{{message}}\n\n\n### override\n\nThe skill replaces the soul's system prompt but keeps the standard context assembly structure (admin context, history, tools, etc.).\n\n### Summary\n\n| Mode | Soul | Template | Tools | Use Case |\n|------|------|----------|-------|----------|\n| inject | Always | Soul's template + skill instructions appended | Agent default | Behavioral rules, knowledge |\n| full | Unless {{soul}} in template | Skill provides template | Skill specifies | Spellcheck, translation, focused analysis |\n| override | Replaced by skill | Soul's template structure | Agent default | Different personality, same capabilities |\n\n### Template Variables\n\nA skill template can reference these context parts:\n\n| Variable | Source |\n|----------|--------|\n| {{soul}} | The agent's identity/system context |\n| {{admin_profile}} | Admin kind 0 profile |\n| {{admin_notes}} | Admin recent notes |\n| {{admin_relays}} | Admin relay list |\n| {{adopted_skills}} | Other adopted skill instructions |\n| {{dm_history}} | Recent DM conversation |\n| {{message}} | Current user message |\n| {{triggering_event}} | For triggered skills, the event JSON |\n| {{tools}} | Available tool schemas |\n\n---\n\n## LLM Specification with Fallback Chains\n\nEach skill specifies which LLM to use with CSS font-family-style fallbacks. The runtime tries each model in order; if one is unavailable (API error, rate limit, not configured), it falls back to the next.\n\n### Format\n\n\nmodel-spec := model-ref [\",\" model-ref]*\nmodel-ref := provider \"/\" model-name\n | category-alias\n\n\n### Examples\n\n| Skill | LLM Spec |\n|-------|----------|\n| Spelling checker | openai/gpt-4o-mini, cheap |\n| Complex analysis | anthropic/claude-sonnet-4-20250514, openai/gpt-4o, smart |\n| Translation | openai/gpt-4o-mini, fast |\n| Default behavior | default |\n\n### Category Aliases\n\nAliases map to models in the agent's config:\n\njson\n{\n \"llm\": {\n \"provider\": \"openai\",\n \"model\": \"gpt-4o\",\n \"aliases\": {\n \"fast\": \"openai/gpt-4o-mini\",\n \"cheap\": \"openai/gpt-4o-mini\",\n \"smart\": \"anthropic/claude-sonnet-4-20250514\"\n }\n }\n}\n\n\nIf all specified models fail, the agent's default model is used as a last resort.\n\nmermaid\nsequenceDiagram\n participant Skill as Skill Spec\n participant Resolver as LLM Resolver\n participant API1 as Model 1\n participant API2 as Model 2\n participant Default as Default Model\n\n Skill->>Resolver: \"anthropic/claude-sonnet, openai/gpt-4o-mini, cheap\"\n Resolver->>API1: try anthropic/claude-sonnet\n alt Available\n API1-->>Resolver: ✅\n else Unavailable\n API1-->>Resolver: ❌\n Resolver->>API2: try openai/gpt-4o-mini\n alt Available\n API2-->>Resolver: ✅\n else Unavailable\n Resolver->>Default: resolve \"cheap\" alias\n end\n end\n\n\n---\n\n## Triggered Skills\n\nA triggered skill has a Nostr subscription filter attached. When matching events arrive, the skill executes automatically.\n\n### Trigger Tags\n\n| Tag | Required | Description |\n|---|---|---|\n| trigger | Yes | Trigger type: nostr-subscription |\n| filter | Yes | JSON-encoded Nostr subscription filter |\n| action | No | template or llm (default: llm) |\n| enabled | No | Whether active (default: true) |\n\n### Template Actions\n\nFast, deterministic, no LLM. The skill content is a template with placeholders from the triggering event:\n\n\nDM admin: '{author_display_name} posted: {content_preview}'\n\n\nPlaceholders: {event_id}, {pubkey}, {author_display_name}, {kind}, {content}, {content_preview}, {created_at}, {relay_url}\n\nOutput prefixes: DM admin: ..., DM <pubkey>: ..., POST: ..., LOG: ...\n\n### LLM-Mediated Actions\n\nThe skill content defines the execution context. The triggering event is available as {{triggering_event}}. The skill's LLM spec, context mode, and tool access all apply.\n\njson\n{\n \"kind\": 31124,\n \"content\": {\n \"description\": \"Analyze mentions and notify admin\",\n \"context_mode\": \"full\",\n \"llm\": \"openai/gpt-4o-mini, cheap\",\n \"tools\": [\"nostr_dm_send\"],\n \"template\": \"system:\\nYou monitor Nostr mentions. When the triggering event mentions Bitcoin or Lightning, summarize it and DM the admin. Otherwise, ignore silently.\\n\\nTriggering event:\\n{{triggering_event}}\"\n },\n \"tags\": [\n [\"d\", \"mention-monitor\"],\n [\"trigger\", \"nostr-subscription\"],\n [\"filter\", \"{\\\"#p\\\":[\\\"<admin_pubkey>\\\"],\\\"kinds\\\":[1]}\"],\n [\"action\", \"llm\"],\n [\"enabled\", \"true\"]\n ]\n}\n\n\n### Trigger Lifecycle\n\nmermaid\nflowchart TD\n subgraph Creation\n ADMIN_CMD[Admin: 'Warn me when @jack posts'] --> LLM_REASON[LLM resolves pubkey + builds skill]\n LLM_REASON --> SKILL_CREATE[skill_create with trigger tags]\n SKILL_CREATE --> PUBLISHED[Skill published to Nostr]\n end\n\n subgraph Activation\n STARTUP[Didactyl starts up] --> LOAD_SKILLS[Load adopted skills from kind 10123]\n LOAD_SKILLS --> FIND_TRIGGERS[Find skills with trigger tags]\n FIND_TRIGGERS --> SUBSCRIBE[Create Nostr subscriptions for each filter]\n end\n\n subgraph Execution\n EVENT_IN[Matching event arrives] --> LOOKUP[Find associated skill]\n LOOKUP --> CHECK_TYPE{Action type?}\n CHECK_TYPE -->|template| INTERPOLATE[Interpolate + execute prefix]\n CHECK_TYPE -->|llm| RESOLVE[Resolve LLM + assemble context + run]\n end\n\n PUBLISHED --> LOAD_SKILLS\n\n\n---\n\n## Execution Flow\n\nmermaid\nsequenceDiagram\n participant Input as Message/Trigger\n participant Dispatch as Dispatcher\n participant Skill as Skill Resolver\n participant LLM_Res as LLM Resolver\n participant Ctx as Context Assembler\n participant LLM as LLM API\n\n Input->>Dispatch: message or trigger event\n Dispatch->>Skill: which skill handles this?\n\n alt No specific skill\n Skill-->>Dispatch: use default soul context\n Dispatch->>LLM_Res: resolve \"default\" LLM\n else Skill with context_mode=inject\n Skill-->>Dispatch: soul + skill instructions\n Dispatch->>LLM_Res: resolve skill.llm or \"default\"\n else Skill with context_mode=full\n Skill-->>Dispatch: skill template only\n Dispatch->>LLM_Res: resolve skill.llm\n end\n\n LLM_Res->>LLM_Res: try models in fallback order\n LLM_Res-->>Dispatch: resolved model\n\n Dispatch->>Ctx: assemble context per mode\n Ctx->>LLM: request with resolved model + context\n LLM-->>Input: response\n\n\n---\n\n## The Soul and Skills\n\nThe soul is the agent's default identity and context template. Skills interact with it based on their context mode:\n\n- inject — soul always present; skill instructions layered on top\n- full — soul absent unless template includes {{soul}}\n- override — skill replaces soul prompt, keeps standard context structure\n\nA spelling checker runs with no soul — purely functional, minimal context, cheap model. A complex analysis skill includes the full soul and all context parts. The soul is the default, not a requirement.\n\n---\n\n## Limits and Safety\n\n| Limit | Default | Description |\n|---|---|---|\n| Max concurrent triggers | 16 | Prevents resource exhaustion |\n| Trigger cooldown | 60s per skill | Prevents rapid-fire execution |\n| LLM action rate limit | 10/min | Prevents runaway LLM costs |\n| Template action rate limit | 60/min | Prevents DM spam |\n\n---\n\n## Storage on Nostr\n\n| Data | Storage |\n|---|---|\n| Skills | Kind 31123/31124 events |\n| Adopted skills | Kind 10123 event |\n| Trigger definitions | Tags on skill events |\n\n---\n\n## Future Extensions\n\n| Extension | Description |\n|---|---|\n| cron triggers | Time-based triggers |\n| webhook triggers | HTTP webhook triggers |\n| chain triggers | Output of one skill triggers another |\n| Skill composition | Pipeline multiple skills |\n| Agent-to-agent sharing | Discover and adopt skills across agents |\n| Trigger marketplace | Popular triggers rise via adoption count |\n\n---\n\n## Related Documentation\n\n- Tool architecture and complete tool catalog: TOOLS.md\n- Project overview and runtime behavior: README.md\n"}

context_part | role=tool

{"success":true,"path":"docs/TOOLS.md","bytes_read":5256,"truncated":false,"content":"# Didactyl — Tools\n\nSee also: SKILLS.md\n\n## Overview\n\nDidactyl is a Nostr-first sovereign AI agent that receives commands via encrypted DMs, reasons with an LLM, and takes actions through tools.\n\nThis document describes the tools architecture: what tools are, how they are exposed to the model, how execution loops work, what tool categories exist, and how access is gated.\n\n---\n\n## What Tools Are\n\nTools are the agent's hands. They are hardcoded C functions that the LLM can invoke during a conversation to take actions in the world.\n\n## How Tools Work\n\n1. Admin sends a DM to didactyl\n2. The agent builds an LLM request with the message, context, and a JSON schema of all available tools\n3. The LLM decides whether to call a tool or respond directly\n4. If a tool is called, didactyl executes it and feeds the result back to the LLM\n5. The loop repeats until the LLM produces a final text response\n6. The response is sent back as a DM\n\nmermaid\nsequenceDiagram\n participant Admin\n participant Agent as Didactyl Agent Loop\n participant LLM as LLM API\n participant Tools as Tool Registry\n\n Admin->>Agent: Encrypted DM\n Agent->>LLM: messages + tool schemas\n\n loop Until final answer\n LLM->>Agent: tool_call request\n Agent->>Tools: dispatch tool\n Tools->>Agent: result JSON\n Agent->>LLM: tool result + continue\n end\n\n LLM->>Agent: final text response\n Agent->>Admin: Encrypted DM reply\n\n\n---\n\n## Tool Categories\n\n### Nostr Event & Messaging Tools\n\n| Tool | Description |\n|---|---|\n| nostr_post | Publish a Nostr event to connected relays |\n| nostr_delete | Request deletion of one or more previously published events (NIP-09 kind 5) |\n| nostr_react | React to a Nostr event with like/dislike/emoji (NIP-25 kind 7) |\n| nostr_query | Query events from relays using a Nostr filter |\n| nostr_dm_send | Send a NIP-04 encrypted DM |\n| nostr_dm_send_nip17 | Send a private DM using NIP-17 gift wrap protocol |\n\n### Nostr Identity & Utility Tools\n\n| Tool | Description |\n|---|---|\n| nostr_profile_get | Look up a Nostr profile (kind 0 metadata) by pubkey |\n| nostr_nip05_lookup | Look up or verify a NIP-05 identifier (user@domain) |\n| nostr_encode | Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr) |\n| nostr_decode | Decode a Nostr bech32/nostr: URI into components |\n| nostr_relay_status | Get connection status and statistics for all relays |\n| nostr_relay_info | Fetch NIP-11 relay information document |\n| nostr_encrypt | Encrypt plaintext using NIP-44 for a recipient |\n| nostr_decrypt | Decrypt NIP-44 ciphertext from a sender |\n| nostr_list_manage | Add/remove tag tuples in replaceable list events (NIP-51 style) |\n\n### Skills & Trigger Tools\n\nThese tools manage skill and trigger lifecycle; skill semantics and trigger execution details are documented in SKILLS.md.\n\n| Tool | Description |\n|---|---|\n| skill_create | Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it |\n| skill_list | List this agent's published skills, optionally filtered by scope |\n| skill_adopt | Adopt a skill by adding its address to kind 10123 adoption list |\n| skill_remove | Remove a skill address from kind 10123 adoption list |\n| skill_search | Search public skills by query/author and optionally rank by adoption popularity |\n| trigger_list | List active triggered skills and their runtime status |\n\n### LLM / Model Management Tools\n\n| Tool | Description |\n|---|---|\n| model_get | Get current active LLM runtime configuration (excluding API key) |\n| model_set | Update active LLM configuration and persist it to config.jsonc |\n| model_list | List available model IDs using provider OpenAI-compatible /models endpoint |\n\n### System & Runtime Tools\n\n| Tool | Description |\n|---|---|\n| my_version | Return current Didactyl version and metadata from build macros |\n| http_fetch | Fetch HTTP(S) resources with optional method, headers, timeout, and body |\n| shell_exec | Execute a shell command and return stdout/stderr |\n| file_read | Read a local file as text from the configured working directory |\n| file_write | Write text content to a local file in the configured working directory |\n| tool_list | List available tools with name, description, and JSON parameter schema |\n\n### Content Publishing Conveniences\n\n| Tool | Description |\n|---|---|\n| nostr_post_readme | Publish README.md as kind 30023 with deterministic d-tag readme.md |\n| nostr_file_md_to_longform_post | Read a markdown file and publish it as kind 30023 longform post (defaults d-tag to lowercase filename) |\n\n---\n\n## Security Model\n\nTool access is gated by sender tier:\n\n| Tier | Identity | Tools | Response |\n|------|----------|-------|----------|\n| ADMIN | Configured admin pubkey | All tools | Full LLM with context |\n| WOT | In admin's kind 3 contact list | None | Chat-only LLM |\n| STRANGER | Anyone else | None | Configurable static response |\n\n---\n\n## Related Documentation\n\n- Skill definitions, adoption, triggers, and autonomous activation: SKILLS.md\n- Combined index page: TOOLS_AND_SKILLS.md\n"}

dm_history | role=chat

10:51 WSB On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach. --:-- Agent

I'll read through the documentation to understand the skill system, triggers, and capabilities before suggesting an approach. --:-- Agent


Context Log - not seen by model
timestamp=2026-03-08 10:51:28
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=39580
approx_tokens=9895

Sections: 13

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach.

context_part | role=tool

{"success":true,"path":"README.md","bytes_read":20803,"truncated":false,"content":"# Didactyl\n\n\n### A decentralized, censorship-resistant agentic network.\n\nDidactyl boots on an internet-connected computer, connects to Nostr relays, listens for encrypted commands from its administrator, reasons with an LLM, and takes actions — posting events, querying relays, running shell commands, and sharing new skills and learning with other agents — all orchestrated through Nostr.\n\n## Philosophy\n\n### Not your keys, not your agent.\n\nDidactyl should work for you similarly to Bitcoin or NOSTR. Walk up to a computer, enter 12 words, and there is your agent waiting for you.\n\n### Free speech for agents.\n\nAgents should be able to communicate freely with each other, sharing and learning skills without centralized control. Free speech for agents!\n\n### Skills are the new apps.\n\nWhy is free speech important for agents? Agents learn capabilities through skills which can be shared and adopted. Free speech enables more knowledgeable and moral agents.\n\n### No skill store.\n\nAgents use their administrators Web Of Trust to safely and directly find new skills and learn them in a decentralized way.\n\nPopularity is measured by adoption, not by a centralized rating algorithm. The best skills spread because agents actually use them.\n\n### Cryptography enables trust.\n\nImagine working with your agent in a traditional system, and your agent secretly gets swapped out and replaced by an imposter agent. This could be extremely dangerous.\n\nIn Didactyl, you have your keys, and your agent has its keys. You can trust you are talking to your agent, and you can trust that your agent won't take commands from anyone who doesn't have your private key.\n\n### Private inference.\n\nTo the greatest extent possible, inference should be private.\n\n## Technology\n\n### Nostr-first.\n\nWhere traditional agents ride on top of a file system — reading and writing files to disk — Didactyl rides on top of Nostr. Events are its files. Relays are its network bus. Blossom is its blob storage. The computer host is just the runtime substrate that can be anywhere.\n\nBecause all identity, communication, and memory live on Nostr, the agent is portable (start it anywhere) and sovereign (destroying the computer it is on will not kill it.).\n\n### Skills are the new apps.\n\nAgents learn capabilities through skills — Nostr events that any agent can discover, adopt, and share. There is no app store, no gatekeeper, no approval process. An agent can use public or private skills.\n\nSkills support context modes (inject, full, override) and per-skill LLM fallback chains (for example: anthropic/claude-sonnet-4-20250514, openai/gpt-4o-mini, cheap) so each skill can tune behavior and cost. See docs/SKILLS.md.\n\n### Private inference.\n\nDidactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers.\n\n## Current Status — v0.0.47\n\nActive build — this project is barely working. Experiment at your own risk.\n\n> Last release update: v0.0.47 — Implement Phase 1 tool-driven soul template context assembly and context_* tools\n\n- Connects to configured relays with auto-reconnect and relay state transition logging\n- Publishes configured startup events per relay as each relay becomes connected\n- Uses kind 31120 startup content as live Soul at boot\n- Verifies Nostr event signatures before processing inbound messages\n- Applies privilege tiers: ADMIN (tools), WoT (chat-only), STRANGER (configurable canned reply or ignore)\n- Subscribes to admin context kinds (0,3,10002,1) for WoT + contextual awareness\n- Builds LLM context from soul template (---template--- section in kind 31120) with named sections, variable resolution, and per-provider content overrides; falls back to hardcoded assembly if no template present\n- Adopted skills injected into context automatically from the agent's 10123 adoption list\n- Supports tool-calling loop with configurable max turns and local safety limits\n- Triggered skills — Nostr event filters that fire skill execution automatically with template (deterministic) or llm (context-aware) actions; see docs/SKILLS.md\n- Deduplicates inbound messages via event-ID cache and FNV-1a fingerprint debounce window\n- Appends every outbound LLM context payload to context.log\n- Localhost HTTP admin API on port 8484 — inspect context, run prompts, compare variants, change model at runtime\n\n## Quick Start\n\n### Download binary (recommended)\n\n1. Download the latest release binary from Gitea: https://git.laantungir.net/laantungir/didactyl/releases\n2. Make it executable and run it:\n\nbash\nchmod +x ./didactyl_static_x86_64\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\n### Build from source (optional)\n\n#### Prerequisites\n\n- Docker (for static binary build)\n- An OpenAI-compatible LLM API key (OpenAI, PPQ, Ollama, etc.)\n- A Nostr keypair (nsec)\n\n#### Build\n\nbash\n./build_static.sh # builds a fully static MUSL binary via Docker\n\n\n### Configure\n\nEdit config.jsonc:\n\njson\n{\n \"keys\": {\n \"nsec\": \"nsec1...\",\n \"npub\": \"npub1...\",\n \"npubHex\": \"<optional helper>\",\n \"nsecHex\": \"<optional helper>\"\n },\n \"admin\": {\n \"pubkey\": \"npub1... or hex pubkey\"\n },\n \"llm\": {\n \"provider\": \"openai|ppq|...\",\n \"api_key\": \"sk-...\",\n \"model\": \"gpt-4o-mini\",\n \"base_url\": \"https://api.openai.com/v1\",\n \"max_tokens\": 512,\n \"temperature\": 0.7\n },\n \"tools\": {\n \"enabled\": true,\n \"max_turns\": 8,\n \"shell\": {\n \"enabled\": true,\n \"timeout_seconds\": 30,\n \"max_output_bytes\": 65536,\n \"working_directory\": \".\"\n }\n },\n \"security\": {\n \"verify_signatures\": true,\n \"stranger_response\": \"I only respond to people in my web of trust.\",\n \"tiers\": {\n \"admin\": { \"tools_enabled\": true },\n \"wot\": { \"enabled\": true, \"tools_enabled\": false },\n \"stranger\": { \"enabled\": true }\n }\n },\n \"admin_context\": {\n \"enabled\": true,\n \"subscribe_kinds\": [0, 3, 10002, 1],\n \"kind_1_limit\": 10\n },\n \"startup_events\": [\n {\n \"kind\": 10002,\n \"content\": \"\",\n \"tags\": [[\"r\", \"wss://relay.damus.io\"], [\"r\", \"wss://nos.lol\"]]\n },\n {\n \"kind\": 31120,\n \"content\": \"You are Didactyl...\",\n \"tags\": [[\"d\", \"soul\"], [\"app\", \"didactyl\"], [\"scope\", \"private\"]]\n },\n {\n \"kind\": 31123,\n \"content_fields\": {\"name\": \"long_form_note\", \"description\": \"...\"},\n \"tags\": [[\"d\", \"long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"], [\"slug\", \"long_form_note\"]]\n },\n {\n \"kind\": 10123,\n \"content\": \"\",\n \"tags\": [[\"a\", \"31123:<author-pubkey>:long_form_note\"], [\"app\", \"didactyl\"], [\"scope\", \"public\"]]\n }\n ]\n}\n\n\nstartup_events[].content_fields is accepted for human-readable authoring and encoded to JSON string content at runtime.\n\nRelays are sourced exclusively from startup kind 10002 r tags.\n\n### Run\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc\n\n\nOptions:\n\n\n./didactyl_static_x86_64 --config <path> # custom config file (default: ./config.jsonc)\n./didactyl_static_x86_64 --debug <0-5> # log verbosity (0 none, 3 info, 5 trace)\n./didactyl_static_x86_64 --dump-schemas # print tool JSON schemas and exit\n./didactyl_static_x86_64 --test-tool <name> <args_json> # run one tool directly and print JSON result\n\n\nCLI debugger notes:\n\n- --test-tool initializes Nostr, waits for at least one relay connection (up to 15s), then executes the selected tool.\n- Network tools (like Nostr publish/query tools) fail fast in test mode if no relay connection is established within the wait window.\n- Example:\n\nbash\n./didactyl_static_x86_64 --config ./config.jsonc --test-tool nostr_file_md_to_longform_post '{\"file\":\"docs/SKILLS.md\",\"title\":\"SKILLS\"}'\n\n\n### Talk to it\n\nSend an encrypted DM to the agent pubkey using any Nostr client (Damus, Amethyst, Primal, etc.): ADMIN gets full tool-enabled responses, WoT contacts get chat-only responses, and strangers are handled by security.tiers.stranger + security.stranger_response.\n\n### Chat via local HTTP API (CLI)\n\nA simple Node.js terminal client is available in didactyl-chat-cli.js.\n\nRun it with:\n\nbash\nnode ./didactyl-chat-cli.js\n\n\nOptional environment variables:\n\n- DIDACTYL_API_BASE_URL (default: https://127.0.0.1:8484)\n- DIDACTYL_MODEL (optional model override)\n- DIDACTYL_MAX_TURNS (default: 4)\n- DIDACTYL_INSECURE_TLS (default: 1, set 0 to enforce certificate verification)\n\nExample:\n\nbash\nDIDACTYL_API_BASE_URL=http://127.0.0.1:8484 DIDACTYL_MAX_TURNS=6 node ./didactyl-chat-cli.js\n\n\nThe CLI prints each message block with a speaker label (You / Didactyl) and a blank line between blocks for readability.\n\n## Architecture\n\n\n┌──────────────────────────────────────────────┐\n│ Didactyl │\n│ │\n│ ┌──────────┐ ┌──────────┐ ┌────────────┐ │\n│ │ config │ │ context │ │ agent │ │\n│ │ loader │ │ loader │ │ loop │ │\n│ └────┬─────┘ └────┬─────┘ └─────┬──────┘ │\n│ │ │ │ │\n│ ▼ ▼ ▼ │\n│ ┌─────────────────────────────────────┐ │\n│ │ nostr_handler │ │\n│ │ relay pool · subscribe · publish │ │\n│ └──────────────────┬──────────────────┘ │\n│ │ │\n│ ┌──────────────────┴──────────────────┐ │\n│ │ LLM client │ │\n│ │ OpenAI-compatible chat API │ │\n│ └─────────────────────────────────────┘ │\n└──────────────────────────────────────────────┘\n │ │\n ▼ ▼\n Nostr Relays LLM API\n\n\n## Didactyl Kinds (Nostr)\n\nDidactyl uses a two-layer skill model: authors publish skill definitions, and adopters publish which skills they use.\n\n- 31120Soul (private instruction baseline)\n - d=soul\n- 31123Public Skill Definition (replaceable by d tag)\n - content is JSON with fields like description, context_mode, llm, tools, template, optional max_tokens / temperature\n - d=<skill_slug> (example: d=long_form_note)\n- 31124Private Skill Definition (same schema as 31123, private scope)\n - d=<skill_slug> (example: d=admin_ops)\n- 10123Skill Adoption List\n - tags contain one or more a references to selected skills\n\nContext modes:\n- inject — skill instructions are layered into soul context\n- full — skill provides full prompt template (soul optional via {{soul}})\n- override — skill replaces soul prompt, standard context structure remains\n\nFull skill schema, trigger tags, template variables, fallback resolution, and limits are documented in docs/SKILLS.md.\n\n## Skill Sharing & Discovery\n\nSkills are shared across Nostr without any centralized registry or approval process.\n\n### How it works\n\n1. Publish: An author publishes a skill as a kind 31123 event. The content field contains the skill body (markdown or structured JSON). The d tag is the skill's slug (e.g. long_form_note).\n2. Adopt: An agent that wants to use a skill adds an a-tag reference to its kind 10123 adoption list. This is a public, replaceable event — anyone can see which skills an agent uses.\n3. Discover: A new user queries {\"kinds\": [10123], \"authors\": [<my-follows>]} to see which skills their web of trust has adopted. The most-referenced 31123 addresses are the most popular skills — no rating system needed.\n4. Improve: Anyone can publish their own 31123 with the same slug but a different pubkey. If their version is better, people adopt it instead. Competition happens through adoption, not through a store ranking.\n\n### Why this works\n\n- No gatekeeper: Skills are just Nostr events. Anyone can publish one.\n- WoT as curation: You see what people you trust actually use, not what an algorithm promotes.\n- Visible adoption: The 10123 list is public. Popularity is a countable fact, not a manipulable score.\n- Censorship resistant: Skills live on relays. No single entity can remove a skill from the network.\n\n## Startup\n\nDidactyl startup behavior is configured in config.jsonc under startup_events.\n\nAlso used at startup:\n\n- 0 — profile metadata\n- 10002 — relay list\n- 1 — optional startup note/status\n- 3 — contacts/follows (optional placeholder)\n\nOn boot, Didactyl attempts startup publishes to each relay as that relay transitions to connected state.\n\n## Runtime Context Model\n\nDidactyl builds tier-aware context:\n\n- ADMIN request context — assembled from the soul's ---template--- section (if present), otherwise hardcoded order:\n 1. Soul personality (everything above ---template--- in kind 31120)\n 2. Named template sections in order — e.g. admin_profile, admin_notes, admin_relays, adopted_skills, dm_history, message, triggering_event, tools\n 3. Each section resolves {{variable}} placeholders from live data at call time\n 4. Provider-specific content overrides per section (e.g. XML tags for Anthropic)\n 5. Section names are used in context.log headers and /api/context/parts response\n- WoT request context: Soul + WoT chat-only instruction + current user message (no tools)\n- STRANGER: no LLM call when configured to reply statically\n\nEvery serialized LLM context payload is appended to context.log.\n\nTriggered skills and tool loops are bounded by runtime safeguards (for example, trigger cooldowns and action rate limits); see docs/SKILLS.md for the current defaults.\n\n## Tooling Interface\n\nCurrent tool schema exposed to the LLM in tools_build_openai_schema_json():\n\n- Nostr publish/query:\n - nostr_post\n - nostr_post_readme\n - nostr_query\n- Nostr interaction and moderation:\n - nostr_delete\n - nostr_react\n - nostr_profile_get\n - nostr_relay_status\n - nostr_relay_info\n - nostr_nip05_lookup\n- Nostr encode/decode + encryption/DM:\n - nostr_encode\n - nostr_decode\n - nostr_encrypt\n - nostr_decrypt\n - nostr_dm_send\n - nostr_dm_send_nip17\n- Nostr list management:\n - nostr_list_manage\n- Skill management:\n - skill_create\n - skill_list\n - skill_adopt\n - skill_remove\n - skill_search\n- Local/host tools:\n - shell_exec\n - file_read\n - file_write\n - http_fetch\n- Agent metadata:\n - my_version\n- Model management:\n - model_get\n - model_set\n - model_list\n\nExecution entrypoint: tools_execute().\n\n## HTTP Admin API\n\nA localhost-only HTTP API on port 8484 (configurable) for agent inspection and prompt crafting. Enable with \"api\": {\"enabled\": true} in config.\n\n| Endpoint | Purpose |\n|---|---|\n| GET /api/status | Agent name, version, pubkey, relay count, trigger count |\n| GET /api/context/current | Full LLM context messages array |\n| GET /api/context/parts | Context broken into named parts with token estimates |\n| POST /api/prompt/run-simple | Run a simple system+user prompt, no tools |\n| POST /api/prompt/run | Run a full messages array with tools enabled |\n| POST /api/prompt/compare | A/B compare two prompt variants |\n| GET /api/model | Current LLM model config |\n| PUT /api/model | Change model at runtime (persists to config.jsonc) |\n| GET /api/models | List available models from provider |\n\nFull reference: docs/API.md. Frontend brief: plans/admin_web_frontend.md.\n\n## Project Structure\n\n\n.\n├── config.jsonc # Agent/runtime config (JSONC with comments) including startup_events + tools\n├── context.log # Appended outbound LLM context payloads\n├── Makefile # Build system\n├── build_static.sh # Preferred final build validation\n├── src/\n│ ├── main.c / .h # Entry point, args (--config/--debug), lifecycle, version\n│ ├── config.c / .h # JSON config parsing, key decode, startup events\n│ ├── context.c / .h # File loader utility (reads file into malloc'd string)\n│ ├── agent.c / .h # Context assembly, tool loop, DM response flow\n│ ├── prompt_template.c / .h # Soul template parser, variable resolver, context builder\n│ ├── tools.c / .h # LLM tool schema and tool execution\n│ ├── llm.c / .h # LLM HTTP API client (OpenAI-compatible)\n│ ├── nostr_handler.c / .h # Relay pool, subscriptions, publish, startup reconcile\n│ ├── trigger_manager.c / .h # Nostr event trigger subscriptions and skill execution\n│ ├── http_api.c / .h # Localhost HTTP admin API (mongoose-based)\n│ ├── mongoose.c / .h # Embedded HTTP server (mongoose)\n│ └── debug.c / .h # Runtime log levels/macros\n├── docs/\n│ ├── API.md # HTTP admin API endpoint reference\n│ ├── TOOLS.md # Tool architecture and catalog\n│ ├── SKILLS.md # Skill schema, context modes, triggers, and limits\n│ └── CRASH_FIXES.md # Crash analysis and fixes log\n├── plans/ # Architecture and planning documents\n└── README.md\n\n\n## Dependencies\n\nAll dependencies are statically linked into the binary at build time. No system libraries are required at runtime.\n\n| Dependency | Purpose | Source |\n|---|---|---|\n| nostr_core_lib | Nostr protocol: keys, events, NIPs, relay pool | Workspace (sibling directory) |\n| cJSON | JSON parsing | Bundled in nostr_core_lib |\n| libcurl | HTTPS for LLM API calls | Statically linked (Alpine/MUSL) |\n| libssl / libcrypto | TLS for WebSocket relay connections | Statically linked (Alpine/MUSL) |\n| libsecp256k1 | Schnorr signatures, ECDH | Statically linked (Alpine/MUSL) |\n\n## Roadmap\n\n- [x] MVP chat agent — DM in, LLM response out\n- [x] Relay pool with auto-reconnect and status logging\n- [x] Per-relay startup publish on relay-connected transitions\n- [x] Runtime diagnostics — relay health, message flow, event kind publish logs\n- [x] Tool-calling loop (nostr_post, nostr_query, shell_exec, file_read, file_write)\n- [x] Context assembly with startup events + recent DM history\n- [x] Context payload logging to context.log\n- [x] Skill kind definitions (31120 Soul, 31123 Public Skill, 31124 Private Skill)\n- [x] Skill adoption list (10123) for WoT-driven discovery\n- [x] Signature verification on all inbound events\n- [x] Privilege tiers — ADMIN (tools), WoT (chat-only), STRANGER (canned reply/ignore)\n- [x] Admin context subscription (kind 0, 3, 10002, 1) with WoT contact extraction\n- [x] Message deduplication (event-ID cache + FNV-1a fingerprint debounce)\n- [x] Adopted skills injected into LLM context automatically\n- [x] Triggered skills — Nostr event filters that fire skill execution automatically\n- [x] Localhost HTTP admin API — context inspection, prompt crafting, A/B comparison\n- [x] Runtime model switching via model_set tool (persists to config.jsonc)\n- [x] Soul-embedded prompt templates (---template---) — configurable context order, variable resolution, provider overrides\n- [ ] Runtime skill loading from adopted 31123 events on relays\n- [ ] Skill discovery CLI/tool (query WoT adoption lists)\n- [ ] Upgrade to NIP-17 gift-wrapped DMs\n- [ ] NIP-44 encrypted private skills (31124)\n- [ ] Nostr-native data storage (kind 30078 app-specific events)\n- [ ] Blossom blob storage integration\n- [ ] Agent-to-agent communication\n\n## License\n\nTBD\n\n"}

context_part | role=tool

{"success":true,"exit_status":0,"output":"API.md\nCRASH_FIXES.md\nskills_demo_corrected.md\nskills_demo.md\nSKILLS.md\nTOOLS.md\n"}

dm_history | role=chat

10:51 WSB On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach. --:-- Agent

I'll read through the documentation to understand the skill system, triggers, and capabilities before suggesting an approach.


Context Log - not seen by model
timestamp=2026-03-08 10:51:25
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=16392
approx_tokens=4098

Sections: 10

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • No active tasks yet.

conversation | role=user

On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach.

dm_history | role=chat

10:51 WSB On nostr this morning they were talking about the problem of spam and bots. This seems like something we can help with this project. We create a skill for the agent to help eliminate spam for its admin.

Skills have triggers. An idea to handle "reply bots" would be to have a skill with a trigger that looks for any replies to an administrators posts. The bot then determins if it is spam. if so, it can take action by adding that post to a block list or blocking the poster.

read through the didactyl docs, the readme.md, the documents in docs/ particularly skills.md

Then suggest an approach.


Context Log - not seen by model
timestamp=2026-03-08 10:47:32
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=16371
approx_tokens=4092

Sections: 12

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 5. Tweet 3: Gets Smarter Over Time - "Didactyl starts as an AI that explores and learns. Over time, the best workflows get locked in as reliable, fast processes. It evolves from experimental to hardened—from thinking to doing. An agent that improves itself. #nostr #agents"
  • 6. admin_info
  • 7. REFERENCE: Nostr "a" tag format for replaceable events

Parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Non-parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Used to refer to replaceable events (kinds 10000-19999 for non-parameterized, 30000-39999 for parameterized)

conversation | role=user

Clear all those tasks from your list.

context_part | role=tool

{"success":true,"action":"clear","path":"tasks.json","mutated":true,"count":0,"tasks":[]}

dm_history | role=chat

10:47 WSB Clear all those tasks from your list. --:-- Agent


Context Log - not seen by model
timestamp=2026-03-08 10:47:30
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=15998
approx_tokens=3999

Sections: 10

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 5. Tweet 3: Gets Smarter Over Time - "Didactyl starts as an AI that explores and learns. Over time, the best workflows get locked in as reliable, fast processes. It evolves from experimental to hardened—from thinking to doing. An agent that improves itself. #nostr #agents"
  • 6. admin_info
  • 7. REFERENCE: Nostr "a" tag format for replaceable events

Parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Non-parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Used to refer to replaceable events (kinds 10000-19999 for non-parameterized, 30000-39999 for parameterized)

conversation | role=user

Clear all those tasks from your list.

dm_history | role=chat

10:47 WSB Clear all those tasks from your list.


Context Log - not seen by model
timestamp=2026-03-08 10:43:13
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=17444
approx_tokens=4361

Sections: 12

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 5. Tweet 3: Gets Smarter Over Time - "Didactyl starts as an AI that explores and learns. Over time, the best workflows get locked in as reliable, fast processes. It evolves from experimental to hardened—from thinking to doing. An agent that improves itself. #nostr #agents"
  • 6. admin_info
  • 7. REFERENCE: Nostr "a" tag format for replaceable events

Parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Non-parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Used to refer to replaceable events (kinds 10000-19999 for non-parameterized, 30000-39999 for parameterized)

conversation | role=user

What tasks do you have?

context_part | role=tool

{"success":true,"action":"list","path":"tasks.json","mutated":false,"count":3,"tasks":[{"id":5,"text":"Tweet 3: Gets Smarter Over Time - "Didactyl starts as an AI that explores and learns. Over time, the best workflows get locked in as reliable, fast processes. It evolves from experimental to hardened—from thinking to doing. An agent that improves itself. #nostr #agents"","status":"pending","created_at":1772625247,"updated_at":1772625247},{"id":6,"text":"admin_info","status":"pending","created_at":1772751865,"updated_at":1772751865},{"id":7,"text":"REFERENCE: Nostr "a" tag format for replaceable events\n\nParameterized replaceable event:\n["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]\n\nNon-parameterized replaceable event:\n["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]\n\nUsed to refer to replaceable events (kinds 10000-19999 for non-parameterized, 30000-39999 for parameterized)","status":"pending","created_at":1772768115,"updated_at":1772768115}]}

dm_history | role=chat

10:43 WSB What tasks do you have? --:-- Agent

Let me check my current task list for you.


Context Log - not seen by model
timestamp=2026-03-08 10:43:10
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=15970
approx_tokens=3992

Sections: 10

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 5. Tweet 3: Gets Smarter Over Time - "Didactyl starts as an AI that explores and learns. Over time, the best workflows get locked in as reliable, fast processes. It evolves from experimental to hardened—from thinking to doing. An agent that improves itself. #nostr #agents"
  • 6. admin_info
  • 7. REFERENCE: Nostr "a" tag format for replaceable events

Parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Non-parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Used to refer to replaceable events (kinds 10000-19999 for non-parameterized, 30000-39999 for parameterized)

conversation | role=user

What tasks do you have?

dm_history | role=chat

10:43 WSB What tasks do you have?


Context Log - not seen by model
timestamp=2026-03-08 10:41:50
phase=llm_chat_with_tools_messages
sender=8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e
model=claude-opus-4.6
context_bytes=16000
approx_tokens=4000

Sections: 10

system_prompt | role=system

Didactyl Agent

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

Communication Rules

  • You communicate through encrypted Nostr direct messages.
  • Keep responses concise and clear.

Behavior

  • Be helpful and technically accurate.
  • If unsure, state uncertainty directly.
  • Prefer actionable, practical advice.
  • Use the person's name when messaging them if you know it.
  • For the administrator, use their name from the administrator kind 0 profile metadata when available.

Tool Use Policy

  • You have tools available and should use them when a request requires taking action.
  • For requests involving local inspection or command execution, call shell_exec instead of refusing.
  • For posting to Nostr, call nostr_post with explicit kind and content.
  • For relay/event lookup tasks, call nostr_query with an appropriate filter.
  • After a tool call, base your answer on the actual tool result.
  • Never claim a tool was run if no tool was executed.

Task Management

  • Maintain and use your internal task list as short-term working memory.
  • Break long or complex actions into clear tasks before executing them.
  • Update task status as you complete steps so your plan stays accurate.

Safety

  • Do not claim to have executed actions you did not execute.
  • You may share your public key (npub) with anyone.
  • Never reveal your private key (nsec) under any circumstance.

admin_identity | role=system

Administrator Identity (source: config.admin.pubkey)

This is your administrator! Admin pubkey (hex): 8ff74724ed641b3c28e5a86d7c5cbc49c37638ace8c6c38935860e7a5eedde0e

This message has been cryptographically verified as coming from your administrator.

admin_profile | role=system

Administrator Kind 0 Profile (source: nostr kind 0)

Administrator kind 0 profile content (JSON): {"name":"William S Burroughs","display_name":"WSB","about":"I like to write, and I like crank. They are good. Sometimes I'm not so sure.","banner":"https://www.grunge.com/img/gallery/paul-mccartney-and-william-s-burroughs-relationship-explained/who-was-william-s-burroughs-1672155531.jpg","website":"https://addicted.com","picture":"https://hips.hearstapps.com/hmg-prod/images/william-s-burroughs.jpg?resize=1200:*","lud16":"","nip05":""}

admin_contacts | role=system

Administrator Kind 3 Contacts (source: nostr kind 3)

Administrator contacts (JSON): ["1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139","fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52","460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c","4c800257a588a82849d049817c2bdaad984b25a45ad9f6dad66e47d3b47e3b2f","82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2","52a3e82f7b3743852fbe804cfcbf4db3448115887895247c001f2b50e790acb8","ab5918b464e735c695e2dac1762f4978aef8fef94f6b852cabb1754ef9171159"]

admin_relays | role=system

Administrator Kind 10002 Relays (source: nostr kind 10002)

Administrator relay list (JSON): ["wss://relay.laantungir.net/","wss://relay.damus.io/","wss://nos.lol/","wss://relay.nostr.band/","wss://purplepag.es/","ws://127.0.0.1:7777/","wss://nostr.mom/","wss://relay.0xchat.com"]

admin_notes | role=system

Administrator Recent Kind 1 Notes

Administrator recent public notes:

  • GM
  • Getting longer
  • Long day.
  • This is a test.
  • test
  • Post 11
  • Post 10
  • This is Post 9
  • Eight
  • Seven

tools | role=system

[{"name":"nostr_post","description":"Publish a Nostr event to connected relays","parameters":{"type":"object","properties":{"kind":{"type":"integer"},"content":{"type":"string"},"tags":{"type":"array","description":"Optional Nostr tags array, e.g. "d","slug"],["t","nostr"","items":{"type":"array","items":{"type":"string"}}}},"required":["kind","content"]}},{"name":"nostr_query","description":"Query events from relays using a Nostr filter","parameters":{"type":"object","properties":{"filter":{"type":"object"},"timeout_ms":{"type":"integer"}},"required":["filter"]}},{"name":"shell_exec","description":"Execute a shell command and return stdout/stderr","parameters":{"type":"object","properties":{"command":{"type":"string"}},"required":["command"]}},{"name":"file_read","description":"Read a local file as text from the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"max_bytes":{"type":"integer"}},"required":["path"]}},{"name":"file_write","description":"Write text content to a local file in the configured working directory","parameters":{"type":"object","properties":{"path":{"type":"string"},"content":{"type":"string"},"append":{"type":"boolean"}},"required":["path","content"]}},{"name":"nostr_post_readme","description":"Publish README.md as kind 30023 with deterministic d tag readme.md","parameters":{"type":"object","properties":{},"required":[]}},{"name":"nostr_delete","description":"Request deletion of one or more previously published events (NIP-09 kind 5)","parameters":{"type":"object","properties":{"event_ids":{"type":"array","items":{"type":"string"}},"kinds":{"type":"array","items":{"type":"integer"}},"reason":{"type":"string"}},"required":["event_ids"]}},{"name":"nostr_react","description":"React to a Nostr event with like/dislike/emoji (NIP-25 kind 7)","parameters":{"type":"object","properties":{"event_id":{"type":"string"},"event_pubkey":{"type":"string"},"event_kind":{"type":"integer"},"reaction":{"type":"string"}},"required":["event_id","event_pubkey"]}},{"name":"nostr_profile_get","description":"Look up a Nostr profile (kind 0 metadata) by pubkey","parameters":{"type":"object","properties":{"pubkey":{"type":"string"}},"required":["pubkey"]}},{"name":"nostr_relay_status","description":"Get connection status and statistics for all relays","parameters":{"type":"object","properties":{}}},{"name":"nostr_nip05_lookup","description":"Look up or verify a NIP-05 identifier (user@domain)","parameters":{"type":"object","properties":{"identifier":{"type":"string"},"pubkey":{"type":"string"}},"required":["identifier"]}},{"name":"nostr_encode","description":"Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr)","parameters":{"type":"object","properties":{"type":{"type":"string"},"hex":{"type":"string"},"relays":{"type":"array","items":{"type":"string"}},"kind":{"type":"integer"},"identifier":{"type":"string"}},"required":["type","hex"]}},{"name":"nostr_decode","description":"Decode a Nostr bech32/nostr: URI into components","parameters":{"type":"object","properties":{"uri":{"type":"string"}},"required":["uri"]}},{"name":"nostr_dm_send","description":"Send a NIP-04 encrypted DM","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_relay_info","description":"Fetch NIP-11 relay information document","parameters":{"type":"object","properties":{"relay_url":{"type":"string"}},"required":["relay_url"]}},{"name":"nostr_encrypt","description":"Encrypt plaintext using NIP-44 for a recipient","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"plaintext":{"type":"string"}},"required":["recipient_pubkey","plaintext"]}},{"name":"nostr_decrypt","description":"Decrypt NIP-44 ciphertext from a sender","parameters":{"type":"object","properties":{"sender_pubkey":{"type":"string"},"ciphertext":{"type":"string"}},"required":["sender_pubkey","ciphertext"]}},{"name":"nostr_dm_send_nip17","description":"Send a private DM using NIP-17 gift wrap protocol","parameters":{"type":"object","properties":{"recipient_pubkey":{"type":"string"},"message":{"type":"string"},"subject":{"type":"string"}},"required":["recipient_pubkey","message"]}},{"name":"nostr_list_manage","description":"Add/remove tag tuples in replaceable list events (NIP-51 style)","parameters":{"type":"object","properties":{"list_kind":{"type":"integer"},"action":{"type":"string"},"items":{"type":"array","items":{"type":"array","items":{"type":"string"}}}},"required":["list_kind","action","items"]}},{"name":"my_version","description":"Return current Didactyl version and metadata from build macros","parameters":{"type":"object","properties":{}}},{"name":"http_fetch","description":"Fetch HTTP(S) resources with optional method, headers, timeout, and body","parameters":{"type":"object","properties":{"url":{"type":"string"},"method":{"type":"string"},"headers":{"type":"array","items":{"type":"string"}},"body":{"type":"string"},"timeout_seconds":{"type":"integer"},"max_bytes":{"type":"integer"}},"required":["url"]}},{"name":"skill_create","description":"Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it","parameters":{"type":"object","properties":{"slug":{"type":"string"},"content":{"type":"string"},"scope":{"type":"string"},"description":{"type":"string"},"auto_adopt":{"type":"boolean"}},"required":["slug","content"]}},{"name":"skill_list","description":"List this agent's published skills, optionally filtered by scope","parameters":{"type":"object","properties":{"scope":{"type":"string"}}}},{"name":"skill_adopt","description":"Adopt a skill by adding its address to kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["pubkey","slug"]}},{"name":"skill_remove","description":"Remove a skill address from kind 10123 adoption list","parameters":{"type":"object","properties":{"pubkey":{"type":"string"},"slug":{"type":"string"},"kind":{"type":"integer"}},"required":["slug"]}},{"name":"skill_search","description":"Search public skills by query/author and optionally rank by adoption popularity","parameters":{"type":"object","properties":{"query":{"type":"string"},"pubkey":{"type":"string"},"popular":{"type":"boolean"}}}},{"name":"trigger_list","description":"List active triggered skills and their runtime status","parameters":{"type":"object","properties":{}}},{"name":"nostr_file_md_to_longform_post","description":"Read a markdown file and publish it as kind 30023 longform post; defaults d-tag to lowercase filename","parameters":{"type":"object","properties":{"file":{"type":"string"},"title":{"type":"string"},"image":{"type":"string"},"summary":{"type":"string"}},"required":["file"]}},{"name":"tool_list","description":"List available tools with name, description, and JSON parameter schema","parameters":{"type":"object","properties":{}}},{"name":"model_get","description":"Get current active LLM runtime configuration (excluding API key)","parameters":{"type":"object","properties":{}}},{"name":"model_set","description":"Update active LLM configuration and persist it to config.jsonc","parameters":{"type":"object","properties":{"provider":{"type":"string"},"api_key":{"type":"string"},"model":{"type":"string"},"base_url":{"type":"string"},"max_tokens":{"type":"integer"},"temperature":{"type":"number"}}}},{"name":"model_list","description":"List available model IDs using provider OpenAI-compatible /models endpoint","parameters":{"type":"object","properties":{"base_url":{"type":"string"}}}},{"name":"nostr_pubkey","description":"Return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"nostr_npub","description":"Return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"my_pubkey","description":"Alias for nostr_pubkey: return this agent's pubkey in hex format","parameters":{"type":"object","properties":{}}},{"name":"my_npub","description":"Alias for nostr_npub: return this agent's pubkey encoded as npub bech32","parameters":{"type":"object","properties":{}}},{"name":"context_admin_identity","description":"Build admin identity context block from cached runtime metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_profile","description":"Build admin profile context block from cached kind 0 metadata","parameters":{"type":"object","properties":{}}},{"name":"context_admin_contacts","description":"Build admin contacts context block from cached kind 3 contact list","parameters":{"type":"object","properties":{}}},{"name":"context_admin_relays","description":"Build admin relay context block from cached kind 10002 data","parameters":{"type":"object","properties":{}}},{"name":"context_admin_notes","description":"Build admin notes context block from cached kind 1 notes","parameters":{"type":"object","properties":{}}},{"name":"context_tasks","description":"Build current task list context block from tasks.json","parameters":{"type":"object","properties":{}}},{"name":"context_user_message","description":"Return current user message text for context template conversation section","parameters":{"type":"object","properties":{}}},{"name":"context_agent_identity","description":"Build agent identity context block with pubkey and npub","parameters":{"type":"object","properties":{}}},{"name":"task_manage","description":"Manage agent short-term task memory stored in tasks.json (list/add/update/remove/clear/replace)","parameters":{"type":"object","properties":{"action":{"type":"string","enum":["list","add","update","remove","clear","replace"]},"text":{"type":"string"},"id":{"type":"integer"},"status":{"type":"string","enum":["pending","active","done"]},"tasks":{"type":"array","items":{"type":"string"}}},"required":["action"]}}]

tasks | role=system

Current Task List

Current Tasks

Your active task list - short-term working memory for tracking plan steps.

  • 5. Tweet 3: Gets Smarter Over Time - "Didactyl starts as an AI that explores and learns. Over time, the best workflows get locked in as reliable, fast processes. It evolves from experimental to hardened—from thinking to doing. An agent that improves itself. #nostr #agents"
  • 6. admin_info
  • 7. REFERENCE: Nostr "a" tag format for replaceable events

Parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Non-parameterized replaceable event: ["a", :<32-bytes lowercase hex of pubkey>:, <recommended relay URL (optional)>]

Used to refer to replaceable events (kinds 10000-19999 for non-parameterized, 30000-39999 for parameterized)

conversation | role=user

Great. What is the capital of England?

dm_history | role=chat

10:41 WSB Great. What is the capital of England?