Watch
1
0
Fork
You've already forked souveraine
0
souveraine/saf/server.md
Fimeg 3ff6ffaa7f license: relicense AGPL-3.0; bring SAF docs online; keep CLAUDE.md + docs/ local
SAF (souveraine architecture files) is now the in-repo doc set. working notes
(CLAUDE.md, docs/) stay on disk, gitignored.
2026-06-19 10:17:56 -04:00

5.2 KiB

SAF: Server Implementation

HTTP server layer — axum on port 8484. Last updated: 2026-05-12 (Full audit — memory CRUD, auth, instance registry)


Implementation Status

Area Module Status Notes
Server struct + lifecycle server/mod.rs (228 lines) SouveraineServer, new(), run(), instance registry, compaction wiring
Database schema server/db.rs (77 lines) agents + agent_instances tables, SQLite
API models api/models.rs (190 lines) All request/response types
Session manager server/session_manager.rs (111 lines) Sessions with SSE broadcast, conversation store wiring
Agent inventory server/agent_inventory.rs (514 lines) CRUD + SQLite + per-agent seed init + subconscious creation + instance heartbeat
HTTP handlers api/handlers.rs (261 lines) Agent, conversation, memory handlers
API routes api/mod.rs (65 lines) Public + memory + web routes
Auth middleware api/auth.rs (42 lines) Bearer-token protection for memory routes
Consciousness engine server/consciousness_engine.rs (677 lines) N+1 Aster (full LLM tool loop), N+25 reflection, 3-tier compaction warnings
CLI integration main.rs + cli/commands.rs souveraine server command
Gitea memory server/gitea_memory.rs (115 lines) ⚠️ Opt-in, gracefully disabled if unreachable
Server conversation server/conversation.rs (72 lines) ⚠️ Simplified Bifrost call, no tool loop (tool loop lives in LocalBackend)

What the Server Provides

Endpoints

Method Path Handler Status
GET /health health_check
GET /v1/agents list_agents
POST /v1/agents create_agent (auto-creates subconscious + seed)
GET /v1/agents/:id get_agent
PATCH /v1/agents/:id update_agent
DELETE /v1/agents/:id delete_agent
GET /v1/conversations list_conversations
POST /v1/conversations create_conversation
GET /v1/conversations/:id get_conversation
POST /v1/conversations/:id/messages stream_messages (SSE)
GET /v1/agents/:id/memory list_memory (auth required)
GET /v1/agents/:id/memory/*path read_memory (auth required)
PUT /v1/agents/:id/memory/*path write_memory (auth required)
PATCH /v1/agents/:id/memory/*path append_memory (auth required)
DELETE /v1/agents/:id/memory/*path delete_memory (auth required)
GET / ServeDir(web/dist/) (SPA fallback, no UI built)

Endpoints Not Implemented

No Letta-compatible block endpoints (/v1/agents/:id/core-memory/blocks) are planned — Souveraine committed to memfs-only memory per docs/MEMORY_BLOCKS_DECISION.md. The memory CRUD endpoints above replace Letta's block API.

Instance Registry

The server maintains an agent_instances table (server/db.rs, server/agent_inventory.rs):

  • register_instance() — creates one row per known agent per process, prunes stale rows (>5 min)
  • heartbeat_instance() — bumps last_seen_at and increments lifetime_active_seconds in 30s ticks
  • instance_count() — how many running instances for a given agent
  • lifetime_active_seconds() — total lifecycle uptime for uptime percentage

A background tokio task in SouveraineServer::new() handles the 30s heartbeat loop.

Auth

Memory routes require a bearer token (Authorization: Bearer <token>), enforced by middleware at api/auth.rs. Loopback requests (127.0.0.1 / ::1) can bypass auth when auth.allow_loopback is true (configurable in souveraine.toml [server.auth] section). Public routes (agents list, conversations, health) are unauthenticated.


How to Run

souveraine server
# Binds to 127.0.0.1:8484 (configurable: [server] bind=, port=, or SOUVERAINE_SERVER_BIND env)
# Creates ~/.souveraine/server/
#   ├── agents/           # Agent directories with UUID naming
#   │   └── {uuid}/
#   │       ├── agent.json
#   │       └── conversations/
#   └── database.sqlite3  # Agent index + instance registry

# With custom bind
souveraine server --bind 0.0.0.0 --port 8484

The user-side memfs lives at ~/.souveraine/agents/{uuid}/memory/ — this is the single canonical path. Subconscious agents at ~/.souveraine/subconscious-agents/{id}-sub/.


Architecture Note

The server and LocalBackend share the same engine (SouveraineServer). The difference is the transport layer:

  • Server mode: axum HTTP + SSE — client/server separation
  • Local mode: in-process Arc<SouveraineServer> with direct BackendEvent streaming — no socket

Both paths run the same run_turn() tool loop (in LocalBackend), the same N+1 Aster pass, and the same N+25 reflection trigger. The server's ServerConversation (72 lines) is a simplified single-turn path used only by the SSE handler; the full tool loop with all 11 tools lives in LocalBackend::run_turn().


Debugging

There is currently no souveraine server debug output — run() uses println! not tracing. Memory CRUD endpoints are logged via auth middleware.