9.4 KiB
Didactyl Admin Web Frontend — Project Brief
What Is Didactyl?
Didactyl is a sovereign AI agent that lives on Nostr. It connects to Nostr relays, listens for encrypted DMs from its administrator, reasons with an LLM, and takes actions — posting events, querying relays, running shell commands, managing skills. Everything the agent knows and does is stored as Nostr events.
The agent is a C binary that runs on a server. It has no web interface of its own — all interaction happens through Nostr DMs.
What We Are Building
A local web admin dashboard that connects to the running didactyl agent via a localhost HTTP API. The dashboard is a prompt crafting and agent inspection tool for the administrator.
This is not a chat interface. The administrator already chats with the agent through Nostr DMs. This dashboard is for:
- Inspecting what the agent sees — its full LLM context, broken into labeled parts with token counts
- Crafting custom prompts — editing system prompts, user messages, and context pieces
- Running prompts against the LLM — with or without the agent tool set
- Comparing prompt variants side-by-side — A/B testing different prompt wordings or models
The API
The didactyl agent exposes a localhost-only HTTP API on port 8484 by default. Full API documentation is in docs/API.md. All endpoints return JSON with CORS headers.
Base URL
http://127.0.0.1:8484
Currently Implemented Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /api/status |
Agent runtime status — name, version, pubkey, relay count, trigger count |
| GET | /api/context/current |
Full LLM context messages array with total char/token counts |
| GET | /api/context/parts |
Context broken into labeled parts with individual sizes |
| POST | /api/prompt/run-simple |
Simple prompt: system + user message, no tools, returns text |
| POST | /api/prompt/run |
Full prompt: messages array with tools enabled, returns conversation trace |
| POST | /api/prompt/compare |
A/B test: two prompt variants run sequentially, responses side-by-side |
| GET | /api/model |
Current LLM model config (provider, model, base_url, max_tokens, temperature) |
| PUT | /api/model |
Change model at runtime — persists to config.json |
| GET | /api/models |
List available models from the configured provider |
Planned Future Endpoints
These are not yet implemented but are on the roadmap:
| Method | Path | Purpose |
|---|---|---|
| GET | /api/config |
Runtime config with redacted secrets |
| GET | /api/events/soul |
Agent soul/system prompt event |
| PUT | /api/events/soul |
Update soul content |
| GET | /api/events/skills |
List skills |
| GET/PUT | /api/events/skills/:d_tag |
Read/update individual skills |
| GET | /api/events/profile |
Agent Nostr profile |
| GET | /api/tools |
List all tool schemas |
| POST | /api/tools/:name/execute |
Execute a tool directly |
| GET | /api/triggers |
Active trigger subscriptions |
| GET | /api/relays |
Relay connection status |
Core User Workflows
1. Context Inspector
The primary read-only workflow. The admin wants to understand what the agent sees when it processes a message.
flowchart TD
LOAD[Load /api/context/parts] --> DISPLAY[Display parts list]
DISPLAY --> DETAIL[Click part to expand content]
DETAIL --> TOKENS[Show char count and token estimate per part]
TOKENS --> TOTAL[Show total context size]
What to show:
- A list/table of context parts with name, role, character count, estimated tokens
- Total context size as a summary bar or header
- Expandable content for each part
- The parts are:
system_prompt,admin_identity,admin_profile,admin_relay_list,startup_events,adopted_skills,dm_history(one entry per turn, up to limit),admin_notes - Part names come from the
---template---section of the soul event (kind 31120); they may differ if the soul is customised
2. Simple Prompt Crafting
Quick iteration on prompt wording without tools.
flowchart TD
WRITE[Write system prompt + user message] --> RUN[POST /api/prompt/run-simple]
RUN --> RESULT[Display response text]
RESULT --> EDIT[Edit and re-run]
EDIT --> RUN
What to show:
- Two text areas: system prompt, user message
- Optional model override dropdown/input
- Run button
- Response display with model used and token estimates
3. Full Prompt with Tools
Craft a complete messages array and run it with the agent tool set.
flowchart TD
CONTEXT[Load context from /api/context/parts] --> EDIT[Edit/rearrange context parts]
EDIT --> ADD[Add user message]
ADD --> RUN[POST /api/prompt/run]
RUN --> TRACE[Display conversation trace]
TRACE --> TOOLS[Show tool calls and results per turn]
TOOLS --> FINAL[Show final response]
What to show:
- Pre-populate from context parts or start from scratch
- Messages editor — add/remove/reorder messages with role and content
- Max turns slider/input
- Optional model override
- Run button
- Turn-by-turn trace showing tool calls with name, arguments, and results
- Final response text
- Token estimates
4. A/B Prompt Comparison
Compare two prompt variants side-by-side.
flowchart TD
CRAFT_A[Craft variant A messages] --> CRAFT_B[Craft variant B messages]
CRAFT_B --> COMPARE[POST /api/prompt/compare]
COMPARE --> SIDE[Display responses side-by-side]
SIDE --> DIFF[Compare final responses and token usage]
What to show:
- Two prompt editors side-by-side, each with messages array + model override + max turns
- Compare button
- Side-by-side response display
- Highlight differences in final response text
- Token usage comparison
5. Status Dashboard
Simple overview of agent health.
What to show:
- Agent name, version, pubkey
- Connected relays count vs configured
- Active triggers count
- API connection status indicator
Key Design Decisions
Localhost Only
The API binds to 127.0.0.1 — the frontend must run on the same machine as the agent, or use SSH tunneling. There is no authentication. This is intentional — it is a local dev/admin tool.
No WebSocket
The API is plain HTTP request/response. There is no WebSocket or streaming. Prompt execution calls may take several seconds for LLM responses — the frontend should show a loading state.
Token Estimation
All token counts from the API use a chars / 4 heuristic. This is approximate. The frontend can display these as-is or add its own tokenizer if more precision is needed.
Model Override
The model field in prompt requests temporarily overrides the agent configured model for that single request, then restores the original. This enables cross-model comparison without changing agent config.
Tool Execution Is Real
When using /api/prompt/run or /api/prompt/compare, tool calls are actually executed. If the LLM decides to post a Nostr event, it will really post it. The frontend should make this clear to the user — perhaps with a warning or confirmation before running prompts with tools enabled.
Response Shapes Quick Reference
Status
{
"success": true,
"name": "Didactyl",
"version": "v0.0.26",
"pubkey": "52a3e8...",
"relay_count": 4,
"connected_relays": 4,
"active_triggers": 0
}
Context Parts
{
"success": true,
"total_chars": 13131,
"total_estimated_tokens": 3283,
"parts": [
{
"name": "system_prompt",
"role": "system",
"chars": 1200,
"estimated_tokens": 300,
"content": "# Didactyl Agent..."
}
],
"messages": [...]
}
Simple Prompt Response
{
"success": true,
"response": "ok",
"model_used": "claude-haiku-4.5",
"input_tokens_estimate": 10,
"output_tokens_estimate": 1
}
Full Prompt Response
{
"success": true,
"final_response": "Done! I posted a tweet.",
"turns": [
{
"turn": 1,
"tool_calls": [
{"name": "nostr_post", "arguments": "...", "result": "..."}
]
}
],
"model_used": "claude-haiku-4.5",
"total_input_tokens_estimate": 3200,
"total_output_tokens_estimate": 180
}
Compare Response
{
"success": true,
"variant_a": { "...same shape as full prompt response..." },
"variant_b": { "...same shape as full prompt response..." }
}
Error Response
{
"success": false,
"error": "description of what went wrong"
}
Technology Suggestions
No technology is mandated for the frontend. Some reasonable choices:
- Vanilla HTML/JS — simplest, no build step, just open in browser
- React/Preact — if you want component structure
- Svelte — lightweight, good for small dashboards
- Vue — also fine
The frontend is a separate project from didactyl. It just needs to make HTTP requests to localhost:8484.
File References
| File | Description |
|---|---|
docs/API.md |
Full API endpoint reference with request/response examples |
plans/admin_api.md |
Original architecture plan for the HTTP API |
src/http_api.c |
C implementation of all endpoints |
src/http_api.h |
Public API header |
config.json.example |
Example config showing the api section |
Getting Started
- Ensure didactyl is running with
api.enabled: truein config.json - Verify the API is up:
curl http://127.0.0.1:8484/api/status - Build the frontend to talk to
http://127.0.0.1:8484 - Start with the status endpoint and context inspector, then add prompt crafting