Files
didactyl/plans/enhanced_existing_agent_wizard.md

7.4 KiB

Enhanced Existing Agent Wizard Flow

Problem

When choosing "existing agent" in the wizard, the current flow:

  1. Asks for nsec
  2. Recovers kind 10002 relay list from Nostr
  3. Immediately boots the agent

This is insufficient when installing an existing agent on a new server because:

  • You cannot review or change the admin pubkey
  • You cannot review or change the LLM provider/model/API key
  • You cannot install a systemd service with a dedicated user
  • You cannot see what config was recovered from Nostr
  • The agent name is not recovered from the kind 0 profile

Current Code

  • existing_agent_flow() — 22 lines, minimal recovery
  • recover_existing_config_from_nostr() — only recovers kind 10002 relays
  • Returns SETUP_WIZARD_RC_EXISTING (2) which does NOT set bootstrap_mode
  • In main.c, existing agents skip reconcile_startup_events() unless first_run is detected

Data Available on Nostr for an Existing Agent

Data Kind Storage Recovery Method
Relay list 10002 Public tags query_and_extract_kind10002_relays()
Agent profile/name 0 Public JSON content Query kind 0 by agent pubkey
LLM config 30078 d=llm_config NIP-44 encrypted to self fetch_self_config_plaintext()
Agent config - admin pubkey, DM protocol 30078 d=agent_config NIP-44 encrypted to self fetch_self_config_plaintext()
Default skill 31124 d=didactyl-default Public content Query kind 31124 by agent pubkey
Adoption list 10123 Public tags Query kind 10123 by agent pubkey

Proposed Enhanced Flow

flowchart TD
    A[Enter nsec] --> B[Connect to default relays]
    B --> C[Recover kind 10002 relay list]
    C --> D{Relay list found?}
    D -->|No| E{Offer to create new agent with this nsec}
    E -->|Yes| E2[Jump to new_agent_flow with nsec pre-loaded]
    E -->|No| E3[Return to main menu]
    D -->|Yes| F[Reconnect with recovered relays]
    F --> G[Recover all config from Nostr]
    G --> H[Display recovered config summary]
    H --> I{Review each setting}
    I -->|Keep all| J[Review summary + launch options]
    I -->|Change admin| K[Prompt new admin pubkey]
    I -->|Change LLM| L[Prompt LLM config]
    I -->|Change relays| M[Prompt relay config]
    K --> I
    L --> I
    M --> I
    J --> N{Launch option}
    N -->|Boot now| O[Return EXISTING]
    N -->|Install systemd| P[Install dedicated-user service]
    N -->|Quit| Q[Exit]

Step-by-step

Step 1: Identity — Enter nsec

Same as current. Derive keys from nsec.

Step 2: Recovery — Connect and fetch config from Nostr

  1. Init nostr handler with default relays
  2. Wait for relay connections
  3. Query kind 10002 for relay list — if not found, offer to create a new agent with this nsec (jump to new_agent_flow with keys pre-loaded, skipping identity step)
  4. Cleanup and re-init with recovered relays
  5. Wait for relay connections on recovered relays
  6. Query kind 0 for agent profile — extract display_name/name
  7. Query kind 30078 d=llm_config — decrypt and parse LLM settings
  8. Query kind 30078 d=agent_config — decrypt and parse admin pubkey + DM protocol
  9. Cleanup nostr handler

Step 3: Review — Present recovered config

Display all recovered values:

  ┌─────────────────────────────────────────────┐
  │  Existing Agent -- Recovered Configuration  │
  ├─────────────────────────────────────────────┤
  │  Agent name:    Simon                       │
  │  Identity:      b27072b7fc2edf45...         │
  │  Admin:         a1b2c3d4e5f6...             │
  │  LLM Provider:  ppq                         │
  │  LLM Model:     claude-haiku-4.5            │
  │  LLM Base URL:  https://api.ppq.ai          │
  │  LLM API Key:   sk-...****                  │
  │  DM Protocol:   nip04                       │
  │  Relays:        5 configured                │
  └─────────────────────────────────────────────┘

Then offer a menu:

  [a] change Admin pubkey
  [l] change LLM provider/model/key
  [r] change Relay configuration
  [c] continue with these settings
  [q] quit

Each change option reuses the existing prompt functions (prompt_admin_pubkey, prompt_llm_config, prompt_relay_configuration) but with context-appropriate headers.

After any change, redisplay the summary and menu.

Step 4: Launch — Boot or install systemd

Same as the new-agent flow's final step:

  [b] boot the agent now
  [i] install dedicated-user systemd service and boot
  [q] quit

The systemd install reuses install_system_service_with_dedicated_user().

Return Codes

  • If user chooses "boot now": return SETUP_WIZARD_RC_EXISTING (2) — same as current
  • If user chooses "install systemd": return SETUP_WIZARD_RC_EXIT (1) — agent runs as systemd service
  • If user changed config values: the main() flow should still work because recover_missing_runtime_config_from_nostr() at line 1108 will fill in any gaps, and the existing agent path at line 1163 loads system context from adopted skills

Key Consideration: bootstrap_mode for changed configs

If the user changes LLM or admin config in the wizard, those changes need to be persisted back to Nostr. Currently, persist_runtime_config_to_nostr() is only called when bootstrap_mode || first_run.

Solution: When the existing-agent wizard detects that config was changed, return SETUP_WIZARD_RC_BOOTSTRAP (0) instead of SETUP_WIZARD_RC_EXISTING (2). This triggers the full reconcile path which persists the updated config.

Files to Modify

  1. src/setup_wizard.c:

    • Add recover_full_config_from_nostr() — fetches kind 0, kind 30078 llm_config, kind 30078 agent_config
    • Add query_self_kind0_name() — queries agent's own kind 0 profile for name
    • Add fetch_and_decrypt_self_config() — replicates fetch_self_config_plaintext() logic from main.c for use in wizard context
    • Rewrite existing_agent_flow() with the enhanced multi-step flow
    • Make prompt_admin_pubkey(), prompt_llm_config(), prompt_relay_configuration() accept a context string parameter for the page header, or add wrapper versions for the existing-agent context
  2. src/main.c:

    • Potentially expose fetch_self_config_plaintext(), apply_recalled_llm_config(), apply_recalled_agent_config() as non-static, OR duplicate the logic in setup_wizard.c
    • Better approach: move these to a shared location or make them accessible via a header

Implementation Notes

  • The wizard already calls nostr_handler_init() / nostr_handler_cleanup() for validation queries. The enhanced flow will do the same but with two init/cleanup cycles: first with default relays to get kind 10002, then with recovered relays to get everything else.
  • The prompt_admin_pubkey() and prompt_llm_config() functions currently have hardcoded step headers like "Step 3 of 7". These should be parameterized or have existing-agent variants.
  • The fetch_self_config_plaintext() function in main.c requires an active nostr handler. The wizard will need to have the handler initialized when calling it.
  • API key display should be masked — show only first 4 and last 4 characters.