Skip to main content
Trinity

Upgrading Trinity

Apply code changes safely to a running Trinity instance. The procedure below keeps agent containers running throughout the upgrade — only the platform services are restarted.

When to Run This

Run this procedure before or after every git pull that includes changes to platform code (backend, frontend, MCP server, scheduler). Skip it for documentation-only changes.

Pre-flight Checklist

  • Back up the database (Step 1 below — do this first, always)
  • Confirm at least 2 GB disk free: df -h /
  • Note the current Git SHA: git rev-parse HEAD
  • Check that no critical agent tasks are running: docker ps --filter "label=trinity.platform=agent"
  • Confirm Docker is running: docker info >/dev/null 2>&1

Step 1: Back Up the Database

The database is the critical state. Back it up before every upgrade.

Development (named volume)

docker run --rm \
  -v trinity_trinity-data:/data \
  -v ~/backups:/backup \
  alpine cp /data/trinity.db /backup/trinity-$(date +%Y%m%d-%H%M%S).db

Production note: On a server using docker-compose.prod.yml, the database lives in a bind-mount directory (e.g., /srv/trinity-data/), not in the named volume. Adjust accordingly:

cp /srv/trinity-data/trinity.db ~/backups/trinity-$(date +%Y%m%d-%H%M%S).db

Verify the backup is readable:

sqlite3 ~/backups/trinity-<timestamp>.db ".tables"
# Expected: a list of table names, no errors

PostgreSQL deployments (instances running with DATABASE_URL set): back up with pg_dump instead of copying trinity.db — see Backup and Restore. PostgreSQL schema migrations run automatically on backend boot, same as SQLite.

Step 2: Pull Latest Changes

git pull origin main

Review what changed:

git log --oneline -10
git diff HEAD~1 HEAD --stat

If docker/base-image/Dockerfile appears in the diff, see Step 5: Base Image Upgrade below.

Step 3: Rebuild Platform Services

# Development
docker compose build --no-cache backend frontend mcp-server scheduler

# Production
docker compose -f docker-compose.prod.yml build --no-cache backend frontend mcp-server scheduler

The trinity-agent-base image is not rebuilt by this command. It changes much less often, and rebuilding it forces every agent to be re-deployed. Rebuild it only when docker/base-image/Dockerfile itself changes.

Step 4: Restart Platform Services

Use docker compose restart, not down/up. docker compose down removes the trinity-agent-network, orphaning every running agent container — they keep running but lose their network.

# Development
docker compose restart backend frontend mcp-server scheduler

# Production
docker compose -f docker-compose.prod.yml restart backend frontend mcp-server scheduler

Services restart in parallel. The backend typically takes 10–20 seconds to become healthy.

Step 5: Verify

Run the six-probe verification. All must pass before you declare the upgrade complete:

# 1. Backend
curl -s http://localhost:8000/health
# Expected: {"status":"healthy",...}

# 2. Scheduler
curl -s http://localhost:8001/health
# Expected: {"status":"healthy","active_schedules":N}

# 3. Frontend (HTTP 200)
curl -s -o /dev/null -w '%{http_code}' http://localhost
# Expected: 200

# 4. Redis
docker exec trinity-redis redis-cli ping
# Expected: PONG

# 5. MCP Server
curl -s http://localhost:8080/health
# Expected: 200 OK

# 6. Vector (log aggregation)
docker exec trinity-vector wget -q -O - http://localhost:8686/health
# Expected: non-empty response

Confirm the new version is live. After the probes pass, check that the backend is actually running the build you just deployed:

curl -s http://localhost:8000/api/version
# Expected: {"version":"0.6.0","git_commit_short":"<sha>","git_branch":"...","build_date":"..."}

The git_commit_short, git_branch, git_commit_subject, and build_date fields report the code that is actually running, not merely what was baked in at build time — so a container running mounted source, or one that drifted from its image, is reported honestly rather than claiming the image's commit. If they read "unknown", the image was built without the deploy script's build args — rebuild with scripts/deploy/start.sh to populate them.

The response also carries edition (oss or enterprise) and enterprise_features, so you can confirm after an upgrade that the entitlements you expect are actually registered.

The same metadata is visible in the UI via the version chip in the navigation bar (click it for the Build Info dialog) and in Settings.

Note: JWT tokens are invalidated when the backend restarts. Users with active web UI sessions will need to log in again. MCP clients (Claude Code) will need to reconnect — run /mcp in your Claude Code session or restart the client.

Base Image Upgrade (if needed)

Rebuild the base image only when docker/base-image/Dockerfile changes:

./scripts/deploy/build-base-image.sh

How agents pick it up. A rebuilt base image is adopted at an agent's next cold start— that is, the next time it goes from stopped to running. Trinity compares the running container's image against the current base image and recreates the container when they differ.

What this means in practice:

  • A running agent is never replaced out from under you. Drift is detected but not acted on until the agent is next started cold.

  • Restart the fleet (Operations) to roll the new image out: each agent goes through the normal lifecycle, so a drifted agent is recreated and an up-to-date one keeps its container.

  • The system agent (trinity-system) follows the same rule and is deliberately never replaced while running. If its image goes stale you get an operator alert rather than a mid-operation container swap; it adopts the rebuild the next time it is started cold.

  • Rebuilding the base image is what makes newly shipped agent-side features available. Skipping it means agents keep running the old runtime, which is usually harmless but occasionally leaves a feature silently inert.

Rollback

If something goes wrong after the upgrade:

1. Stop platform services

# Development
docker compose stop backend frontend mcp-server scheduler

# Production
docker compose -f docker-compose.prod.yml stop backend frontend mcp-server scheduler

2. Restore the database backup

# Development (named volume)
docker run --rm \
  -v trinity_trinity-data:/data \
  -v ~/backups:/backup \
  alpine cp /backup/trinity-<timestamp>.db /data/trinity.db

# Production (bind mount)
cp ~/backups/trinity-<timestamp>.db /srv/trinity-data/trinity.db

3. Check out the previous version

git checkout <previous-sha>
# or
git checkout <previous-tag>

4. Rebuild and restart

docker compose build --no-cache backend frontend mcp-server scheduler
docker compose restart backend frontend mcp-server scheduler

5. Run the six-probe verification to confirm rollback succeeded.