# Anima System Design **Date**: 2026-04-12 **Status**: Draft **Author**: Till Wegmueller + Claude ## Overview Anima is a strategic work coordination platform for developers who manage projects, AI agents, and collaborative workflows. It is not an IDE — it is the command post layer above, where you assign work, track AI progress, manage discussions (including email threads), and surface documentation. The system is server-authoritative. The desktop client is a terminal into the command post — it caches for responsiveness but does not own data. ## Service Architecture ### Services | Service | Role | Runtime | |---------|------|---------| | **anima-server** | Core API + embedded MCP server. Projects, work items, plans, workflows, teams, settings, RBAC. gRPC for desktop client. Forge integration. Seshat's Library client. | Rust binary, always running | | **anima-mail** | Polls Stalwart via JMAP, routes inbound mail to work item threads, sends outbound mail on behalf of work items. Creates/manages mailboxes via Stalwart admin API. | Rust binary, async worker | | **anima-agent** | v1: Single-agent manager. Provisions VM/container, deploys skills, manages agent lifecycle. Interface designed for future multi-provider orchestration. | Rust binary, on-demand | | **anima-ai** | Light AI inference — summaries, gap analysis triggers, thread updates, description generation, mail classification. Stateless, horizontally scalable. | Rust binary, scalable | | **anima-desktop** | Slint desktop client. gRPC to anima-server. Caches for responsiveness, doesn't own data. | Slint/Rust app | ### External Dependencies | Dependency | Purpose | |------------|---------| | **PostgreSQL** | Primary relational store | | **Stalwart** | Mail server (JMAP + admin API + plus-addressing) | | **Seshat's Library** | Document library, vector search (pgvector), blob storage for files/patches/attachments | | **Forge APIs** | GitHub/Gitea/GitLab — PR metadata, issue migration, read-only | ### Data Flow ``` Desktop ──gRPC──► anima-server ──SQL──► PostgreSQL │ ╰── MCP (embedded) ├──► Seshat's Library (docs, vectors, blobs) ├──► anima-mail ──JMAP──► Stalwart ├──► anima-ai (light inference, N instances) ├──► anima-agent ──► VM/Container └──► Forge APIs (read-only) AI in VM ──MCP──► anima-server (scoped token, work item context only) ``` ## Domain Model ### Entities **Project** - Name, description, status (active/archived) - Has many Plans, Work Items, Repositories, Mailboxes - Links to team members with roles via RBAC **Plan** - Belongs to a Project - Title, description, progress (derived from child work items) - Has many Work Items - Phases derived from its Workflow **Work Item** - Belongs to a Project, optionally to a Plan - Title, description (versioned — every update creates a new revision, revertable), status, priority - Follows a Workflow (determines phases and required AI skills) - Has a Discussion Thread (messages, email attachments, AI/Akh contributions) - Has Patches/PRs (attachments, linked to forge PRs) - Has Documents (stored in Seshat's Library) - Has many Agent Sessions (long-running, parallel or sequential) - Has Capabilities (derived from what the work needs — repo access, API keys, network zones). Agent sessions inherit these. - Phase tracking within its workflow **Workflow** - Template defining phases (e.g., Analysis → Implementation → Review & Audit) - Each phase declares required AI Skills - Ships with defaults, user-customizable - Future: marketplace for sharing **Discussion Thread** - Belongs to a Work Item - Ordered messages from: humans, AI (via Akh), email (inbound/outbound) - AI contributions are promotable to update work item description (creates new revision) - Email messages carry headers linking back to work item via plus-addressing **Agent Session** - Belongs to a Work Item (many sessions per work item) - Represents heavy work running in a VM/container - Status (provisioning, running, paused, completed, failed) - Has Tasks (sub-units of work within the session) - Skills deployed, capabilities inherited from work item - Akh identity configured (persona for thread contributions) - Long-running once started, persists while work item is open - Admins can login (SSH) to inspect/debug — audit logged **Akh** - AI persona/identity from the Akh domain - Agents assume an Akh when writing in discussion threads - Gives AI contributions a consistent voice and attribution **Repository** - Belongs to a Project - Forge type (GitHub/Gitea/GitLab), remote URL - Has Worktrees (checked-out branches, managed by agents in VMs) - PRs/patches linked to Work Items **Document** - Stored in Seshat's Library (blob + vector embedding) - Linked to Project and/or Work Item - Types: markdown, text, patches, attachments - Searchable by AI via vector queries **Team Member** - User identity, role bindings per project (via RBAC) - Settings, notification preferences **Mailbox** - Belongs to one or more Projects (no global unattached box) - A "gather" mailbox is one linked to multiple projects - Managed via Stalwart admin API - Plus-address routing rules ### Relationships ``` Project ─┬─► Plans ──► Work Items ─┬─► Discussion Thread (messages, emails, Akh-authored) │ ├─► Patches/PRs ├─► Repositories ├─► Agent Sessions (many, long-running, loginable) ├─► Team Members │ └─► Tasks └──►┐ ├─► Documents (→ Seshat's Library) Mailboxes (shared across ├─► Capabilities (derived, inherited by sessions) multiple projects) ├─► Description Revisions (versioned, revertable) └─► Workflow (phases, skills) Akh ──► identity assumed by AI in discussions ``` ## gRPC API Design ### Public Services (desktop client, embedded MCP) **ProjectService** - `ListProjects`, `GetProject`, `CreateProject`, `UpdateProject`, `ArchiveProject` - `ListProjectMembers`, `AddProjectMember`, `RemoveProjectMember` **PlanService** - `ListPlans`, `GetPlan`, `CreatePlan`, `UpdatePlan`, `DeletePlan` **WorkItemService** - `ListWorkItems`, `GetWorkItem`, `CreateWorkItem`, `UpdateWorkItem`, `DeleteWorkItem` - `GetDescriptionRevisions`, `RevertDescription` — versioned description management - `ListCapabilities`, `UpdateCapabilities` — derived capabilities attached to work items **WorkflowService** - `ListWorkflows`, `GetWorkflow`, `CreateWorkflow`, `UpdateWorkflow`, `DeleteWorkflow` - Ships with built-in defaults, user workflows stored alongside **ThreadService** - `GetThread`, `PostMessage`, `PromoteMessage` — promote AI message to update work item description (creates new revision) - `StreamThread` — server-streaming RPC for live thread updates **AgentSessionService** - `ListSessions`, `GetSession`, `StartSession`, `StopSession` - `LoginSession` — returns connection info for admin SSH/shell access - `ListTasks`, `GetTask`, `UpdateTaskStatus` - `StreamSessionStatus` — server-streaming for live status **RepositoryService** - `ListRepositories`, `AddRepository`, `RemoveRepository` - `ListPatches`, `AttachPatch` — link forge PRs to work items **MailboxService** - `ListMailboxes`, `CreateMailbox`, `DeleteMailbox` - `LinkProjects`, `UnlinkProjects` — manage which projects a mailbox serves **DocumentService** - `ListDocuments`, `GetDocument`, `UploadDocument`, `DeleteDocument` - Delegates storage to Seshat's Library **AkhService** - `ListAkhs`, `GetAkh`, `CreateAkh`, `UpdateAkh`, `DeleteAkh` **TeamService** - `ListUsers`, `GetUser`, `CreateUser`, `UpdateUser`, `DeleteUser` - Roles and permissions per project via RBAC **DashboardService** - `GetDashboard` — aggregated view: pending decisions, active sessions, work item status across projects - `StreamDashboardUpdates` — live updates ### Internal Services (not exposed to desktop) **AnimaAiService** (anima-server → anima-ai) - `Summarize`, `AnalyzeGap`, `GenerateDescription`, `ClassifyMail` **AgentProviderService** (anima-server → anima-agent) - `ProvisionVM`, `DestroyVM`, `DeploySkills`, `GetVMStatus`, `GetLoginCredentials` ### API Patterns - **Streaming** for anything real-time: threads, agent sessions, dashboard - **Pagination** via cursor-based tokens on all List RPCs - **Field masks** on Update RPCs for partial updates - **Standard error model** with domain-specific error codes ## Desktop Client (anima-desktop) ### Technology - **Slint** for UI rendering (native, cross-platform: macOS, Wayland, X11, Windows) - **Rust** for all client logic - **tonic** gRPC client for server communication - Local **SQLite** cache for responsiveness (read cache, server is source of truth) ### Screen Map | Screen | Purpose | Key Data | |--------|---------|----------| | **Dashboard** | Morning command view. Pending human decisions, active agent sessions, work item status summaries. | DashboardService | | **Project List** | Grid/list of all projects with status, stats, AI activity indicators. | ProjectService | | **Project Detail** | Plans-centric view. Plans with progress bars, nested work items, phase indicators, repositories, skills. | PlanService, WorkItemService, RepositoryService | | **Work Item Detail** | Full work item view. Versioned description, thread (messages + emails + Akh contributions), patches, phases, capabilities, agent sessions. | WorkItemService, ThreadService, AgentSessionService | | **Work Item Email Mode** | Same work item focused on email thread. Inbound/outbound mail, share buttons. | ThreadService, MailboxService | | **Library** | Document browser. Search, read, manage documents across projects. | DocumentService (→ Seshat's Library) | | **Workflows** | Browse/create/edit workflow templates. Phase editor, skill assignment. | WorkflowService | | **Settings** | Server connection, user preferences, notification settings. | TeamService | | **Team/People** | Team member management, roles per project. | TeamService | ### Client Architecture ``` ┌─────────────────────────────┐ │ Slint UI Layer │ │ (.slint files, components) │ ├─────────────────────────────┤ │ View Models (Rust) │ │ Translate domain → UI state │ ├─────────────────────────────┤ │ gRPC Client Layer │ │ tonic, streaming listeners │ ├─────────────────────────────┤ │ Local Cache (SQLite) │ │ Read cache, invalidated by │ │ streaming updates from server│ └─────────────────────────────┘ ``` ### Caching Strategy - On startup: fetch current state, populate SQLite cache - gRPC streams (threads, dashboard, sessions) push updates → invalidate/update cache → UI reacts - Stale cache is acceptable for offline viewing but all writes go to server - Cache is disposable — can be wiped and rebuilt from server ### Design System - Headings: **Inter** - Body: **Geist** - Captions: **Funnel Sans** - Color palette: **Violet Void** (dark theme) - Roundness: Basic - Elevation: Sharp depth - Decorative: Neon streak overlays ## Mail Integration (anima-mail) ### Inbound Flow ``` External sender → sends to workitem+WI-123@project.anima.example → Stalwart receives, stores in project mailbox → anima-mail polls via JMAP → parses plus-address to extract work item ID → calls ThreadService.PostMessage on anima-server (as email-type message) → work item thread updated, desktop streams update ``` ### Outbound Flow ``` User clicks "Send" on work item thread (email mode) → desktop calls ThreadService.PostMessage (outbound email) → anima-server notifies anima-mail → anima-mail composes email with: - Reply-To: workitem+WI-123@project.anima.example - Custom headers: X-Anima-WorkItem, X-Anima-Project → sends via JMAP submission to Stalwart → recipient replies → inbound flow catches it ``` ### Mailbox Management - anima-mail uses Stalwart's admin API to create/delete mailboxes - One or more mailboxes per project, linked via MailboxService - "Gather" mailboxes link to multiple projects — routing uses plus-address to disambiguate - Compromised addresses get rotated, old mailbox dropped ### Spam Handling - Simple screener on inbound: reject unknown senders on work-item-specific addresses - Gather mailboxes are more open but can have basic filtering rules - Compromised addresses get rotated, old mailbox dropped ### Mail Classification - anima-mail calls anima-ai `ClassifyMail` to route ambiguous inbound mail when plus-addressing isn't present - **Classification always runs on the smallest/cheapest AI model available** — it is a simple routing task, not a reasoning task. anima-ai supports model tiers and mail classification always uses the minimal tier. ## Agent System (anima-agent) ### v1 Scope Single-agent interaction. One provider (configurable — local Docker, bare-metal hypervisor, or cloud VM). The interface is designed for future multi-provider orchestration but v1 runs one provider. ### Lifecycle ``` Work Item needs heavy work → anima-server calls AgentProviderService.ProvisionVM → anima-agent provisions VM/container with: - Capabilities from work item (repo access, API keys, network rules) - AI skills deployed for current workflow phase - Akh identity configured (persona for thread contributions) → Agent starts working, reports progress via tasks → Agent writes to discussion thread as its Akh → Session is long-running, persists while work item is open → Admin can LoginSession to SSH in and inspect/debug (audit logged) → When work completes or is stopped: VM destroyed by default (configurable to keep for debugging) ``` ### Capabilities - Defined on the Work Item, derived from what the work needs - Examples: access to specific repos, GCP service accounts, k8s API, database credentials, network zones - anima-agent translates capabilities into VM provisioning config (mounted secrets, firewall rules, IAM bindings) - No allowlisting needed — the VM only has what the work item declares ### Skills Deployment - Workflow phases declare required AI skills - anima-agent deploys skills into the VM before the agent starts - Skills are versioned and stored (future: pulled from marketplace) ### Admin Access - `LoginSession` returns SSH connection details - For when AI gets stuck and a human needs to inspect VM state - Audit logged ### MCP Server (embedded in anima-server) The MCP server exists to give **agents running inside VMs** access to Anima data relevant to their work item. It is not a general integration point for external tools. - **Scoped tokens**: Each agent session gets a token that identifies it. Permissions and scope are stored server-side in the database — looked up on each request. - **No external tool access**: The desktop UI is the interface for humans. The MCP is the interface for Anima's own agents only. - **Read-heavy**: Agents read work item descriptions, thread history, documents, workflow phase requirements - **Limited writes**: Post to thread (as Akh), update task status, flag for human review - **Token lifecycle**: Token provisioned when agent session starts, scope stored in DB, revoked on session end ``` anima-agent provisions VM → generates MCP token (identifies agent session) → scope stored in DB (work item context, allowed permissions) → deploys token into VM alongside skills → AI agent inside VM uses MCP to read context and report back → token revoked on session end ``` ### Future: Multi-Provider Orchestration The v1 `AgentProviderService` interface supports future expansion: - An **Agent Orchestrator** sits in front of multiple providers - Providers register capabilities (GCP provider, bare-metal provider, corporate-net provider, Docker provider) - Orchestrator matches work item capabilities to provider capabilities and dispatches - Each provider manages its own VM pool - Scheduler places work on providers based on access requirements (GCP for GCP deployments, corporate-net machine for firewalled k8s API, etc.) ## anima-ai Service ### Model Tiers anima-ai supports multiple model tiers. Callers specify the tier, not the model — the service maps tiers to configured models. | Tier | Use Cases | Model Characteristics | |------|-----------|----------------------| | **Minimal** | Mail classification, spam screening, routing | Smallest/cheapest available | | **Standard** | Summaries, description generation, thread digests | Mid-range, good at text | | **Reasoning** | Gap analysis triggers, code review decisions, capability derivation | Stronger reasoning, higher cost | ### API (internal gRPC, called by anima-server) - `ClassifyMail(mail) → work_item_id, confidence` — minimal tier - `Summarize(thread/document) → summary` — standard tier - `GenerateDescription(context) → description` — standard tier - `AnalyzeGap(plan, implementation_state) → gap_report` — reasoning tier - `ShouldReview(work_item, changes) → review_decision` — reasoning tier - `DeriveCapabilities(work_item) → capabilities` — reasoning tier ### Design Principles - **Stateless**: no persistent state, reads context from anima-server per request - **Horizontally scalable**: run N instances behind a load balancer - **Model-agnostic**: tier mapping is configuration, swap models without code changes - **Cost-conscious**: always use the cheapest model that can do the job ## Authentication & Authorization ### Authentication - **Users (humans)**: Session-based auth against anima-server. Login via credentials (v1), future: OIDC/SSO. - **Desktop client**: Authenticates on launch, receives a session token, attaches to all gRPC calls. - **Inter-service**: anima-mail, anima-ai, anima-agent authenticate to anima-server with service tokens (pre-shared, rotatable). - **Agent MCP tokens**: Tokens identify the agent session only. Scope and permissions are stored server-side in the database, looked up on each request. Revocation is instant. ### RBAC System Full role-based access control: - **Permissions**: granular actions (e.g., `workitem.create`, `workitem.read`, `thread.post`, `plan.update`, `agent.login`, `mailbox.manage`) - **Roles**: named collections of permissions, stored in database (e.g., Owner, Admin, Member, Viewer) - **Role bindings**: user + project + role, stored in database - Custom roles are a configuration change, not a code change. v1 ships with sensible defaults. | Concept | Storage | Example | |---------|---------|---------| | Permission | Code-defined enum, referenced in DB | `workitem.update`, `agent.login` | | Role | DB row, has many permissions | "Admin" → [workitem.*, plan.*, agent.login, ...] | | Role Binding | DB row: user + project + role | Till → Project Anima → Owner | | MCP Token | DB row: token ID → agent session ID | Token abc123 → Session S-42 | | MCP Scope | DB row: session → work item → allowed permissions | S-42 → WI-17 → [thread.post, workitem.read] | ### v1 Simplifications - No OIDC/SSO, just username/password - Service tokens are static config, rotated manually ## Crate & Repository Structure ### Workspace Layout ``` anima/ ├── proto/ # Protobuf definitions │ └── anima/v1/ # Versioned API │ ├── project.proto │ ├── plan.proto │ ├── workitem.proto │ ├── workflow.proto │ ├── thread.proto │ ├── agent.proto │ ├── repository.proto │ ├── mailbox.proto │ ├── document.proto │ ├── akh.proto │ ├── team.proto │ ├── dashboard.proto │ └── ai.proto # Internal: anima-server → anima-ai │ ├── crates/ │ ├── anima-core/ # Domain types, RBAC, shared logic │ ├── anima-db/ # PostgreSQL migrations, queries (sqlx) │ ├── anima-proto/ # Generated protobuf code (tonic-build) │ ├── anima-server/ # Main server binary + embedded MCP │ ├── anima-mail/ # Mail worker binary │ ├── anima-agent/ # Agent manager binary │ ├── anima-ai/ # AI inference service binary │ └── anima-desktop/ # Slint desktop client │ ├── docs/ │ └── superpowers/specs/ # Design specs │ ├── main.pen # Penpot design file ├── projectbrief.txt # Project brief ├── Cargo.toml # Workspace root └── README.md ``` ### Crate Dependencies | Crate | Type | Depends On | |-------|------|------------| | **anima-core** | lib | — | | **anima-proto** | lib | anima-core | | **anima-db** | lib | anima-core | | **anima-server** | bin | anima-core, anima-proto, anima-db | | **anima-mail** | bin | anima-proto, anima-core | | **anima-agent** | bin | anima-proto, anima-core | | **anima-ai** | bin | anima-proto, anima-core | | **anima-desktop** | bin | anima-proto, anima-core | ### Key Rust Dependencies - **tonic** / **prost** — gRPC server & client, protobuf - **sqlx** — async PostgreSQL with compile-time query checking - **slint** — desktop UI - **tokio** — async runtime - **jmap-client** or custom — JMAP protocol for Stalwart ## Forge Integration - **Read-only** forge API integration for GitHub, Gitea, GitLab - Pull PR/merge request metadata, link to work items - Issue migration path: import existing issues as work items - **Anima owns work items** — no dual issue tracking on forges - Git operations (clone, commit, push) only happen inside agent VMs (heavy work) - Patches and documents are attachments stored in Seshat's Library for AI ingestion - AI reads forge data via MCP when needed during agent sessions ## Out of Scope (v1) - **Mobile**: The project brief envisions mobile as a "quick response on the go" UI. Not in v1. - **Multi-provider agent orchestration**: v1 runs a single agent provider. Multi-provider scheduling is a future expansion. - **Workflow marketplace**: v1 ships defaults and allows custom workflows. Marketplace comes later. - **OIDC/SSO**: v1 uses username/password. Federation is future work. ## Integration Boundaries ### Seshat's Library Seshat's Library is a **separate running service** with its own API. anima-server communicates with it as an external dependency (like PostgreSQL or Stalwart), not as a linked crate. It provides: - Blob storage for files, patches, attachments - Vector embeddings (pgvector) for AI-searchable document library - Its own API surface that anima-server calls into ### Stalwart anima-mail connects to Stalwart via two interfaces: - **JMAP** for reading/sending mail (prefer JMAP EventSource push over polling where available) - **Admin REST API** for mailbox lifecycle management ### Forge APIs PR/issue metadata is fetched **on-demand** when viewing a work item or repository, not continuously polled. Webhooks can be added later for real-time PR status updates if needed.