Product guides for self-host and digichat, then the per-module API reference — schemas, examples, and copy-as-Markdown for agents. Machine-readable OpenAPI lives in the explorer.
digithings is open-source, MIT-licensed AI infrastructure: modules that plug into the stack you already run rather than replacing it. digigraph orchestrates specialist sub-graphs — quant research, retrieval, vault, and chat. Self-hosted anywhere, BYOK, audit-on by default.
git clone https://github.com/digithings-ai/digithings && cd digithings
cp .env.example .env # add your keys
docker compose up -d
Each backend service exposes a liveness probe at GET /healthz. The service URLs and ports are defined in docker-compose.yml; reference them through env vars ($DIGIGRAPH_URL, $DIGIKEY_URL, …) rather than hardcoding an address.
Essential environment
OPENROUTER_API_KEY / OPENAI_API_KEY — LLM access via the LiteLLM proxy.
DIGIKEY_ADMIN_TOKEN — required to mint API keys (see Authentication).
DIGIKEY_PRIVATE_KEY_PEM — stable RS256 signing key for production.
See .env.example for the full, annotated list.
Useful make targets
make up / make down — start / stop the core stack.
make up-digichat — start the chat BFF + its Postgres.
make stack-local — run the Python services without Docker.
make test-unit — unit tests (no stack required).
Interactive OpenAPI for every HTTP surface lives at OpenAPI explorer — committed specs under docs/openapi/, not live FastAPI /docs on localhost.
Self-host from GHCR
Prefer published images when you do not want to docker compose build. Requires Compose **v2.24+** and a clone of the repo for compose files, config/, and .env (build context is not required). Stack images (digikey, digigraph, …) publish via publish-service-images.yml on main after promote — until those packages exist on GHCR, use docker compose build / make up instead.
DIGICHAT_IMAGE_TAG — digichat only; prefer vX.Y.Z from release-please.
All services bind loopback by default. Use Tailscale or Cloudflare Tunnel for remote access — never expose ports publicly. Full notes: docs/templates/self-host/README.md and docs/DEPLOYMENT.md in the repo.
digichat install
digithings ships **self-hosted** AI infra. Clients install digichat **releases from GitHub** and run them in their cloud or on-prem. There is no live shared digichat SaaS for clients. digithings.ai/chat is digithings' own install of the same product.
Install unit
docker pull ghcr.io/digithings-ai/digichat:v0.9.3
Git tag: digichat-vX.Y.Z
GHCR image: ghcr.io/digithings-ai/digichat:vX.Y.Z (currently published through v0.9.3)
Changelog: frontend/digichat/CHANGELOG.md
Pin a published tag — do not assume a version exists on GHCR until the digichat release workflow has published it from main.
Does not start digiquant / digisearch / digismith / heartbeat. Full operator guide: docs/digichat/INSTALL.md. Minimal compose overlays live under infra/digichat-release/.
Architecture overview
digigraph is the horizontal orchestrator. digisearch and digiquant each own vertical LangGraph pipelines and expose them as HTTP + MCP. digivault is the markdown knowledge vault. digikey issues RS256 JWTs; every protected service verifies JWKS. LiteLLM is the only LLM router. Loopback-only by default.
LiteLLM :4000 — provider proxy; Ollama in Compose on host :11435 (models optional)
Chat path (simplified)
Browser → digichat → digikey (session/JWT) → digigraph → LiteLLM; digigraph may call digisearch, digiquant, or digivault tools with the same JWT and X-Request-ID.
Non-negotiables
Polars only — never pandas
Pydantic v2 models on the wire
MCP-first tool design
NautilusTrader for all backtest / optimize paths
Never expose live-trading without explicit human approval
Canonical detail: root ARCHITECTURE.md and each module's ARCHITECTURE.md. This page's module sections below are the operator-facing API reference; machine-readable OpenAPI is at OpenAPI explorer.
Authentication
digikey is the single issuer of RS256 JWTs. Services verify tokens against digikey's JWKS and enforce per-route scopes. The flow: mint an API key (admin), exchange it for a short-lived JWT, then call services with Authorization: Bearer <jwt>.
curl -X POST $DIGIGRAPH_URL/workflow \
-H "Authorization: Bearer $JWT" -H "content-type: application/json" \
-d '{"prompt":"Backtest a momentum strategy on AAPL"}'
Scopes
digigraph:workflow, digigraph:chat, digigraph:mcp
digiquant:backtest, digiquant:optimize
digisearch:query, digisearch:ingest
JWTs are short-lived (default 900s); revoke a key via POST /v1/admin/keys/{id}/revoke.
Conventions
Liveness vs status
GET /healthz is the auth-exempt liveness probe — always {"ok": true}, for load balancers. GET /v1/status (digigraph, digismith) is a richer operator diagnostic; never use it for health checks.
validation_error — request body failed validation.
rate_limited — HTTP 429, with a Retry-After header.
Correlation
Send X-Request-ID to correlate a call across services; it is generated if absent and echoed on the response and in the audit log.
Rate limits & CORS
Mutating routes are rate-limited per IP (typically 10/min, 429 + Retry-After on breach). CORS uses an explicit allowlist (DIGI_CORS_ORIGINS) — no wildcard — with credentials enabled for session cookies.
digigraph
Orchestration · LangGraph state machine
core
A declarative graph decides what runs next — profile in, path out.
Overview
A LangGraph state machine routes each request to the right sub-graph — quant research, retrieval, or chat — through conditional edges keyed on the request profile and the run's state. DIGI_SUPERVISOR=1 adds an entry node that stamps the run and enforces a recursion budget; it does not pick the branch, and unset, requests enter the research graph directly.
Speaks the OpenAI API so existing clients work unchanged; LiteLLM handles routing, caching, and checkpointed state across hops.
Authentication
Endpoints accept a digikey-issued RS256 JWT in `Authorization: Bearer`. When no JWKS is configured the service runs in passthrough mode (dev/test only). `/healthz` and `/v1/status` are auth-exempt.
Strategy research that ends in a reproducible backtest, not a markdown file.
Overview
Atlas runs scheduled research and Hermes turns it into signals; backtests run on a real NautilusTrader engine with Optuna driving the parameter search.
Every run writes an append-only audit trail and a tearsheet. No broker adapter ships wired — the IB, Alpaca, and QuantConnect adapters are declared stubs, so reaching a live venue is your own deliberate integration.
Authentication
Backtest/optimize/pipeline routes accept a digikey JWT (optional in passthrough mode). Async jobs stream progress over SSE.
Composite research turn (plan → retrieve → aggregate) with citations.
auth · digisearch:query10/min/IPrequires the digisearch[agent] extra
MCP tools
digisearch_querySearch documents; returns formatted hits with score + preview.
digisearch_research_turnComposite research turn with citations (needs digisearch[agent]).
Stack
ChChromaAZAzure AI SearchOpenAIBS4BeautifulSoupPDFpdfplumberLangGraphFastAPI
Related
Links
digichat
Chat surface · Next.js BFF · BYOK
core
Talk to your stack with your keys, your models, your audit log.
Overview
A Next.js and React BFF streaming digigraph through the Vercel AI SDK, your key forwarded per request — never stored, never logged.
NextAuth handles identity; Postgres and Drizzle persist sessions for humans and agents alike.
Authentication
The deployed digithings.ai chat is an agentic Cloudflare Pages Function (no login) that grounds answers in the digivault docs. The full Docker BFF additionally authenticates users via NextAuth and exchanges a BFF session for a digikey JWT to call digigraph.
Run locally
compose
docker compose --profile digichat up -d
cli
make digichat-dev # Next.js dev server with hot reload
curl -X POST $DIGICHAT_URL/api/chat \
-H "content-type: application/json" \
-d '{"messages":[{"role":"user","content":"What does digigraph do?"}]}'
GET/api/conversations
List persisted conversations (Docker BFF).
auth · session
POST/api/conversations
Create a conversation (Docker BFF).
auth · session
GET/api/conversations/{id}
Fetch one conversation (Docker BFF).
auth · session
DELETE/api/conversations/{id}
Delete a conversation (Docker BFF).
auth · session
GET/api/ecosystem/config
Ecosystem config for the chat shell.
auth · none / session
POST/api/v1/chat
OpenAI-compatible chat proxy through the BFF.
auth · session
Notes
Committed OpenAPI: docs/openapi/digichat.json (authored; path existence checked in tests/contracts).
Self-host: make up-ghcr-digichat pulls ghcr.io/digithings-ai/digichat (see infra/self-host/compose.ghcr.yml).
Stack
Next.jsReactVercel AI SDKAuthNextAuthPostgresDrizzle
Related
Links
digikey
Auth · RS256 JWTs · scoped API keys
support
Identity, JWTs, and scoped keys — one issuer for humans and machines.
Overview
RS256-signed JWTs with a published JWKS, organization and project membership, and row-level scopes baked into the token.
SQLAlchemy over Postgres stores keys, bcrypt hashes them, and an optional Redis blocklist handles revocation.
Authentication
digikey is the issuer. Admin routes require the `DIGIKEY_ADMIN_TOKEN` bearer; token exchange takes a raw API key or a BFF-session grant. JWKS and /healthz are public.
digigraph:workflow / :chat / :mcp
digigraph routes
digiquant:backtest / :optimize
digiquant routes
digisearch:query / :ingest
digisearch routes
*
Wildcard (all scopes) — dev_global keys only
Run locally
compose
docker compose up -d digikey
standalone
uvicorn digikey.server:app
Configuration
DIGIKEY_DATABASE_URL*
—
SQLite or Postgres URL for key storage.
DIGIKEY_PRIVATE_KEY_PEM
—
RSA 2048 PEM for RS256 signing (prod).
DIGIKEY_ADMIN_TOKEN*
—
Bearer for POST /v1/admin/keys.
DIGIKEY_BFF_TOKEN
—
Bearer for grant_type=bff_session (digichat).
DIGIKEY_JWT_TTL_SEC
900
Access-token lifetime.
DIGIKEY_BLOCKLIST_REDIS_URL
—
Redis for JWT revocation (prod).
Endpoints
Base URL $DIGIKEY_URL — the service URL from docker-compose.yml.
Correlation IDs across every hop — and prompts logged by length, never by text.
Overview
Structured logging, Prometheus metrics, and OpenTelemetry spans thread through every request so a multi-hop run is traceable end to end.
Audit events record a prompt's length and its IDs, never the prompt itself — tail events.jsonl and check. Optional LangSmith export runs a regex PII redactor on the way out.
Authentication
Status and metrics are public diagnostics. Tracing is a library wrapper, not an HTTP surface.
Run locally
compose
docker compose up -d digismith
standalone
uvicorn digismith.server:app
Configuration
LANGSMITH_API_KEY
—
Enable LangSmith trace export; absent = no-op.
LANGSMITH_ENDPOINT
https://api.smith.langchain.com
LangSmith API base (host shown in /v1/status).
OTEL_EXPORTER_OTLP_ENDPOINT
—
Enable OTel HTTP export when set.
Endpoints
Base URL $DIGISMITH_URL — the service URL from docker-compose.yml.
from digismith.trace import traceable@traceable("name") wraps a function with langsmith.traceable when LANGSMITH_API_KEY is set; otherwise a no-op. PII is redacted from span inputs/outputs.
from digismith.config import tracing_enabledReturns True when tracing is configured (key set + SDK importable).
Notes
Span attributes SHOULD include workflow_id, request_id, session_id, job_id.
Spans MUST NOT include raw prompts/completions, secrets, or full document bodies.
Stack
LSLangSmithOpenTelemetryPrometheusFastAPI
Related
Links
digiclaw
Always-on runtime · heartbeat · audit
support
The always-on agent runtime — heartbeats, scheduling, append-only audit.
Overview
A heartbeat service that keeps agents running: Atlas runner scheduling and drift detection, calling digigraph over HTTP on an interval.
Every action lands in an append-only audit log, and it runs no LLM of its own.
Authentication
CLI-only — no HTTP service / OpenAPI. Heartbeat runner pings service health and appends an immutable audit log. Container image: ghcr.io/digithings-ai/digiclaw (Compose profile heartbeat).
Run locally
cli
python -m digiclaw # one cycle
docker compose --profile heartbeat up -d heartbeat
# GHCR: docker compose -f docker-compose.yml -f infra/self-host/compose.ghcr.yml --profile heartbeat up -d
Configuration
DIGIGRAPH_URL
—
digigraph base URL for health checks.
DIGIQUANT_URL
—
digiquant base URL for health + drift checks.
DIGICLAW_DIGIKEY_API_KEY
—
Key (digiquant:backtest+optimize) for auth-gated drift checks.
AUDIT_LOG_PATH
digiquant/results/audit/events.jsonl
Append-only JSONL audit destination.
REOPTIMIZE_STRATEGY
mean_reversion_tech
Strategy id for the drift check.
Public interface
python -m digiclawRun one heartbeat cycle: health-check services, run an auth-gated drift check, and (on drift) trigger re-optimization.
audit_log(event_type, agent_id, payload)Append one redacted JSON line to the audit log.
Keys matching password / api_key / token / secret are redacted before write.
Stack
hxHTTPxDBdigibase
Related
Links
digibase
Shared HTTP + audit library
support
The shared Python library every service builds on — and nothing more.
Overview
Not a service but a deliberately minimal library: request-ID middleware and logging, CORS and error handlers, an audit redaction helper, and a Prometheus metrics endpoint.
Imported by every other module so they all behave consistently, with optional OpenTelemetry setup. Auth middleware is digikey's job, not digibase's.
Authentication
Shared Python library imported by every service — not a network surface.
Run locally
cli
# installed as a dependency of each service; no standalone run
Configuration
DIGI_ENV
dev
Environment label for metrics.
DIGI_CORS_ORIGINS
—
Global CORS allowlist (comma-separated).
DIGI_PII_PATTERNS
—
Extra regex patterns for PII redaction.
Public interface
from digibase.errors import register_fastapi_error_handlersStandard error envelope: {error:{code,message,request_id,service}}.
from digibase.http import outbound_service_headersBuilds X-Request-ID + Authorization headers for service-to-service calls.
from digibase.http import install_request_id_middlewareReads/generates X-Request-ID, stores on request.state, echoes on the response.
from digibase.audit import redact_mappingRedacts password/api_key/token/secret keys from a payload before logging.
from digibase.metrics import install_metricsMounts Prometheus /metrics with http_requests_total / _duration / _in_flight.
from digibase.otel import setup_otel_fastapiOptional OTel wiring; no-op unless OTEL_EXPORTER_OTLP_ENDPOINT is set.
Stack
PydanticFastAPIPrometheusOpenTelemetry
Related
Links
digivault
Markdown vault · wikilinks · backlinks
support
A folder of markdown notes, served over HTTP — frontmatter, wikilinks and backlinks.
Overview
An Obsidian-style vault service: it manages a folder of markdown notes with YAML frontmatter, wikilinks, tags and a folder taxonomy, and answers over HTTP rather than asking callers to walk the filesystem.
Routes cover listing, reading and creating notes, renaming with backlink repair, backlink and tag lookups, and a lint report. Two more — orchestrator_tools and orchestrator_invoke — expose the vault to digigraph as callable tools. Runs behind the `digivault` compose profile, so it is opt-in rather than up by default.
Authentication
`DigiAuthMiddleware` with a per-path scope map: digivault:read for reads and for both orchestrator routes, digivault:write for mutations. /v1/orchestrator_invoke is gated at read because most of its tools are reads — the one mutating tool re-checks digivault:write in the handler, so a read-only caller cannot reach it through the shared endpoint.
Run locally
cli
docker compose --profile digivault up -d digivault # opt-in profile, not up by default
digivault lint --root ./docs/vision
Configuration
DIGIVAULT_ROOT
/data/vault
Vault directory. Unset, the routes that read the filesystem answer 503 rather than guessing a path; /v1/orchestrator_tools still returns its static manifest.
DIGIKEY_JWKS_URL
http://digikey:8005/.well-known/jwks.json
Where the middleware fetches the public half to verify tokens.
DIGIKEY_ISSUER
http://digikey:8005
Expected token issuer.
DIGIKEY_AUDIENCE
digi-ecosystem
Expected token audience.
Public interface
GET /v1/notesList notes in the vault.
GET /v1/notes/{name}Read one note — body plus parsed YAML frontmatter.
POST /v1/notesCreate a note. Requires digivault:write.
PATCH /v1/notes/{name}/frontmatterUpdate frontmatter in place.
POST /v1/notes/{name}/renameRename a note and repair the wikilinks pointing at it.
GET /v1/notes/{name}/backlinksEvery note linking to this one.
GET /v1/tags/{tag}Notes carrying a tag.
GET /v1/lintVault health: broken wikilinks, missing frontmatter, taxonomy drift.
POST /v1/orchestrator_toolsTool manifest, so digigraph can discover what the vault offers.
POST /v1/orchestrator_invokeInvoke one of those tools by name.
Notes
The vault is a folder of markdown files — YAML frontmatter, wikilinks, tags, folder taxonomy. There is no database; the filesystem is the store.
Its first consumer is this repository's own docs/vision/, which scripts/gen-api-vault.ts generates from the same module registry this page is built from.
Stack
FastAPIPydanticYMPyYAML
Related
Links
digistore
Storage abstraction · roadmap
roadmap
One storage API over S3, MinIO, Postgres, or SQLite.
Overview
Roadmap: a storage abstraction so business code never binds to a backend, today a session-scoped dataset manager living inside digigraph.
Run SQLite on a laptop, then swap to S3 and Postgres in production without rewriting.
Authentication
Roadmap. Today a session-scoped dataset manager lives inside digigraph; the standalone storage service is planned.
Notes
Planned: one storage API over S3, MinIO, Postgres, or SQLite so business code never binds to a backend.
Planned surface: digistore.configure(backend=…) + get/put/list over a backend-neutral interface.
Stack
PostgresSQLiteS3S3MiMinIO
Related
Links
digilink
MCP protocol bridge · roadmap
roadmap
A protocol bridge so non-native transports speak MCP.
Overview
Roadmap: a translation layer registering adapters that turn REST, gRPC, or bespoke transports into MCP tools.
Today MCP is built into individual modules; this keeps the stack open instead of locked to one protocol.
Authentication
Roadmap. Today MCP is built into individual modules (e.g. digisearch-mcp).
Notes
Planned: a protocol bridge registering adapters that turn REST, gRPC, or bespoke transports into MCP tools.
Planned surface: digilink.register_adapter("rest", …) to expose a non-native transport as MCP.