Deploying on a Server
The reference deployment is a single central instance on a trusted
server, with every workstation as a thin client. This chapter condenses
the full runbook (docs/deploy/central-instance.md in the repository) to the
essentials.
Topology
workstations (pi, agents) the central instance (always-on host)
┌────────────────────┐ HTTP ┌──────────────────────────┐
│ IJIMA_URL=... │──────────▶│ ijima serve (systemd) │
│ IJIMA_TOKEN=... │ tailnet │ /var/lib/ijima (NVMe) │
└────────────────────┘ │ zpool/backups (nightly) │
└──────────────────────────┘
- Network: Tailscale; the daemon binds the tailnet interface. TLS via
tailscale serve(terminates on the tailnet’s certs) or thetlsfeature directly. - Storage: data directory on fast local disk (SurrealDB/surrealkv); nightly snapshots to bulk storage.
Provision checklist
- Install the binary (see Getting Started) with
cli,backend-sqlite,embeddings-candle,mining,tlsas needed. /etc/ijima/ijima.toml— host/port/data_dir/issuer_key (copy fromdeploy/ijima.toml.example).deploy/ijima.service→ systemd;systemctl enable --now ijima.- Mint grants per principal (operators, harnesses, machine feeds) — Token Management — via the principals overlay policy.
- Grant shared-namespace memberships for the org walls:
ijima namespace grant ns_ia_shared <principal> --auth <admin>(repeat forns_kellas_shared,ns_shiroyama_shared,ns_writing_sharedas needed). curl .../healthliveness;GET /status(admin) for counts.- Import workstation corpora — Importing Legacy Corpora.
- Point each workstation’s
IJIMA_URL/IJIMA_TOKENat the instance.
Backup & restore
The store is a directory. The drill:
systemctl stop ijima
zfs snapshot zpool/backups/ijima@$(date +%F) # or rsync the directory
systemctl start ijima
Restore = stop, replace the directory, start. Run the drill once before trusting it.
Upgrades
systemctl stop ijima && <install new binary> && systemctl start ijima
Schema definitions are idempotent at open. Check the CHANGELOG for on-disk-layout notes before skipping multiple minors.
Backups and restore drills
SurrealKV is a directory; a naive file copy of a live store can be torn (manifest/WAL disagreeing mid-write) — recoverable, but you want to know before an incident. The pattern that works in production:
- Mirror hourly — rsync the data dir to bulk storage (a snapshot- managed filesystem if you have one). A torn copy is possible; the next hour’s mirror replaces it.
- Drill weekly — copy the mirror aside, boot a throwaway daemon on it (second port, same binary), compare the census against live. Log PASS / DEGRADED (opens, counts differ — writes during the mirror window) / FAIL (does not open). A backup you have never opened is a hope, not a backup.
- Mind permissions — a root-run mirror leaves secrets root-owned; a restore runbook needs the chown step.
Logical export (JSONL through the daemon)
ijima export --url <daemon> --token <admin> [--namespace <ns>] [--out file]
streams every memory (or one wall’s) as JSONL — one {"namespace": …, "memory": {…}} object per line, row count in the x-export-count
header. It runs through the daemon API and so works against a live
instance; the old direct-to-store SQL dump lost the store LOCK race
to the running daemon and is gone (v0.3.0).
The honest tiering: the mirror + drill above remains the primary restore path. Export is the extractable corpus — verification, offline analysis, compliance — and an ad-hoc restore is a documented loop rather than a first-class command:
# restore one wall's rows into another daemon (jq, not a database tool)
ijima export --url old --token t --namespace ns_wall --out wall.jsonl
jq -c '.memory' wall.jsonl | while read -r mem; do
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d "$mem" "$NEW_URL/memories?namespace=ns_wall" > /dev/null
done
Re-POSTing is idempotent at the content layer (duplicates collapse), but provenance fields (source, harness) are re-stamped — a logical restore is a re-ingestion, not a byte copy. Point-in-time fidelity stays with the mirror.
First-day verification
After provisioning: import one real workstation, run a pi session against
the central instance for a day, and confirm /status counts grow. The
deployment isn’t real until a harness has lived on it.