Skip to content
DocumentationAPI ReferenceChangelog
Getting StartedTalon Studio v1.0.2-beta

Architecture

How the single-container appliance fits together: Next.js, embedded PostgreSQL, the pySigma sidecar, and a local Git store on the /data volume.

What it is

Talon Studio is a vendor-neutral, single-container appliance that you run on your own infrastructure. The default deployment is deliberately simple: one Docker container for the platform and one mounted /data volume, with the assistant's voice in a second, optional container. There is no external database, message broker, or worker fleet to run — everything the platform needs is inside the image.

A single Next.js process serves the UI and API and runs background workers. Alongside it, an embedded PostgreSQL instance stores operational state and an embedded pySigma sidecar handles Sigma validation and query translation. Detection content lives in a local Git store. All durable state is on the /data volume.

How it works

The platform runs inside one container, with one volume for durable state. Spoken replies come from a second container, kokoro, which the release compose file runs beside it; without it, the browser's own voice reads replies.

talon-studio · one container:3000 exposed
Next.js app
UI · API · workers · :3000
Embedded Postgres
127.0.0.1:5432 — never exposed
pySigma sidecar
validate + translate · 127.0.0.1:8001
/datapostgres · secrets · repos (one per workspace) · content clones · uploads · logs
Next.js app
UI, API routes, auth, settings, and background loops — one process, serving HTTP on port 3000.
Embedded Postgres
Durable product database and indexed content cache. Listens on 127.0.0.1 inside the container; never published.
Embedded pySigma
Sigma validation, SIEM query translation and local text embeddings, on 127.0.0.1:8001 inside the container.
Local Git store
Detection-as-code audit trail, one repo per workspace under /data/repos.
/data volume
All durable appliance state: database, generated secrets, repos, content clones, uploads and logs.

The boot order is fixed. The entrypoint generates any secret you did not provide, starts Postgres (running initdb on an empty volume), starts pySigma and waits for it to answer, runs pending database migrations, and only then starts the app. The app checks its configuration first and refuses to start on an insecure one, then creates the first admin if the database has no users. The entrypoint runs as root only to initialise the database and set volume ownership; Postgres runs as postgres, and pySigma, the migrations and the app run as the unprivileged talon user.

The products compose into one product loop. Connect introspects your SIEMs to learn what telemetry exists; Atlas maps that evidence onto MITRE ATT&CK coverage; Forge authors detections as code; Monitor and Replay validate them against ground truth; the release pipeline deploys to each SIEM; and the Command dashboard reads validation health, coverage, and drift back out.

Git is canonical, Postgres is a cache
Saved detections are written to the workspace's Git repo as YAML — that is the source-controlled audit trail. Postgres mirrors the same content so the UI reads are fast, but Git remains the source of truth and the handoff format.

Setup

You don't assemble these components — the image ships them together. Setup is about the one thing that must persist: the volume. Mount a single Docker volume at /data and everything lands under it.

/data volume layout
/data/postgres # embedded database
/data/secrets # generated secrets + first-admin password (0600)
/data/repos # one Git repo per workspace
/data/security_content # Splunk Security Content clone + index
/data/sigma # SigmaHQ rules clone + index
/data/atomic-red-team # Atomic Red Team clone + index
/data/azure-sentinel # Azure Sentinel content clone + index
/data/stratus-red-team # Stratus Red Team clone + index
/data/uploads # user uploads (profile avatars)
/data/logs # durable NDJSON logs, rotated
The pySigma sidecar is embedded — it starts with the container on 127.0.0.1:8001; nothing to install separately.
Embedded Postgres binds inside the container only. Never publish port 5432 or 8001.
Back up the /data volume before every upgrade — migrations run automatically on start, and they only run forward.

Usage

Operationally, treat the container as stateless and the volume as precious. Upgrades are docker compose pull && docker compose up -d; the new image reuses the same /data and runs any pending migrations on boot. The compose file is on the Install page.

The image serves plain HTTP on port 3000. Terminate TLS at your own reverse proxy or load balancer and point NEXTAUTH_URL at the HTTPS address. Health probes at /api/health (readiness — the database, pySigma and Git storage are usable) and /api/health/live (liveness) let your orchestrator manage the lifecycle.

Run one instance per volume. The appliance is single-instance by design: migrations take no lock, so two containers on the same data could race each other, and the Helm chart refuses to render more than one replica.

An external database is an env-var toggle: set TALON_DISABLE_EMBEDDED_PG=true with POSTGRES_URL pointing at your managed Postgres, and the entrypoint skips the embedded one, waits up to 60s for yours to answer, and exits non-zero if it never does. A POSTGRES_URL to a host other than loopback must carry sslmode=require (or verify-ca / verify-full), or the app refuses to start. The /data volume is still needed for the repos, secrets and content.

Shutting down cleanly
Don't force-kill the container. On SIGTERM/SIGINT the app drains in-flight Git write queues (bounded at 15s) before exiting, and the entrypoint gives it up to 30s to do so before stopping Postgres underneath it. Docker's default grace period is 10s, so give it longer: docker compose down -t 45, or stop_grace_period: 45s on the service.