Add out-of-scope section (mobile, multi-provider, marketplace, OIDC), integration boundaries (Seshat's Library, Stalwart, Forge APIs), VM default retention policy (destroy by default), and JMAP push preference.
23 KiB
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,ArchiveProjectListProjectMembers,AddProjectMember,RemoveProjectMember
PlanService
ListPlans,GetPlan,CreatePlan,UpdatePlan,DeletePlan
WorkItemService
ListWorkItems,GetWorkItem,CreateWorkItem,UpdateWorkItem,DeleteWorkItemGetDescriptionRevisions,RevertDescription— versioned description managementListCapabilities,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,StopSessionLoginSession— returns connection info for admin SSH/shell accessListTasks,GetTask,UpdateTaskStatusStreamSessionStatus— server-streaming for live status
RepositoryService
ListRepositories,AddRepository,RemoveRepositoryListPatches,AttachPatch— link forge PRs to work items
MailboxService
ListMailboxes,CreateMailbox,DeleteMailboxLinkProjects,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 projectsStreamDashboardUpdates— 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
ClassifyMailto 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
LoginSessionreturns 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 tierSummarize(thread/document) → summary— standard tierGenerateDescription(context) → description— standard tierAnalyzeGap(plan, implementation_state) → gap_report— reasoning tierShouldReview(work_item, changes) → review_decision— reasoning tierDeriveCapabilities(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.