Files
didactyl/docs/TOOLS.md

781 lines
19 KiB
Markdown

# Didactyl — Tools
See also: [SKILLS.md](SKILLS.md) · [CONTEXT.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
1. A trigger fires (DM, cron, subscription, webhook, or chain) — see [SKILLS.md](SKILLS.md)
2. The agent builds the context window from triggered skills and their `{{...}}` references
3. The agent builds an LLM request with the context, triggering event, and a JSON schema of available tools
4. The LLM decides whether to call a tool or respond directly
5. If a tool is called, didactyl executes it and feeds the result back to the LLM
6. The loop repeats until the LLM produces a final text response
7. 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](SKILLS.md).
| Tool | Description |
|---|---|
| `skill_create` | Create or update a skill definition as kind `31123`/`31124` and optionally auto-adopt it (content should be markdown instructions; runtime handles role packaging) |
| `skill_edit` | Edit an existing self skill by d tag and republish it as kind `31123`/`31124` (content should remain markdown-first) |
| `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**
```json
{
"name": "nostr_post",
"arguments": {
"kind": 1,
"content": "Hello from Didactyl!",
"tags": [["t", "didactyl"]]
}
}
```
**nostr_delete**
```json
{
"name": "nostr_delete",
"arguments": {
"event_ids": ["<event_id_hex>"],
"reason": "Mistake"
}
}
```
**nostr_react**
```json
{
"name": "nostr_react",
"arguments": {
"event_id": "<event_id_hex>",
"event_pubkey": "<pubkey_hex>",
"reaction": "🤙"
}
}
```
**nostr_query**
```json
{
"name": "nostr_query",
"arguments": {
"filter": {
"kinds": [1],
"limit": 5
},
"timeout_ms": 5000
}
}
```
**nostr_my_events**
```json
{
"name": "nostr_my_events",
"arguments": {
"kind": 1,
"limit": 10
}
}
```
**nostr_dm_send**
```json
{
"name": "nostr_dm_send",
"arguments": {
"recipient_pubkey": "<pubkey_hex>",
"message": "Secret message"
}
}
```
**nostr_dm_send_nip17**
```json
{
"name": "nostr_dm_send_nip17",
"arguments": {
"recipient_pubkey": "<pubkey_hex>",
"message": "Private message via NIP-17",
"subject": "Confidential"
}
}
```
### Nostr Identity & Utility
**nostr_profile_get**
```json
{
"name": "nostr_profile_get",
"arguments": {
"pubkey": "<pubkey_hex>"
}
}
```
**nostr_nip05_lookup**
```json
{
"name": "nostr_nip05_lookup",
"arguments": {
"identifier": "user@domain.com"
}
}
```
**nostr_encode**
```json
{
"name": "nostr_encode",
"arguments": {
"type": "npub",
"hex": "<pubkey_hex>"
}
}
```
**nostr_decode**
```json
{
"name": "nostr_decode",
"arguments": {
"uri": "nostr:npub1..."
}
}
```
**nostr_relay_status**
```json
{
"name": "nostr_relay_status",
"arguments": {}
}
```
**nostr_relay_info**
```json
{
"name": "nostr_relay_info",
"arguments": {
"relay_url": "wss://relay.damus.io"
}
}
```
**nostr_subscription_status**
```json
{
"name": "nostr_subscription_status",
"arguments": {}
}
```
**nostr_subscription_set**
```json
{
"name": "nostr_subscription_set",
"arguments": {
"name": "admin_context_profile",
"enabled": true
}
}
```
**nostr_encrypt**
```json
{
"name": "nostr_encrypt",
"arguments": {
"recipient_pubkey": "<pubkey_hex>",
"plaintext": "Sensitive data"
}
}
```
**nostr_decrypt**
```json
{
"name": "nostr_decrypt",
"arguments": {
"sender_pubkey": "<pubkey_hex>",
"ciphertext": "<nip44_ciphertext>"
}
}
```
**nostr_list_manage**
```json
{
"name": "nostr_list_manage",
"arguments": {
"list_kind": 10000,
"action": "add",
"items": [["p", "<pubkey_hex>"]]
}
}
```
**nostr_block_list**
```json
{
"name": "nostr_block_list",
"arguments": {
"type": "p"
}
}
```
**nostr_block_edit**
```json
{
"name": "nostr_block_edit",
"arguments": {
"action": "add",
"items": [["p", "<pubkey_hex>"]],
"public": false
}
}
```
### Context & Identity
**nostr_pubkey** / **my_pubkey**
```json
{
"name": "nostr_pubkey",
"arguments": {}
}
```
**agent_identity**
```json
{
"name": "agent_identity",
"arguments": {}
}
```
**admin_identity**
```json
{
"name": "admin_identity",
"arguments": {}
}
```
**nostr_admin_profile**
```json
{
"name": "nostr_admin_profile",
"arguments": {}
}
```
**nostr_agent_notes** / **my_notes**
```json
{
"name": "my_notes",
"arguments": {}
}
```
### Skills & Triggers
**skill_create**
```json
{
"name": "skill_create",
"arguments": {
"d": "weather-skill",
"content": "## Weather Assistant\n\nYou provide concise weather summaries.\n\nInput:\n{{message}}",
"description": "Fetches weather data",
"trigger": "dm",
"filter": "{\"from\":\"admin\"}",
"auto_adopt": true
}
}
```
**skill_edit**
```json
{
"name": "skill_edit",
"arguments": {
"d": "weather-skill",
"description": "Updated weather skill description"
}
}
```
**skill_list**
```json
{
"name": "skill_list",
"arguments": {
"adopted": true
}
}
```
**skill_adopt**
```json
{
"name": "skill_adopt",
"arguments": {
"pubkey": "<author_pubkey_hex>",
"d": "cool-skill"
}
}
```
**skill_search**
```json
{
"name": "skill_search",
"arguments": {
"query": "bitcoin",
"popular": true
}
}
```
**trigger_list**
```json
{
"name": "trigger_list",
"arguments": {}
}
```
### Tasks & Memory
**task_list**
```json
{
"name": "task_list",
"arguments": {}
}
```
**task_manage**
```json
{
"name": "task_manage",
"arguments": {
"action": "add",
"text": "Finish documentation",
"status": "active"
}
}
```
**memory_save**
```json
{
"name": "memory_save",
"arguments": {
"content": "User likes coffee."
}
}
```
**memory_recall**
```json
{
"name": "memory_recall",
"arguments": {}
}
```
### LLM & Configuration
**model_get**
```json
{
"name": "model_get",
"arguments": {}
}
```
**model_set**
```json
{
"name": "model_set",
"arguments": {
"model": "gpt-4o",
"temperature": 0.7
}
}
```
**config_store**
```json
{
"name": "config_store",
"arguments": {
"d_tag": "custom_setting",
"content": "{\"value\": 42}"
}
}
```
**config_recall**
```json
{
"name": "config_recall",
"arguments": {
"d_tag": "custom_setting"
}
}
```
### System & Runtime
**agent_version**
```json
{
"name": "agent_version",
"arguments": {}
}
```
**local_http_fetch**
```json
{
"name": "local_http_fetch",
"arguments": {
"url": "https://api.github.com/zen",
"method": "GET"
}
}
```
**local_shell_exec**
```json
{
"name": "local_shell_exec",
"arguments": {
"command": "ls -la"
}
}
```
**local_file_read**
```json
{
"name": "local_file_read",
"arguments": {
"path": "README.md"
}
}
```
**local_file_write**
```json
{
"name": "local_file_write",
"arguments": {
"path": "test.txt",
"content": "Hello world",
"append": false
}
}
```
**tool_list**
```json
{
"name": "tool_list",
"arguments": {}
}
```
### Cashu Wallet
**cashu_wallet_balance**
```json
{
"name": "cashu_wallet_balance",
"arguments": {}
}
```
**cashu_wallet_mint_quote**
```json
{
"name": "cashu_wallet_mint_quote",
"arguments": {
"amount": 100,
"unit": "sat"
}
}
```
**cashu_wallet_receive_token**
```json
{
"name": "cashu_wallet_receive_token",
"arguments": {
"token": "cashuA..."
}
}
```
**cashu_wallet_send_token**
```json
{
"name": "cashu_wallet_send_token",
"arguments": {
"amount": 21
}
}
```
**cashu_wallet_mints_set**
```json
{
"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](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](SKILLS.md#requirements-tags).
---
## Related Documentation
- Skill definitions, adoption, triggers, and autonomous activation: [SKILLS.md](SKILLS.md)
- Context assembly model: [CONTEXT.md](CONTEXT.md)