Add Anima system design spec
Comprehensive design covering service architecture (anima-server,
anima-mail, anima-agent, anima-ai, anima-desktop), domain model,
gRPC API, Slint desktop client, mail integration via Stalwart/JMAP,
agent VM lifecycle, embedded MCP server, RBAC, and crate structure.
2026-04-12 01:00:55 +02:00
# 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)
2026-04-12 01:02:23 +02:00
→ When work completes or is stopped: VM destroyed by default (configurable to keep for debugging)
Add Anima system design spec
Comprehensive design covering service architecture (anima-server,
anima-mail, anima-agent, anima-ai, anima-desktop), domain model,
gRPC API, Slint desktop client, mail integration via Stalwart/JMAP,
agent VM lifecycle, embedded MCP server, RBAC, and crate structure.
2026-04-12 01:00:55 +02:00
```
### 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
2026-04-12 01:02:23 +02:00
## 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.