Skip to content
contents

// docs

digithings docs.

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.

OpenAPI explorer

Getting started

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.

Prerequisites

  • Docker (with Compose)
  • Python ≥ 3.12 (for running services outside Docker)
  • Node.js LTS (for the frontends)

Run the whole stack

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.

Quick start (once GHCR stack images exist)

cp .env.example .env
# Edit .env: provider keys, DIGIKEY_*, optional AUTH_* for digichat

docker compose \
  -f docker-compose.yml \
  -f infra/self-host/compose.ghcr.yml \
  pull
docker compose \
  -f docker-compose.yml \
  -f infra/self-host/compose.ghcr.yml \
  up -d

Or: make up-ghcr / make up-ghcr-digichat. digichat itself is already on GHCR (ghcr.io/digithings-ai/digichat).

Profiles

  • digichat — digichat + Postgres
  • digivault — digivault
  • heartbeat — digiclaw loop
  • litellm-cache — Redis for LiteLLM
  • observability — Prometheus + Grafana

Image tags

  • DIGI_IMAGE_TAG — digikey, digigraph, digiquant, digisearch, digismith, digivault, digiclaw (pin sha-<12> in production).
  • 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.

Profiles

  • **A — digigraph stack** — digichat + db + digikey + digigraph + LiteLLM + digivault. Adapters: digigraph owns digillm→LiteLLM and digivault.
  • **B — Azure AI Foundry** — digichat + db only (DefaultAzureCredential). For client Azure environments; digithings has no Azure.

Profile A (digigraph)

cp infra/digichat-release/.env.profile-a.example \
   infra/digichat-release/.env.profile-a
# edit AUTH_SECRET, DIGIKEY_BFF_TOKEN, DIGICHAT_EMBED_TENANTS, DIGI_IMAGE_TAG, provider keys

make digichat-profile-a-up

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.

Service map

  • digigraph :8000 — workflows, OpenAI-compatible chat, federated tools
  • digiquant :8001 — NautilusTrader backtest / optimize
  • digisearch :8002 — RAG ingest + query
  • digismith :8003 — observability helpers + status
  • digivault :8004 — vault (opt-in compose profile)
  • digikey :8005 — API keys + JWT exchange + JWKS
  • digichat :3005 — Next.js BFF + chat UI (profile digichat)
  • 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>.

1 · Mint an API key (admin)

curl -X POST $DIGIKEY_URL/v1/admin/keys \
  -H "Authorization: Bearer $DIGIKEY_ADMIN_TOKEN" \
  -H "content-type: application/json" \
  -d '{"tenant_slug":"acme","scopes":["digiquant:backtest","digigraph:workflow"]}'
# → { "api_key": "dgk_live_… (shown once)", "key_prefix": "dgk_live_…", "id": "<uuid>" }

2 · Exchange for a JWT

curl -X POST $DIGIKEY_URL/v1/oauth/token \
  -H "content-type: application/json" \
  -d '{"grant_type":"api_key","api_key":"'"$DIGI_API_KEY"'"}'
# → { "access_token": "<JWT>", "token_type": "Bearer", "expires_in": 900 }
import os, httpx

tok = httpx.post(
    f"{os.environ['DIGIKEY_URL']}/v1/oauth/token",
    json={"grant_type": "api_key", "api_key": os.environ["DIGI_API_KEY"]},
).json()["access_token"]
const r = await fetch(`${process.env.DIGIKEY_URL}/v1/oauth/token`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ grant_type: "api_key", api_key: process.env.DIGI_API_KEY }),
});
const { access_token } = await r.json();

3 · Call a service

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.

Error envelope

Every service returns the same error shape:

{
  "error": {
    "code": "http_401",
    "message": "Bearer token required",
    "request_id": "req-…",
    "service": "digigraph"
  }
}
  • http_401 — missing/invalid token · http_403 / insufficient_scope — scope denied.
  • 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.

digigraph:workflowPOST /workflow + debug routes (default fallback)
digigraph:chat/v1/chat/completions, /v1/models, /v1/model-info
digigraph:mcp/threads/*, /files/* (when enabled)

Run locally

compose
docker compose up -d digigraph
standalone
uvicorn digigraph.server:app
mcp
FastMCP streamable-http (workflow, chat, thread_state, list_orchestrator_tools)

Configuration

DIGIQUANT_URLdigiquant base URL (defaults to the compose service URL).
DIGISEARCH_URLdigisearch base URL; empty disables retrieval.
DIGIKEY_JWKS_URLJWT public-key (JWKS) endpoint.
OPENAI_API_BASELiteLLM proxy base URL.
DIGI_LLM_MODEtestModel tier: test / medium / best.
DIGI_CHECKPOINTERmemoryLangGraph state backend: memory / sqlite / postgres / none.
DIGI_ENABLE_THREAD_API0Gate /threads/* and /files/*.
DIGI_ENABLE_DEBUG_ENDPOINTS0Gate /test_llm and /v1/debug/*.

Endpoints

Base URL $DIGIGRAPH_URL — the service URL from docker-compose.yml.

GET/healthz

Liveness probe. Auth-exempt; always 200.

auth · none
Response
{ "ok": true }
curl $DIGIGRAPH_URL/healthz
GET/v1/status

Public, secret-free project status.

auth · none30/min/IP
Response
{
  "service": "digigraph",
  "project_name": "demo",
  "agents_enabled": true,
  "llm_mode": "test",
  "mcp_enabled": true,
  "workflow_profile": "default"
}
curl $DIGIGRAPH_URL/v1/status
POST/workflow

Run the full research + backtest graph (digiclaw custom skill).

auth · digigraph:workflow (optional)10/min/IP
Request
prompt*stringThe user request to route through the supervisor.
session_idstringConversation/session correlation id.
allowed_toolsstring[]Tool allowlist override for this run.
digi_bearerstringJWT forwarded downstream to digisearch/digiquant.
Response
successbooleanWhether the workflow completed.
messagestringHuman-readable summary or full RAG answer.
backtest_resultobject | nulldigiquant BacktestResult, if a backtest ran.
rag_sourcesobject[] | nullAggregated digisearch citations.
curl -X POST $DIGIGRAPH_URL/workflow \
  -H "Authorization: Bearer $JWT" -H "content-type: application/json" \
  -d '{"prompt": "Backtest a momentum strategy on AAPL"}'
POST/v1/chat/completions

OpenAI-compatible chat. Set stream:true for SSE (events: tool_call, content, done).

auth · digigraph:chat (optional)10/min/IP
Request
modelstringModel id; default "digigraph-rag".
messages*{role,content}[]Chat messages.
streambooleanStream tokens as SSE.
curl -X POST $DIGIGRAPH_URL/v1/chat/completions \
  -H "Authorization: Bearer $JWT" -H "content-type: application/json" \
  -d '{"model":"digigraph-rag","messages":[{"role":"user","content":"hi"}]}'
GET/v1/models

OpenAI-style model list.

auth · digigraph:chat (optional)30/min/IP
curl $DIGIGRAPH_URL/v1/models -H "Authorization: Bearer $JWT"

MCP tools

  • workflow(prompt, thread_id?)Run the full research + backtest graph; returns a JSON WorkflowResult.
  • chat(message, thread_id?, model?)Single-turn chat via /v1/chat/completions.
  • thread_state(thread_id)Return the LangGraph checkpoint state for a thread.
  • list_orchestrator_tools()List registered orchestrator tool names.
  • list_orchestrator_tools_detailed()Tool manifest: name, tags, dynamic_schema flag.

Stack

LangGraphFastAPILiteLLMPydanticPolarsOpenAI SDK

Related

Links

digiquant

Quant engine · NautilusTrader
core

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.

digiquant:backtest/run_backtest, /backtest/*, /v1/jobs/*, /v1/orchestrator_tools
digiquant:optimize/run_optimize, /run_pipeline, /v1/workflow

Run locally

compose
docker compose up -d digiquant
standalone
uvicorn digiquant.server:app

Configuration

DIGIQUANT_DATA_DIR/app/dataDirectory of OHLCV CSVs for backtests.
DIGIKEY_JWKS_URLJWT public-key (JWKS) endpoint.
DIGIQUANT_ALLOW_EXPORT1Enable export of strategy configs.

Endpoints

Base URL $DIGIQUANT_URL — the service URL from docker-compose.yml.

GET/strategies

List registered NautilusTrader strategies.

auth · none30/min/IP
Response
[{ "name": "mean_reversion_tech", "aliases": [], "description": "...", "default_params": {} }]
curl $DIGIQUANT_URL/strategies
POST/run_backtest

Synchronous backtest. Returns a BacktestResult.

auth · digiquant:backtest (optional)10/min/IP
Request
strategy_name*stringRegistered strategy id.
symbols*string[]Instruments to test.
data_dirstringDirectory of {symbol}.csv OHLCV files.
strategy_paramsobjectStrategy parameter overrides.
full_tearsheetbooleanInclude extended charts (default true).
Response
run_idstringUnique run identifier.
total_pnlnumberTotal P&L.
sharpe_rationumber | nullSharpe ratio.
num_tradesintegerNumber of trades executed.
statusstring"completed" | "failed".
curl -X POST $DIGIQUANT_URL/run_backtest \
  -H "Authorization: Bearer $JWT" -H "content-type: application/json" \
  -d '{"strategy_name":"mean_reversion_tech","symbols":["AAPL"]}'
POST/backtest/start

Submit an async backtest job; returns {job_id}. Poll progress over SSE.

auth · none10/min/IP
Response
{ "job_id": "..." }
GET/backtest/{job_id}/progress

SSE stream of backtest progress events (JSON frames).

auth · none
curl -N $DIGIQUANT_URL/backtest/$JOB_ID/progress
POST/run_optimize

Parameter optimization (grid / bayesian / random). Returns best params.

auth · digiquant:optimize (optional)10/min/IP
Request
strategy_name*stringRegistered strategy id.
symbols*string[]Instruments.
methodstring"grid" | "bayesian" | "random" (default grid).
n_trialsintegerTrial budget (default 50).
objectivestring"sharpe" | "return" | "pnl".
Response
best_paramsobjectBest parameter set found.
best_sharpenumber | nullObjective value at best params.
num_evaluationsintegerTrials evaluated.
POST/run_pipeline

Full pipeline: backtest → optimize → export.

auth · digiquant:optimize (optional)10/min/IP

Stack

NautilusTraderOptunaLangGraphPolarsyfinanceSupabase

Related

Links

digisearch

Vector retrieval · multi-backend
core

Production RAG without a stack rewrite when you switch vector DB.

Overview

One client over Chroma or Azure AI Search, with backend-neutral entities so you swap engines without touching business code.

Dense, sparse, and hybrid retrieval are first-class; BeautifulSoup and pdfplumber handle ingest, Polars throughout.

Authentication

All query/ingest routes require a digikey JWT carrying the matching scope.

digisearch:query/query, /v1/research_turn, orchestrator routes, /indexes/*
digisearch:ingest/ingest

Run locally

compose
docker compose up -d digisearch
standalone
uvicorn digisearch.server:app
mcp
digisearch mcp   (FastMCP streamable-http: digisearch_query, digisearch_research_turn)

Configuration

CHROMA_PATHPersistent Chroma directory (activates the Chroma backend).
AZURE_SEARCH_ENDPOINTAzure AI Search endpoint (alternative backend).
AZURE_SEARCH_API_KEYAzure AI Search key.
OPENAI_API_KEYEmbeddings provider key.
DIGIKEY_JWKS_URL*JWT public-key endpoint.

Endpoints

Base URL $DIGISEARCH_URL — the service URL from docker-compose.yml.

POST/query

Hybrid / keyword / vector search over an index.

auth · digisearch:query10/min/IP
Request
text*stringQuery text.
index_namestringTarget index (default "default").
top_kintegerResults to return, 1–100 (default 10).
modestring"keyword" | "vector" | "hybrid" (default hybrid).
filters{field,op,value}[]Structured metadata filters.
Response
resultsobject[]Normalized hits (chunk_id, doc_id, score, content, metadata).
totalintegerTotal matches.
backendstring"chroma" | "azure_ai_search" | "stub".
curl -X POST $DIGISEARCH_URL/query \
  -H "Authorization: Bearer $JWT" -H "content-type: application/json" \
  -d '{"text":"momentum factor","index_name":"default","top_k":5}'
POST/ingest

Ingest a document (parse → chunk → embed → index).

auth · digisearch:ingest30/min/IP
Request
source*stringServer-side path to the document.
index_namestringTarget index.
doc_typestringpdf | html | docx | markdown | csv | plaintext.
metadataobjectEvidence metadata (tier, venue, tags, …).
Response
{ "doc_id": "...", "chunks_created": 12, "index_name": "default", "status": "ok" }
POST/v1/research_turn

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

ChromaAzure AI SearchOpenAIBeautifulSouppdfplumberLangGraphFastAPI

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

Configuration

OPENROUTER_API_KEY*LLM calls via OpenRouter free models.
CORE_SUPABASE_URL*Vault Supabase project URL (RLS read).
CORE_SUPABASE_ANON_KEY*Anon key for RLS-gated vault reads.
AUTH_SECRETNextAuth secret (Docker BFF): openssl rand -base64 32.
DIGIKEY_BFF_TOKENBearer for grant_type=bff_session (Docker BFF).

Endpoints

Base URL $DIGICHAT_URL — the service URL from docker-compose.yml.

GET/api/health

Liveness probe.

auth · none
Response
{ "ok": true }
POST/api/chat

Agentic chat grounded in digivault (single tool: search_digivault).

auth · none (public, rate-limited)
Request
messages*{role,content}[]Conversation so far.
modelstringOpenRouter free model id.
Response
{ "content": "…grounded answer…", "tool_calls": [] }
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 SDKNextAuthPostgresDrizzle

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 / :mcpdigigraph routes
digiquant:backtest / :optimizedigiquant routes
digisearch:query / :ingestdigisearch 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_PEMRSA 2048 PEM for RS256 signing (prod).
DIGIKEY_ADMIN_TOKEN*Bearer for POST /v1/admin/keys.
DIGIKEY_BFF_TOKENBearer for grant_type=bff_session (digichat).
DIGIKEY_JWT_TTL_SEC900Access-token lifetime.
DIGIKEY_BLOCKLIST_REDIS_URLRedis for JWT revocation (prod).

Endpoints

Base URL $DIGIKEY_URL — the service URL from docker-compose.yml.

GET/.well-known/jwks.json

RSA public key set for verifying issued JWTs.

auth · none
curl $DIGIKEY_URL/.well-known/jwks.json
POST/v1/admin/keys

Create an API key. The raw key is returned ONCE.

auth · admin token10/min/IP
Request
tenant_slug*stringTenant identifier.
labelstringHuman-readable key name.
scopesstring[]Granted scopes.
Response
{ "key_prefix": "dgk_live_…", "api_key": "dgk_live_…(once)", "id": "<uuid>" }
curl -X POST $DIGIKEY_URL/v1/admin/keys \
  -H "Authorization: Bearer $DIGIKEY_ADMIN_TOKEN" -H "content-type: application/json" \
  -d '{"tenant_slug":"acme","scopes":["digiquant:backtest"]}'
POST/v1/oauth/token

Exchange an API key (or BFF session) for a short-lived RS256 JWT.

auth · none (key in body)10/min/IP
Request
grant_type*string"api_key" | "bff_session".
api_keystringRaw dgk_live_ key (api_key grant).
requested_scopesstring[]Downscope to a subset of granted scopes.
Response
{ "access_token": "<JWT>", "token_type": "Bearer", "expires_in": 900 }
curl -X POST $DIGIKEY_URL/v1/oauth/token \
  -H "content-type: application/json" \
  -d '{"grant_type":"api_key","api_key":"'"$DIGI_API_KEY"'"}'
POST/v1/admin/keys/{key_id}/revoke

Revoke a key and blocklist its live JWTs (when Redis is configured).

auth · admin token10/min/IP
Response
{ "revoked": true, "jtis_invalidated": 3 }

Stack

PyJWTcryptographybcryptSQLAlchemyPostgresRedis

Related

Links

digismith

Observability · spans · correlation IDs
support

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_KEYEnable LangSmith trace export; absent = no-op.
LANGSMITH_ENDPOINThttps://api.smith.langchain.comLangSmith API base (host shown in /v1/status).
OTEL_EXPORTER_OTLP_ENDPOINTEnable OTel HTTP export when set.

Endpoints

Base URL $DIGISMITH_URL — the service URL from docker-compose.yml.

GET/v1/status

Tracing configuration diagnostic (operator-facing; secret-free).

auth · none
Response
{
  "version": "0.1.0",
  "tracing_configured": true,
  "langsmith_sdk_installed": true,
  "langsmith_host": "api.smith.langchain.com",
  "request_id": "..."
}
curl $DIGISMITH_URL/v1/status
GET/metrics

Prometheus metrics (text/plain 0.0.4).

auth · none

Public interface

  • 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

LangSmithOpenTelemetryPrometheusFastAPI

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_URLdigigraph base URL for health checks.
DIGIQUANT_URLdigiquant base URL for health + drift checks.
DIGICLAW_DIGIKEY_API_KEYKey (digiquant:backtest+optimize) for auth-gated drift checks.
AUDIT_LOG_PATHdigiquant/results/audit/events.jsonlAppend-only JSONL audit destination.
REOPTIMIZE_STRATEGYmean_reversion_techStrategy 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.

Notes

  • Audit event types: heartbeat, reoptimize_triggered, reoptimize_completed, reoptimize_failed, drift_check_skipped.
  • Keys matching password / api_key / token / secret are redacted before write.

Stack

HTTPxdigibase

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_ENVdevEnvironment label for metrics.
DIGI_CORS_ORIGINSGlobal CORS allowlist (comma-separated).
DIGI_PII_PATTERNSExtra 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/vaultVault 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_URLhttp://digikey:8005/.well-known/jwks.jsonWhere the middleware fetches the public half to verify tokens.
DIGIKEY_ISSUERhttp://digikey:8005Expected token issuer.
DIGIKEY_AUDIENCEdigi-ecosystemExpected 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

FastAPIPydanticPyYAML

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

PostgresSQLiteS3MinIO

Related

Links