19 KiB
Didactyl — Tools
See also: SKILLS.md · CONTEXT.md
Overview
Didactyl is a Nostr-first sovereign AI agent that reasons with an LLM and takes actions through tools.
This 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.
What Tools Are
Tools are in the agent's hands — the chisels in the woodshop. They are hardcoded C functions that the LLM can invoke during a conversation to take actions in the world.
A skill teaches the agent how to carve — the technique, the judgment, the decision-making. A tool is the chisel — the physical capability. The skill never directly uses the chisel without the craftsperson (the LLM) in the loop. If you want a hardcoded program that runs without reasoning, that's a tool or an external program — not a skill.
How Tools Work
- A trigger fires (DM, cron, subscription, webhook, or chain) — see SKILLS.md
- The agent builds the context window from triggered skills and their
{{...}}references - The agent builds an LLM request with the context, triggering event, and a JSON schema of available tools
- The LLM decides whether to call a tool or respond directly
- If a tool is called, didactyl executes it and feeds the result back to the LLM
- The loop repeats until the LLM produces a final text response
- For DM triggers, the response is sent back as a DM
Trigger fires (DM, cron, subscription, webhook, chain)
│
├─ Build context from triggered skills
├─ Build tool schemas (filtered by skill's tools tag)
│
├─ Send to LLM: context + tool schemas
│
│ ┌─────────────────────────────────────┐
│ │ LLM reasons about the request │
│ │ │
│ │ Option A: call a tool │
│ │ → agent executes tool │
│ │ → feeds result back to LLM │
│ │ → loop continues │
│ │ │
│ │ Option B: produce text response │
│ │ → loop ends │
│ └─────────────────────────────────────┘
│
└─ Deliver response (DM reply, chain forward, etc.)
Tool Categories
Nostr Event & Messaging Tools
| Tool | Description |
|---|---|
nostr_post |
Publish a Nostr event to connected relays |
nostr_delete |
Request deletion of one or more previously published events (NIP-09 kind 5) |
nostr_react |
React to a Nostr event with like/dislike/emoji (NIP-25 kind 7) |
nostr_query |
Query events from relays using a Nostr filter |
nostr_my_events |
Query recent events authored by this agent and return kind, event_id, timestamp, d_tag, and cache presence |
nostr_dm_send |
Send a NIP-04 encrypted DM |
nostr_dm_send_nip17 |
Send a private DM using NIP-17 gift wrap protocol |
Nostr Identity & Utility Tools
| Tool | Description |
|---|---|
nostr_profile_get |
Look up a Nostr profile (kind 0 metadata) by pubkey |
nostr_nip05_lookup |
Look up or verify a NIP-05 identifier (user@domain) |
nostr_encode |
Encode a Nostr entity into nostr: URI (npub, note, nprofile, nevent, naddr) |
nostr_decode |
Decode a Nostr bech32/nostr: URI into components |
nostr_relay_status |
Get connection status and statistics for all relays |
nostr_relay_info |
Fetch NIP-11 relay information document |
nostr_subscription_status |
List currently managed runtime Nostr subscriptions and filters |
nostr_subscription_set |
Update one managed runtime subscription by name (toggle enabled and/or replace filter) |
nostr_encrypt |
Encrypt plaintext using NIP-44 for a recipient |
nostr_decrypt |
Decrypt NIP-44 ciphertext from a sender |
nostr_list_manage |
Add/remove tag tuples in replaceable list events (NIP-51 style) |
nostr_block_list |
View blocked pubkeys, event IDs, or hashtags from the local encrypted kind-10000 block list cache |
nostr_block_edit |
Add or remove blocked tuples in kind-10000 block list; entries are private (encrypted) by default |
Context & Identity Tools
These tools provide the agent with information about itself and its administrator, often used to build system prompts or context blocks.
| Tool | Description |
|---|---|
nostr_pubkey |
Return this agent's pubkey in hex format |
nostr_npub |
Return this agent's pubkey encoded as npub bech32 |
my_pubkey |
Alias for nostr_pubkey |
my_npub |
Alias for nostr_npub |
agent_identity |
Build agent identity context block with pubkey and npub |
admin_identity |
Build admin identity context block from cached runtime metadata |
nostr_admin_profile |
Build admin profile context block from cached kind 0 metadata |
nostr_admin_contacts |
Build admin contacts context block from cached kind 3 contact list |
nostr_admin_relays |
Build admin relay context block from cached kind 10002 data |
nostr_admin_notes |
Build admin notes context block from cached kind 1 notes |
nostr_agent_profile |
Build agent profile context block from cached kind 0 metadata |
nostr_agent_contacts |
Build agent contacts context block from cached kind 3 contact list |
nostr_agent_relays |
Build agent relay context block from cached kind 10002 data |
nostr_agent_notes |
Build agent notes context block from cached kind 1 notes |
my_kind0_profile |
Alias for nostr_agent_profile |
my_contacts |
Alias for nostr_agent_contacts |
my_relays |
Alias for nostr_agent_relays |
my_notes |
Alias for nostr_agent_notes |
Skills & Trigger Tools
These tools manage skill and trigger lifecycle; skill semantics and trigger execution details are documented in SKILLS.md.
| Tool | Description |
|---|---|
skill_create |
Create or update a skill definition as kind 31123/31124 and optionally auto-adopt it |
skill_edit |
Edit an existing self skill by d tag and republish it as kind 31123/31124 |
skill_list |
List available skills discovered online (agent + admin), with adoption status and optional filters |
skill_adopt |
Adopt a skill by adding its address to kind 10123 adoption list |
skill_remove |
Remove a skill address from kind 10123 adoption list |
skill_search |
Search public skills by query/author and optionally rank by adoption popularity |
trigger_list |
List active triggered skills and their runtime status |
Task & Memory Tools
These tools manage the agent's short-term and long-term memory, persisted on Nostr.
| Tool | Description |
|---|---|
task_list |
Build current task list context block from agent task memory on Nostr |
task_manage |
Manage agent short-term task memory stored on Nostr kind 30078 (d=tasks): list/add/update/remove/clear/replace |
memory_save |
Prepend a new entry to encrypted agent memory (kind 30078, d=memory) and truncate oldest content if needed |
memory_recall |
Recall encrypted agent memory (kind 30078, d=memory) |
LLM / Model Management Tools
| Tool | Description |
|---|---|
model_get |
Get current active LLM runtime configuration (excluding API key) |
model_set |
Update active LLM configuration and persist it to Nostr kind 30078 (d=llm_config) |
model_list |
List available model IDs using provider OpenAI-compatible /models endpoint |
Configuration Persistence Tools
| Tool | Description |
|---|---|
config_store |
Encrypt and publish agent config as kind 30078 for a given d_tag |
config_recall |
Fetch and decrypt agent config kind 30078 by d_tag |
System & Runtime Tools
| Tool | Description |
|---|---|
agent_version |
Return current Didactyl version and metadata from build macros |
local_http_fetch |
Fetch HTTP(S) resources with optional method, headers, timeout, and body |
local_shell_exec |
Execute a shell command and return stdout/stderr |
local_file_read |
Read a local file as text from the configured working directory |
local_file_write |
Write text content to a local file in the configured working directory |
tool_list |
List available tools with name, description, and JSON parameter schema |
Cashu Wallet Tools (NIP-60)
| Tool | Description |
|---|---|
cashu_wallet_balance |
Return wallet balances aggregated by mint and unit from loaded token proofs |
cashu_wallet_info |
Fetch mint info for a specific mint_url (or configured default mint) |
cashu_wallet_mint_quote |
Request a mint quote for an amount and unit |
cashu_wallet_mint_check |
Check whether a mint quote is paid/issued |
cashu_wallet_mint_claim |
Claim newly minted proofs for a paid quote and persist token event |
cashu_wallet_melt_quote |
Request a melt quote for a Lightning invoice/payment request |
cashu_wallet_melt_pay |
Pay a melt quote using selected proofs and persist history/token rollover |
cashu_wallet_check_proofs |
Ask mint for current proof states and summarize unspent/pending/spent proofs |
cashu_wallet_receive_token |
Receive an ecash token string (cashuA/cashuB), swap to fresh proofs, and store it in wallet state |
cashu_wallet_send_token |
Create an outbound ecash token from wallet proofs and return a cashuA/cashuB token string |
cashu_wallet_mints_set |
Set wallet mints (NIP-60), public mints (NIP-61), or both |
Blossom Tools
| Tool | Description |
|---|---|
blossom_upload |
Upload a local file to a Blossom server and return blob metadata |
blossom_download |
Download a Blossom blob to a local file path |
blossom_head |
Fetch Blossom blob metadata by SHA-256 |
blossom_delete |
Delete a Blossom blob by SHA-256 using signed auth |
blossom_list |
List Blossom blobs for a pubkey (defaults to agent pubkey) |
Content Publishing Conveniences
| Tool | Description |
|---|---|
nostr_post_readme |
Publish README.md as kind 30023 with deterministic d-tag readme.md |
nostr_file_md_to_longform_post |
Read a markdown file and publish it as kind 30023 longform post (defaults d-tag to lowercase filename) |
Tool Execution Examples
These examples show the JSON structure for tool calls.
Nostr Event & Messaging
nostr_post
{
"name": "nostr_post",
"arguments": {
"kind": 1,
"content": "Hello from Didactyl!",
"tags": [["t", "didactyl"]]
}
}
nostr_delete
{
"name": "nostr_delete",
"arguments": {
"event_ids": ["<event_id_hex>"],
"reason": "Mistake"
}
}
nostr_react
{
"name": "nostr_react",
"arguments": {
"event_id": "<event_id_hex>",
"event_pubkey": "<pubkey_hex>",
"reaction": "🤙"
}
}
nostr_query
{
"name": "nostr_query",
"arguments": {
"filter": {
"kinds": [1],
"limit": 5
},
"timeout_ms": 5000
}
}
nostr_my_events
{
"name": "nostr_my_events",
"arguments": {
"kind": 1,
"limit": 10
}
}
nostr_dm_send
{
"name": "nostr_dm_send",
"arguments": {
"recipient_pubkey": "<pubkey_hex>",
"message": "Secret message"
}
}
nostr_dm_send_nip17
{
"name": "nostr_dm_send_nip17",
"arguments": {
"recipient_pubkey": "<pubkey_hex>",
"message": "Private message via NIP-17",
"subject": "Confidential"
}
}
Nostr Identity & Utility
nostr_profile_get
{
"name": "nostr_profile_get",
"arguments": {
"pubkey": "<pubkey_hex>"
}
}
nostr_nip05_lookup
{
"name": "nostr_nip05_lookup",
"arguments": {
"identifier": "user@domain.com"
}
}
nostr_encode
{
"name": "nostr_encode",
"arguments": {
"type": "npub",
"hex": "<pubkey_hex>"
}
}
nostr_decode
{
"name": "nostr_decode",
"arguments": {
"uri": "nostr:npub1..."
}
}
nostr_relay_status
{
"name": "nostr_relay_status",
"arguments": {}
}
nostr_relay_info
{
"name": "nostr_relay_info",
"arguments": {
"relay_url": "wss://relay.damus.io"
}
}
nostr_subscription_status
{
"name": "nostr_subscription_status",
"arguments": {}
}
nostr_subscription_set
{
"name": "nostr_subscription_set",
"arguments": {
"name": "admin_context_profile",
"enabled": true
}
}
nostr_encrypt
{
"name": "nostr_encrypt",
"arguments": {
"recipient_pubkey": "<pubkey_hex>",
"plaintext": "Sensitive data"
}
}
nostr_decrypt
{
"name": "nostr_decrypt",
"arguments": {
"sender_pubkey": "<pubkey_hex>",
"ciphertext": "<nip44_ciphertext>"
}
}
nostr_list_manage
{
"name": "nostr_list_manage",
"arguments": {
"list_kind": 10000,
"action": "add",
"items": [["p", "<pubkey_hex>"]]
}
}
nostr_block_list
{
"name": "nostr_block_list",
"arguments": {
"type": "p"
}
}
nostr_block_edit
{
"name": "nostr_block_edit",
"arguments": {
"action": "add",
"items": [["p", "<pubkey_hex>"]],
"public": false
}
}
Context & Identity
nostr_pubkey / my_pubkey
{
"name": "nostr_pubkey",
"arguments": {}
}
agent_identity
{
"name": "agent_identity",
"arguments": {}
}
admin_identity
{
"name": "admin_identity",
"arguments": {}
}
nostr_admin_profile
{
"name": "nostr_admin_profile",
"arguments": {}
}
nostr_agent_notes / my_notes
{
"name": "my_notes",
"arguments": {}
}
Skills & Triggers
skill_create
{
"name": "skill_create",
"arguments": {
"d": "weather-skill",
"content": "I can tell you the weather.",
"description": "Fetches weather data",
"auto_adopt": true
}
}
skill_edit
{
"name": "skill_edit",
"arguments": {
"d": "weather-skill",
"description": "Updated weather skill description"
}
}
skill_list
{
"name": "skill_list",
"arguments": {
"adopted": true
}
}
skill_adopt
{
"name": "skill_adopt",
"arguments": {
"pubkey": "<author_pubkey_hex>",
"d": "cool-skill"
}
}
skill_search
{
"name": "skill_search",
"arguments": {
"query": "bitcoin",
"popular": true
}
}
trigger_list
{
"name": "trigger_list",
"arguments": {}
}
Tasks & Memory
task_list
{
"name": "task_list",
"arguments": {}
}
task_manage
{
"name": "task_manage",
"arguments": {
"action": "add",
"text": "Finish documentation",
"status": "active"
}
}
memory_save
{
"name": "memory_save",
"arguments": {
"content": "User likes coffee."
}
}
memory_recall
{
"name": "memory_recall",
"arguments": {}
}
LLM & Configuration
model_get
{
"name": "model_get",
"arguments": {}
}
model_set
{
"name": "model_set",
"arguments": {
"model": "gpt-4o",
"temperature": 0.7
}
}
config_store
{
"name": "config_store",
"arguments": {
"d_tag": "custom_setting",
"content": "{\"value\": 42}"
}
}
config_recall
{
"name": "config_recall",
"arguments": {
"d_tag": "custom_setting"
}
}
System & Runtime
agent_version
{
"name": "agent_version",
"arguments": {}
}
local_http_fetch
{
"name": "local_http_fetch",
"arguments": {
"url": "https://api.github.com/zen",
"method": "GET"
}
}
local_shell_exec
{
"name": "local_shell_exec",
"arguments": {
"command": "ls -la"
}
}
local_file_read
{
"name": "local_file_read",
"arguments": {
"path": "README.md"
}
}
local_file_write
{
"name": "local_file_write",
"arguments": {
"path": "test.txt",
"content": "Hello world",
"append": false
}
}
tool_list
{
"name": "tool_list",
"arguments": {}
}
Cashu Wallet
cashu_wallet_balance
{
"name": "cashu_wallet_balance",
"arguments": {}
}
cashu_wallet_mint_quote
{
"name": "cashu_wallet_mint_quote",
"arguments": {
"amount": 100,
"unit": "sat"
}
}
cashu_wallet_receive_token
{
"name": "cashu_wallet_receive_token",
"arguments": {
"token": "cashuA..."
}
}
cashu_wallet_send_token
{
"name": "cashu_wallet_send_token",
"arguments": {
"amount": 21
}
}
cashu_wallet_mints_set
{
"name": "cashu_wallet_mints_set",
"arguments": {
"target": "both",
"wallet_mints": ["https://mint.host.com"],
"public_mints": ["https://mint.host.com"]
}
}
Security Model
Tool access is gated at two levels:
Sender Tier (DM triggers)
| Tier | Identity | Tools | Response |
|---|---|---|---|
| ADMIN | Configured admin pubkey | All tools | Full LLM with context |
| WOT | In admin's kind 3 contact list | None | Chat-only LLM |
| STRANGER | Anyone else | None | Configurable static response |
Skill Requirements (all triggers)
Skills declare which tools they need via requires_tool tags (see SKILLS.md — Requirements Tags). During execution, only the required and optional tools declared by the skill are exposed to the LLM. If a skill has no requires_tool tags, all available tools are exposed.
Tool Portability
Tool names serve as the capability vocabulary for cross-app skill portability. When a skill declares ["requires_tool", "http_fetch"], any app that provides an http_fetch capability can run that skill — regardless of how it implements the fetch internally.
Runtime Availability
Not all tools are available in every runtime. Tools that require specific host capabilities:
| Tool | Requires |
|---|---|
local_shell_exec |
Host OS shell access |
local_file_read |
Host filesystem |
local_file_write |
Host filesystem |
blossom_upload |
Filesystem + HTTP |
blossom_download |
Filesystem + HTTP |
Tools available in any runtime (including browser):
| Tool | Capability |
|---|---|
nostr_* |
Nostr relay WebSocket connections |
local_http_fetch |
HTTP client |
memory_save / memory_recall |
Nostr event storage |
cashu_wallet_* |
HTTP client + Nostr storage |
Skills should declare requires_tool tags so apps can determine compatibility. See SKILLS.md — Requirements Tags.
Related Documentation
- Skill definitions, adoption, triggers, and autonomous activation: SKILLS.md
- Context assembly model: CONTEXT.md