Sophon 2.0 is here
Sophon Docs
Self-Hosting

Backup & Upgrade

Data persistence, backup and restore procedures, upgrading Sophon, and rollback.

What's Stored Where

DataLocationTier
Configuration, agents, skills, memory, documents, logsSOPHON_DATA (host bind mount)All
Encryption key (vault.key)SOPHON_DATA/security/vault.keyAll
SQLite databaseSOPHON_DATA/data/sophon.dbPersonal
PostgreSQL datapgdata named volumePro, Enterprise
Qdrant vector dataqdrantdata named volumePro, Enterprise
Redis dataredisdata named volumeEnterprise
RabbitMQ datarabbitmqdata named volumeEnterprise

Backup

Sophon Data Directory

The most important backup — contains your configuration, agents, skills, documents, memory, and encryption keys.

# Stop Sophon (optional but recommended for consistency)
docker compose down

# Create a timestamped backup
tar czf sophon-backup-$(date +%Y%m%d).tar.gz -C "$SOPHON_DATA" .

PostgreSQL (Pro/Enterprise)

# While running
docker compose exec postgres pg_dump -U sophon sophon \
  > sophon-db-$(date +%Y%m%d).sql

# Or with compression
docker compose exec postgres pg_dump -U sophon -Fc sophon \
  > sophon-db-$(date +%Y%m%d).dump

Qdrant (Pro/Enterprise)

# Create a collection snapshot
curl -X POST http://localhost:6333/collections/sophon/snapshots

Snapshots are stored inside the qdrantdata volume. Copy them to your backup location.

Redis (Enterprise)

Redis with --appendonly yes persists to disk automatically. The data lives in the redisdata named volume. To back up:

# Trigger a save
docker compose exec redis redis-cli -a "$REDIS_PASSWORD" BGSAVE

# Copy the volume data
docker run --rm -v sophon_redisdata:/data -v $(pwd):/backup \
  alpine tar czf /backup/redis-backup-$(date +%Y%m%d).tar.gz -C /data .

Restore

Sophon Data Directory

# Stop Sophon
docker compose down

# Restore from backup
mkdir -p "$SOPHON_DATA"
tar xzf sophon-backup-20260324.tar.gz -C "$SOPHON_DATA"

# Restart
docker compose up -d

PostgreSQL

# From SQL dump
docker compose exec -T postgres psql -U sophon sophon \
  < sophon-db-20260324.sql

# From compressed dump
docker compose exec -T postgres pg_restore -U sophon -d sophon \
  < sophon-db-20260324.dump

Qdrant

Restore from the Qdrant snapshot API:

curl -X PUT "http://localhost:6333/collections/sophon/snapshots/recover" \
  -H "Content-Type: application/json" \
  -d '{"location": "file:///qdrant/storage/snapshots/sophon/<snapshot-name>.snapshot"}'

The vault.key File

The file at SOPHON_DATA/security/vault.key contains the AES-256 encryption key used to encrypt all credentials at rest — API keys in models.json, channel tokens in channels.json, and speech-provider keys.

If you lose this file, all encrypted credentials become unrecoverable. You would need to re-enter every API key and re-authenticate every channel.

Always verify vault.key is included in your backups:

# Verify it exists in a backup archive
tar tzf sophon-backup-20260324.tar.gz | grep vault.key

Upgrading

Upgrading to v2.0.0

Back up first. The first time the v2.0.0 Gateway starts, it applies five new database migrations automatically. There is no automatic downgrade path: going back to 1.15 means restoring the backup you took before upgrading. Stop the Gateway, then back up the data directory (and, on Pro and Enterprise, the PostgreSQL database) using the Backup steps above.

On Docker, change both image tags in your compose file to 2.0.0 (images are published with exact version tags only), then follow Pull and Restart.

Data and backups

  • Five migrations, applied on first start. They add storage for Sophon Graph runs, plan revisions and approval escalation, and give every conversation event a unique sequence number. If an earlier version wrote two events in one conversation with the same number, the migration renumbers the duplicates and moves them after that conversation's last event, so they appear at the end of its history. No events are removed.
  • SQLite now uses write-ahead logging (Personal tier). While the Gateway runs, sophon.db-wal and sophon.db-shm may appear next to data/sophon.db, and recent writes can sit in the -wal file until they're merged into the database. Stop the Gateway before you copy the database by hand, and keep the side files with it if they're present. The tar command under Backup copies the whole data directory, so it already includes them. WAL mode is stored in the database file itself.

Behavior changes

  • Sophon Graph is on by default. Approved multi-step plans now run in Graph mode, including plans made by scheduled, heartbeat and webhook runs. To use Classic, the previous step-by-step engine:

    • One conversation: the execution-mode pill in the Dashboard chat composer, or /mode classic in the CLI (/mode default returns to your default).
    • Your default: Settings → Execution → Execution mode.
    • Everyone (admin): switch off Enabled under Settings → Execution → Graph runtime, or set Sophon:GraphRuntime:Enabled to false in config/appsettings.user.json (environment variable SOPHON__GraphRuntime__Enabled=false). This puts every user on Classic.

    Graph supports a single Gateway instance, so turn it off if you run more than one Gateway replica. Dependent sub-agent tasks also need Graph: with it off, they fail with a clear error instead of running out of order.

  • The CLI opens full screen. sophon now starts the full-screen chat, and its first run tells you how to switch back. Opt out for one session with SOPHON_CLI_FULLSCREEN=0 sophon, or for good with "fullScreen": false in ~/.sophon/config/cli.json. Small windows, redirected output, the Dashboard's built-in terminal and an active Windows screen reader fall back automatically; if a terminal can't switch to full screen, the CLI tells you to re-run with SOPHON_CLI_FULLSCREEN=0. In the full-screen chat a newline is Alt+Enter, not Shift+Enter. If a terminal is left in a bad state, run sophon doctor --reset-terminal. See Interactive chat.

  • Prompt-injection detection defaults to Warn. In 1.15 it only annotated and logged. It now has three modes: Off, Warn (the default) and Block. In Warn, a detection shows as a notice card in the conversation and is written to the audit log; Block is opt-in. An admin changes the mode in the Dashboard under Settings → Security, or with Sophon:PromptInjection:Mode. If you had turned detection off (Sophon:PromptInjection:Enabled or DetectionEnabled set to false), it stays off. The guard matches known phrasing and is not a security boundary. See Prompt injection.

  • Spending budgets may trigger sooner. Usage of models newly added to the catalog used to be recorded at $0. It now carries an estimated cost based on list prices, so spending budgets count it and may trigger where they did not before. Review your budget limits if you use those models.

  • Marketplace automatic updates are new and off by default. Nothing changes until an admin turns on Settings → Marketplace → Automatic updates (Sophon:Marketplace:AutoUpdate). When on, the regular update check also installs new versions through the verified install path and rolls back a failed update.

Integrations and APIs

  • Session list. GET /api/sessions now returns top-level conversations only (view=top is the default), hiding plan-step and sub-agent sessions. Pass view=all for the previous flat list, or view=children&parentId=<id> for one conversation's agent activity. The realtime session list uses the same default.
  • Deciding approvals. POST /api/approvals/{id}/decide now accepts only approved, rejected, edited or timed_out (any casing); any other value returns 400 with the list of allowed values. Deciding an approval that already has an outcome no longer overwrites it: the response is 200 with the recorded outcome and alreadyDecided: true. An approval whose caller cancels the wait is now recorded as cancelled rather than timed_out. Sender approvals are unchanged.
  • Node voice routes. /api/nodes/me/voice/runtime, /state and /wake return 404 until you set Sophon:Voice:NodeWake:Enabled to true. No shipped client calls them, so most installs see no change. When enabled, /wake requires the node's voice permission, is rate-limited per node, and rejects over-long transcripts.
  • Custom SignalR clients. VoiceStatus is no longer sent when a speech-to-text stream opens; it now only means the reply finished. Transcript events carry utteranceId, and VoiceUtteranceStarted {sessionId, utteranceId} announces each utterance, so a client can accept a final transcript only for the utterance most recently announced to it (a client that ignores the event keeps working). ApprovalResolved {id, outcome, sessionId, escalationSessionId} is broadcast on /hubs/chat with outcomes approved, rejected, timed_out or cancelled, InfoRequestAnswered gains cancelled: true, and StreamAudio accepts a third mode value, "answer", which transcribes without starting an agent turn. See SignalR events.
  • Paired devices. The agent can reach only devices owned by the requesting user; launching, closing or focusing an app now asks for approval; the ungated single-command passthrough tool is gone; and desktop command results use camelCase field names, with the app-launch parameter named name. See Node protocol.

Skills and developer tools

  • proxy credentials. Skills whose manifest declares the deprecated "access": "proxy" credential mode now receive the stored credential inside their sandbox, exactly like "injected". In 1.15 they received nothing, so those skills didn't work. Brokered proxy calls are not implemented. Before upgrading, check which installed skills declare credentials. See Credential vault.
  • sophon dev exit codes. Failing sophon dev commands now exit non-zero, so scripts and CI no longer treat a broken project as a success. sophon dev validate also now fails when an entry point's source file is missing (a missing .cs file used to be only a warning).

Upgrading to v1.15.0

Upgrading to v1.15.0: this release ships 8 new database migrations that are applied automatically the first time the upgraded Gateway starts. Migrations are one-way — take a backup of the data directory and database first, using the Backup steps above. Once you're on 1.15, you can also create data-directory backups from the Dashboard at Settings → Backup (see Backup & Export).

Pull and Restart

# Pull the image tags pinned in your compose file
docker compose pull

# Restart with new images
docker compose up -d

EF Core database migrations run automatically on startup. No manual migration step is needed.

Upgrade Checklist

  1. Back up your data directory and database (see above)
  2. Pull the pinned image tags
  3. Restart the services
  4. Verify the health check passes: curl http://localhost:8081/api/health
  5. Check logs for migration errors: docker compose logs sophon-gateway

Pinning a Version

To avoid unexpected upgrades, pin a specific image tag:

services:
  sophon-gateway:
    image: buildersoftdev/sophon:2.0.0
  sophon-dashboard:
    image: buildersoftdev/sophon-dashboard:2.0.0

Rollback

If an upgrade causes issues:

  1. Stop the services: docker compose down
  2. Restore from your backup (data directory + database)
  3. Pin the previous image tag in your compose file
  4. Restart: docker compose up -d
# Example: rollback to 1.1.0
docker compose down

# Restore data
tar xzf sophon-backup-20260324.tar.gz -C "$SOPHON_DATA"

# Restore database (Pro/Enterprise)
docker compose up -d postgres
docker compose exec -T postgres psql -U sophon sophon < sophon-db-20260324.sql

# Update compose to pin old version
# image: buildersoftdev/sophon:1.1.0

docker compose up -d