• v0.8.0 9fade55901

    feat(local_agents): tier-3 index + picker merge (v0.8.0)

    vh released this 2026-05-24 21:13:30 -07:00 | 249 commits to main since this release

    Worldtree's GET /agents doesn't return consumer-defined (tier-3)
    agents — the public list excludes them by design. Confirmed live in
    v0.7.0's smoke. Without server-side knowledge, ratatoskr's picker
    couldn't show tier-3 agents the operator had defined; the workflow
    was "remember the agent_id, pass --agent ratatoskr:
    explicitly." Friction grows with every tier-3 agent.

    Fix: client-side index, merged at picker time

    New module ratatoskr.local_agents maintains a JSON-backed index at
    $XDG_CONFIG_HOME/ratatoskr/local_agents.json (override via
    $RATATOSKR_LOCAL_AGENTS). tier3 CLI define / patch / delete update
    the index as side-effects. tui._resolve_then_run loads the index
    after list_agents(client) and appends entries not already in the
    remote list (dedup by agent_id; remote wins on conflict).

    Library-level tier3.define_agent / patch_agent / delete_agent
    stay pure — local persistence lives in the CLI layer (_run_define
    etc.), not in the library functions. Tests of the library don't
    touch the filesystem.

    Public surface

    ratatoskr.local_agents:
    LocalAgentEntry (frozen dataclass)
    load_local_agents() -> list[LocalAgentEntry]
    add_local_agent(entry)
    update_local_agent(entry) # same semantics as add (agent_id key)
    remove_local_agent(agent_id)
    make_description(system_prompt) -> str # synthetic picker label

    Failure modes are lenient: missing file → empty index; corrupt JSON
    or schema mismatch → empty index (no crash). The picker continues
    to show foundational agents either way; tier-3 surface degrades to
    the pre-v0.8.0 workflow.

    Picker integration

    Local entries convert to ratatoskr.sessions.AgentInfo with synthetic
    fields:
    name = agent_name (from LocalAgentEntry)
    description = "(tier 3) "
    version, capabilities, supported_models, persona_traits, ui_hints
    = None / [] / [] / {} / {}

    If Worldtree later starts returning tier-3 in GET /agents, this
    module's role narrows to redundant local cache; can be removed
    cleanly since the dedup-by-agent-id keeps remote-wins behavior.

    Tests

    286/286 GREEN (was 265, +21: 20 local_agents + 1 picker-merge
    integration). Ruff clean. Tests isolate the index via
    $RATATOSKR_LOCAL_AGENTS pointed at pytest's tmp_path — no pollution
    of operator's real ~/.config/ratatoskr/.

    Manual smoke

    Sindra-like define against personal Worldtree:
    python -m ratatoskr.tier3 define --name foo --system-prompt "..." --model X
    cat ~/.config/ratatoskr/local_agents.json

    ratatoskr --new picker now shows ratatoskr:foo alongside mimir et al.

    Cross-machine: the file is per-host. Operator can sync via dotfiles
    if needed; out of scope for this commit.

    Minor bump (v0.7.1 → v0.8.0) — new public module + new picker
    behavior (more agents shown). No caller-side breaking changes.

    Downloads