Skip to content

How it fits together

How the app, PocketBase, agents, and connectors relate to each other.

The compose services

compose.yaml is the production deploy path (docker compose -f compose.yaml up). compose.override.yaml layers in dev-only behavior — bind mounts, seeding, stub env — and is auto-merged whenever you run a bare docker compose up, which is what ./jarvis up does. So in day-to-day dev, you always get the merged (base + override) stack.

Base stack (compose.yaml)

Service Image Role
pocketbase jarvis-pocketbase:0.39.10 The backend hub. Published on 127.0.0.1:8091 → container port 8090. Data persisted in the pb_data volume. Healthchecked via /api/health.
agent jarvis-agent:dev The Python agent framework smoke container. restart: "no" — it's not a long-running daemon.
scheduler jarvis-scheduler:dev Runs supercronic against a crontab baked into the image at build time (backend/generated/crontab). Uses init: true so tini runs as PID 1 — supercronic itself isn't safe as PID 1 on some Docker/Linux-VM setups. Writes to the vault volume.

Dev overrides (compose.override.yaml)

Service Role
pocketbase (override) Replaces the entrypoint to upsert the dev superuser (idempotent) before serving. Production uses the image's default CMD, with no auto-created superuser.
agent / scheduler (override) Bind-mount agent-runtime/src (and, for scheduler, also modules/ and backend/generated/crontab read-only) so code and crontab edits are picked up without a rebuild.
bootstrap One-shot container that runs seed.py to seed dev data. Dev-only; not present in the base stack.
cli On-demand container for the jarvis CLI, only started under the cli profile (profiles: ["cli"]) — used by ./jarvis cli ....

Note

Because compose.override.yaml merges in automatically on a bare docker compose up, ./jarvis up always gives you the dev-flavored stack above. A real production deploy runs docker compose -f compose.yaml up explicitly, skipping the override.

Data flow

flowchart TD
    App["Flutter app"]
    PB[("PocketBase
127.0.0.1:8091")] Sch["scheduler"] Agent["agent"] App <-->|REST + realtime| PB Sch -->|read / write| PB Agent -->|read / write| PB

The app and every agent talk only to PocketBase — never directly to each other. The scheduler and agent containers reach PocketBase over the internal compose network, at http://pocketbase:8090; the app talks to the published http://127.0.0.1:8091.

Note

Host-only connectors (iMessage, homelab) and the MCP server run outside Docker, on the host via launchd — they are not part of this compose stack at all. See Operating → Host agents & launchd.

Next