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¶
- Connectors → Overview for what pulls data into PocketBase.
- Operating → The jarvis CLI for the full command reference.