From 9adec1028c3b32989ae5da8c57bc303d68020527 Mon Sep 17 00:00:00 2001 From: Jacob Nelson Date: Sun, 23 Aug 2026 17:24:06 -0500 Subject: [PATCH] feat(agent): containerize agent and wire into compose stack --- .env.example | 9 +++++++++ README.md | 2 ++ agent/.dockerignore | 4 ++++ agent/Dockerfile | 13 +++++++++++++ agent/README.md | 40 ++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 12 ++++++++++++ 6 files changed, 80 insertions(+) create mode 100644 agent/.dockerignore create mode 100644 agent/Dockerfile create mode 100644 agent/README.md diff --git a/.env.example b/.env.example index c12190c..b8e071c 100644 --- a/.env.example +++ b/.env.example @@ -60,3 +60,12 @@ STATIC_CRON_TOKEN=REPLACE_WITH_RANDOM_HEX # --- SimpleFIN Bridge (optional — simpler US bank automation, ~$1.50/mo) --- # Connect accounts at https://bridge.simplefin.org, then paste the access URL below # SIMPLEFIN_URL= + +# --- Accounting Agent --- +# Firefly API base URL as seen from inside the compose network +FIREFLY_API_URL=http://app:8080 +# Personal Access Token: Firefly UI -> Options -> Profile -> OAuth -> Personal Access Tokens +AGENT_FIREFLY_TOKEN=REPLACE_WITH_PERSONAL_ACCESS_TOKEN +# Name of the agent's own database inside the existing Postgres container +AGENT_DB_NAME=agentdb +HEARTBEAT_INTERVAL_MINUTES=60 diff --git a/README.md b/README.md index 11bd13e..f8f11aa 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ # Firefly III - jbnel.dev Finance Stack + +`agent/` — personal accounting agent worker; see `agent/README.md` and `docs/superpowers/specs/`. diff --git a/agent/.dockerignore b/agent/.dockerignore new file mode 100644 index 0000000..4d8f010 --- /dev/null +++ b/agent/.dockerignore @@ -0,0 +1,4 @@ +tests/ +__pycache__/ +*.egg-info/ +.pytest_cache/ diff --git a/agent/Dockerfile b/agent/Dockerfile new file mode 100644 index 0000000..e737d28 --- /dev/null +++ b/agent/Dockerfile @@ -0,0 +1,13 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY pyproject.toml ./ +COPY src ./src + +RUN pip install --no-cache-dir . + +HEALTHCHECK --interval=60s --timeout=10s --start-period=30s \ + CMD ["python", "-m", "agent.healthcheck"] + +CMD ["python", "-m", "agent"] diff --git a/agent/README.md b/agent/README.md new file mode 100644 index 0000000..685cd5f --- /dev/null +++ b/agent/README.md @@ -0,0 +1,40 @@ +# firefly-agent + +Worker container for the personal accounting agent. See the architecture spec: +`docs/superpowers/specs/2026-08-23-accounting-agent-architecture-design.md`. + +## What it does (Phase 1) + +On startup: creates `agentdb` in the stack's Postgres if missing, applies SQL +migrations from `src/agent/migrations/`, runs one heartbeat, then schedules the +heartbeat every `HEARTBEAT_INTERVAL_MINUTES`. The heartbeat calls Firefly's +`/api/v1/about` and records the outcome in `sync_runs`. + +## Development + + python3 -m venv .venv && source .venv/bin/activate + pip install -e './agent[dev]' + cd agent && pytest # needs Docker running (testcontainers) + +## Configuration + +All via environment variables (see `.env.example`, "Accounting Agent" section): +`FIREFLY_API_URL`, `AGENT_FIREFLY_TOKEN` (required), `AGENT_DB_NAME`, +`HEARTBEAT_INTERVAL_MINUTES`, plus the existing `DB_HOST`/`DB_PORT`/ +`POSTGRES_USER`/`POSTGRES_PASSWORD`. + +## Deploy & verify + + # on the host, in the repo directory + git pull + docker compose build agent + docker compose up -d agent + docker compose exec agent python -m agent.verify + +Expected verify output: agentdb OK with migrations applied, recent heartbeat +runs, Firefly version, and your asset accounts listed. + +Inspect heartbeats directly: + + docker compose exec db psql -U firefly -d agentdb \ + -c "SELECT connector, status, finished_at FROM sync_runs ORDER BY id DESC LIMIT 5;" diff --git a/docker-compose.yml b/docker-compose.yml index f94c4b0..d4a466c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -66,6 +66,18 @@ services: - "traefik.http.services.firefly-importer.loadbalancer.server.port=8080" - "traefik.docker.network=traefik_proxy" + agent: + build: ./agent + restart: unless-stopped + env_file: .env + networks: + - firefly + depends_on: + db: + condition: service_healthy + app: + condition: service_healthy + db: image: postgres:16-alpine restart: unless-stopped