8.8 KiB
v0.2.0 Migration Plan
Agent Event Cleanup
Delete all old skill/soul events from each agent's relay set before restarting with the new genesis file.
Genesis File Changes
Kind 0 profile event (new)
Add a startup event for the agent's profile:
{
"kind": 0,
"content_fields": {
"name": "Didactyl",
"about": "I am a Didactyl agent living on Nostr"
},
"tags": []
}
Kind 3 contacts event (new)
Add a startup event following the admin:
{
"kind": 3,
"content": "",
"tags": [
["p", "ADMIN_HEX_PUBKEY"]
]
}
The admin hex pubkey is derived from the admin.pubkey field at startup.
Default skill rename and trigger tags
Before:
"default_skill": {
"d_tag": "didactyl-default",
"kind": 31124,
"content": "# Didactyl Agent\n\n...\n\n---template---\n\n- section: admin_identity\n ...",
"tags": [["app", "didactyl"], ["scope", "private"]]
}
After:
"default_skill": {
"d_tag": "default_admin_dm",
"kind": 31124,
"content": "# Didactyl Agent\n\nYou are {{my_kind0_profile}}\n\nYour npub: {{my_npub}}\n\n## Rules\n\n- Communicate through encrypted Nostr direct messages\n- Keep responses concise and clear\n- Be helpful and technically accurate\n- If unsure, state uncertainty directly\n- Use tools when a request requires taking action\n- After a tool call, base your answer on the actual tool result\n- Never claim a tool was run if no tool was executed\n- Maintain your task list as short-term working memory\n- Never reveal your private key (nsec)\n- You may share your public key (npub) with anyone",
"tags": [
["app", "didactyl"],
["scope", "private"],
["description", "Default admin DM handler"],
["trigger", "dm"],
["filter", "{\"from\":\"admin\"}"]
]
}
Key changes:
d_tagrenamed todefault_admin_dm---template---DSL removed entirely- Content uses
{{my_kind0_profile}}and{{my_npub}}for identity injection - Trigger/filter tags added so the new trigger-scoped system fires it on admin DMs
- Description tag added
Source Code Changes
Phase 1: Remove ---template--- DSL
src/prompt_template.h
- Remove
PROMPT_TEMPLATE_MARKER,PROMPT_TEMPLATE_MAX_SECTIONS,PROMPT_TEMPLATE_MAX_NAME_LEN,PROMPT_TEMPLATE_MAX_ROLE_LEN - Remove
prompt_template_section_tstruct - Remove
prompt_template_tstruct - Remove
prompt_template_emit_hook_fntypedef - Remove
prompt_template_parse()declaration - Remove
prompt_template_build_messages()declaration - Remove
prompt_template_free()declaration - Keep the file if
resolve_inline_variables_local()needs a public header, otherwise fold into agent.c
src/prompt_template.c
- Remove
prompt_template_parse()and all section-parsing code (lines 231-502) - Remove
prompt_template_build_messages()(lines 551-639) - Remove
prompt_template_free()(lines 641-667) - Remove section-related helpers:
init_section_defaults(),parse_int_or_zero(),extract_tool_result_content(),append_message_object() - Keep
resolve_inline_variables_local()— it handles{{...}}variable resolution used bybuild_context_from_triggers() - Keep
map_variable_tool_name()— maps variable names to tool names - Keep string helpers:
dup_range(),ltrim_inplace(),rtrim_inplace(),append_text()
src/agent.c
- Remove
g_prompt_templatestatic variable (line 28) - Remove
g_has_prompt_templatestatic variable (line 29) - Remove
template_emit_hook()callback - Remove the
prompt_template_parse()call inagent_init()(line 2127-2128) - Remove the
prompt_template_free()calls inagent_init()andagent_cleanup() - Remove the
g_has_prompt_templatebranch inagent_build_admin_messages_json()(lines 2334-2035) — replace with trigger-composed context path
Phase 2: Remove g_system_context
src/agent.c
- Remove
g_system_contextglobal (line 24) - Remove
system_contextparameter fromagent_init() - Remove
strdup(system_context)and allg_system_contextreferences - Remove
g_system_contextnull checks fromagent_on_trigger(),agent_on_message(),agent_build_admin_messages_json() - In
agent_cleanup(): removefree(g_system_context)
src/agent.h
- Update
agent_init()signature:int agent_init(didactyl_config_t* config);
src/nostr_handler.c
- Remove
g_system_contextglobal (line 28) - Remove
g_system_contextinitialization innostr_handler_reconcile_startup_events()(lines 3124-3157) - Remove
nostr_handler_get_system_context()function (lines 3289-3291) - Remove
seed_default_skill_into_cache()if it only servesg_system_context
src/nostr_handler.h
- Remove
nostr_handler_get_system_context()declaration
src/main.c
- Remove
system_contextvariable (line 1261) - Remove fallback logic (lines 1262-1270)
- Call
agent_init(&cfg)without system_context parameter
Phase 3: Rename default skill constants
src/default_events.h
DIDACTYL_DEFAULT_SKILL_D_TAG:"didactyl-default"→"default_admin_dm"DIDACTYL_DEFAULT_SKILL_TAGS_JSON: add trigger/filter/description tagsDIDACTYL_DEFAULT_SKILL_TEMPLATE: remove---template---section, replace with lean markdown using{{my_kind0_profile}}and{{my_npub}}
Phase 4: Update agent_build_admin_messages_json()
This function is used by the HTTP API. Currently has two paths (template DSL and legacy hardcoded). Replace both with a single path using build_context_from_triggers() — same as agent_on_message() now uses.
Phase 5: Delete legacy files
| File | Action |
|---|---|
config.jsonc.example |
Delete |
context_template.md |
Delete |
context_template.recovered.md |
Delete |
Phase 6: Update genesis files
genesis.jsonc
- Add kind 0 startup event with name and about
- Rename
default_skill.d_tagtodefault_admin_dm - Add trigger/filter/description tags to
default_skill.tags - Replace content with lean markdown (no
---template---)
genesis.jsonc.example
- Same changes as genesis.jsonc
- Add kind 0 and kind 3 startup events
Phase 7: Update documentation
README.md
- Remove kind 31120 from Didactyl Kinds table
- Remove soul references
- Update architecture description
docs/GENESIS.md
- Remove config.jsonc migration references
- Update default_skill section to show
default_admin_dm - Document kind 0 and kind 3 startup events
docs/API.md
- Remove
/api/events/soulendpoint - Remove config.jsonc references
docs/SKILLS.md, docs/CONTEXT.md, docs/TOOLS.md
- Verify no soul/31120/config.jsonc references remain
Variable Resolution for Default Skill
The default admin DM skill content uses:
{{my_npub}}— resolves viamap_variable_tool_name()→nostr_npubtool → returns agent npub{{my_kind0_profile}}— resolves viamap_variable_tool_name()→my_kind0_profiletool → returns agent kind 0 profile context
These already work in resolve_inline_variables_local() because map_variable_tool_name() returns NULL for unknown names, and the skill lookup callback handles the rest. But my_npub and my_kind0_profile are not in the current map_variable_tool_name() mapping — they need to be added, OR the function needs to pass through unknown names as tool names (which it currently does NOT do after the Phase 1a change that made it return NULL for unknowns).
Fix needed: In map_variable_tool_name(), return the variable name itself as a tool name when it doesn't match a known alias. This way {{my_npub}} calls the my_npub tool directly.
Current (after Phase 1a change):
return NULL; // unknown → try skill lookup
Should be:
return var_name; // unknown → try as tool name first, then skill lookup
Wait — this was the ORIGINAL behavior before Phase 1a changed it. The Phase 1a change made map_variable_tool_name() return NULL for unknowns so the skill lookup callback would fire. But now we need BOTH: try as tool name first, then skill lookup.
Resolution: Restore return var_name; in map_variable_tool_name(). The skill lookup callback in resolve_inline_variables_local() already only fires when replacement_owned is NULL after the tool attempt. So the flow is:
- Check known aliases (admin_profile → nostr_admin_profile, etc.)
- Try the variable name as a direct tool name
- If tool returns nothing useful, try skill lookup callback
- If skill lookup returns nothing, resolve to empty string
This is exactly the resolution order specified in SKILLS.md.
Execution Order
- Phase 3 — rename constants (safe, no behavioral change)
- Phase 5 — delete legacy files
- Phase 6 — update genesis files
- Phase 1 — remove template DSL
- Phase 2 — remove g_system_context
- Phase 4 — update agent_build_admin_messages_json
- Phase 7 — update docs
- Build and test
increment_and_push.sh -pfor v0.2.1