Skip to content

Architecture

Four layers, and one rule that shapes all of them: the domain core has no Tauri dependency, so the same operations layer serves the desktop app and the MCP hub.

Blueprint schematic titled 'AI-POS — what happens when an agent writes', subtitled 'the agent reaches the hub through .mcp.json; aipos-core has zero Tauri deps and one cross-process lock'. Four blocks. Entry: the agent CLI (claude or codex) calls aipos-mcp, the stdio hub, which checks policy through authorize(), the allowlist. Core: the hub reaches ops (tasks and notes), workflow (gates and phase), and sync (every write). Disk: ops writes tasks/, one file each; workflow appends to ledger.jsonl, append-only; sync rewrites AGENTS.md, read at start. App: sync notifies the watcher (notify and debounce), which tells the desktop app to re-read live. A legend keys the four arrow colours: agent call, authorisation, write, read back. The footer reads 'A denied call is still written to the ledger. Remove AI-POS and every file above stays readable.'

The drawing follows one hub call from the agent’s terminal down to disk. It leaves two things out on purpose: the app’s own write path — the UI reaches the same core through Tauri IPC, not through the hub — and cross-workspace delivery, which is covered in Teams.

App-level views: Projects, Teams, Agent sessions, Templates, Settings.

Workspace-level views: Dashboard, Tasks, Collaboration, Inbox, Specs, Ledger, Search, Tools, Terminal, Project settings.

The folders under src/ are a layering rule rather than a filing preference, and a test enforces the machine-checkable part of it. CONTRIBUTING.md in the repository root has the table.

It talks to the layer below over Tauri IPC, which carries lightweight DTOs and state diffs only. Three event families come back the other way:

  • workspace://changed: reload state from disk
  • ledger://appended: read the new tail only
  • terminal://output, terminal://exit, terminal://sessions

Thin on purpose.

  • commands.rs: the IPC surface. Heavy I/O always goes through spawn_blocking, so it never blocks the UI thread.
  • watcher.rs: the file watcher behind workspace://changed.
  • terminal.rs: the embedded terminal, a real PTY process per agent CLI (portable-pty; ConPTY on Windows). Sessions belong to the app layer, so switching workspaces does not interrupt them.
  • mcp_deploy.rs: resolves the bundled hub binary and writes the root .mcp.json pointer — also the “Repair connection” path.
  • git.rs: optional git init for fresh workspaces — the wizard’s checkbox, shown only when git is available; best-effort, never fails creation.

Zero Tauri dependencies, hexagonal.

  • agent.rs: hub tool authorisation, by tier and by the per-tool allowlist.
  • security/: crypto (AES-GCM) and secrets (an encrypted local key-value store).
  • workspace/: layout; atomic writes (temp + rename); the cross-process lock; tasks (files are the truth); the ledger (append-only JSONL); workflow (the harness state machine and its gates); templates; handoff (the checkpoint serialiser); sync (after every mutation, brings the takeover surfaces back up to date from one snapshot); bootstrap (writes the handoff layer); manifest; specs (folded on archive); modules; settings; doctor; assets (curriculum upgrade); registry; backup (portable zip); init; ops (the consistency layer); flywheel (post-mortem lessons under an evidence rule); ids (sequential T-0001 families, plus the UUIDs used for anything crossing workspaces); context; rules; teams; exchange; agent_catalog.
  • index/: scanning, language-agnostic chunking, and an FTS5 full-text index. A derivative, so it can always be rebuilt.
  • state.rs: thread-safe shared state.
  • orchestrator/: dormant. An LLMProvider port with adapters, a model registry and a cost router. Nothing in the app or the hub reaches it; groundwork only.
  • mcp/: archived. An rmcp client, kept as groundwork for a future tool gateway.

A stdio binary, spawned by the agent host through the workspace’s .mcp.json (the Claude CLI does this automatically; other hosts differ).

Its tool surface is one shape: authorise → core ops → ledger. Denied calls are recorded too.

The app and the hub reach the same workspace files. An agent and the app can write concurrently and safely because every mutation takes the same cross-process lock, held for the duration of one mutation; read paths stay lock-free.

Seeing an agent’s change appear in your window is a separate mechanism: the file watcher emits workspace://changed, debounced by 400 ms, and the UI reloads from disk.

See also Disk contract for what all of this writes to disk.