Getting Started
A single-page consolidated reference for getting QTG running, authenticated, and verified. If you want a guided multi-step walkthrough instead, usedocs/quickstart/ (4 documents, ~30 minutes end-to-end).
Supported platforms
Toolchain:
- Python 3.14+
- uv package manager
- PostgreSQL (Docker Compose provided)
- Exchange API keys (live mode only)
- AWS KMS key (EVM proving lanes) or 1Password CLI (dev quickstart)
Quickstart
MG_DATABASE_URLMG_CALLBACK_HMAC_SECRETMG_CALLBACK_ALLOWED_HOSTS_CSV
Docker
qtg-testnet against the
same database, and whichever network bucket was not migrated fails its boot check.
The Postgres data volume is external so that docker compose down -v cannot delete
it. Compose therefore refuses to start when it is absent, which is the intended signal
— see docs/quickstart/01-local-setup.md.
Dashboard
Execution modes
Signer backends
The default proving-lane signer is AWS KMS. For dev or for evaluating QTG without AWS, a local private-key signer provides two key sources:- 1Password CLI (recommended for local) — keys fetched on demand from your vault.
- Plain env var (
plain) — development only; plaintext key held in process memory. Do not use for fund movement volume. No sign-without-expose guarantee.
docs/reference/signers/local-private-key-signer.md and docs/reference/signers/signer-protocol.md.
Multi-signer bootstrap
For redundancy or rotation overlap, configure additional signers viaMG_EXTRA_SIGNERS_JSON. Signer health checks run at bootstrap.
CCTP local signer readiness
.env (copied from .env.example).
The retained one-shot command is TESTNET-only and can sign and broadcast through
AWS KMS. Its presence is not live approval: use it only with a fresh reviewed
operator approval for the exact run. Pytest has no CCTP broadcast authority.
Binance master / sub-account model
Binance sub-account bindings are signed through the master credentials — QTG never holds sub-account trading keys. Declare sub bindings withaccount_role: "sub" and sub_account_uid, omitting access_key and secret_key.
For Binance, sub_account_uid is intentionally the sub-account email (Binance sub-account asset and transfer APIs use email / fromEmail); do not put the numeric subUserId / UID there.
Master bindings use account_role: "master" and carry credentials. The Binance master API key must have Enable Sub-Account Management so QTG can read sub balances through /sapi/v3/sub-account/assets. See .env.example for the full binding JSON shape.
CEX logical venue alias
MG_CEX_BINDINGS_JSON maps an alias such as binance_lab to the existing Binance provider. If an alias exists, runtime proving and balance both resolve binding-first. Legacy MG_BINANCE_* settings remain as fallback.
Auth model
Inbound request HMAC
Required headers:X-QTG-Key-IdX-QTG-TimestampX-QTG-NonceX-QTG-Signature
PATHis the routed, percent-decoded path the server dispatches on — no origin, no query string.QUERYis the query exactly as sent: no leading?, no sorting, empty string if absent. Sorting before signing transmits bytes you did not sign, and every such request 401s.
examples/ directory.
RBAC — 3 roles
Each API key is bound to exactly one role, enforced per route by the HMAC auth middleware:
All mutating routes are mirrored into an append-only
audit_events table. Query via GET /v3/audit/events (canonical, admin + operator) or the legacy GET /v3/registry/audit. For agent-namespace tenant isolation, see docs/reference/api/v3-endpoints.md.
Outbound callback HMAC (v3)
Headers:X-QTG-Callback-TimestampX-QTG-Callback-NonceX-QTG-Callback-Signature-Version: v3X-QTG-Callback-Signature
docs/callback-verification-contract.md. A working receiver example is provided in the repository’s examples/ directory.
Schema bootstrap
PostgreSQL only since v0.1.0. Auto-creating tables at startup is no longer supported — a fresh DB is built from the 3-bucket alembic chain (global / mainnet / testnet):scripts/quickstart.sh runs these for you. Schema changes ship as new migrations in the same chain.
- Heads are per-bucket — there is no single global “head” revision; upgrade each bucket to its own
@head. - Startup validation: on boot the server checks that the schema exists and the alembic head matches before accepting traffic — a drifted or unmigrated DB refuses to boot.
- Existing databases (schema drift, live deployment): managed by the same
alembic_v3/migration chain. - One-off data backfills:
scripts/or explicit operational runbooks. - Local and container dependency installation: all aligned on
uv. - Minimum Python:
3.14(repo-local default + Docker baseline both aligned).
MG_NETWORK_MODE is required and has no default (mainnet | testnet). The server refuses to boot if it is unset; .env.example ships MG_NETWORK_MODE=mainnet.
Runtime surfaces
QTG runs as a single FastAPI service with a few operator-facing surfaces:- REST API — the
/v3/*movement, template, registry, and signer endpoints, plus/healthz. - Dashboard — a React SPA served against the
/dashboard/*endpoints (Gateway balances, CCTP transfer tracking, movement management, route lookup). - Runtime workers — when
MG_WORKERS_ENABLED=true, 8 always-on workers (dispatcher, observer, recovery, callbacks, expiration, proposal expiry, executor health, audit promotion) run and execute real integrations, plus conditional sidecars behind their own flags. - CLI tools — preflight, seed, and import utilities for setup and operations.
examples/ (a callback receiver and a signed sender) and docs/ (design, reference, and operational docs).
Verification commands
GET /healthz returns:
Important runtime nuances
- Auto-approve. When
MG_AUTO_APPROVE_ENABLED=trueandstrategy_idis provided, policy-matched requests becomeAPPROVEDimmediately and manual approval is skipped. - Address allowlist. On-chain executors apply the DB-level address guard at dispatch time, not at template registration.
- Callback v3. Nonce-based replay protection is implemented; receivers must store and reject seen nonces.
- Signer health. Bootstrap runs a health check on every configured signer.
- EVM proving signer. Defaults to the local AWS KMS signer bootstrapped via
MG_LOCAL_SIGNER_*. - EVM RPC endpoints. Default to PublicNode URLs for ~24 mainnet + testnet chains so the dev quickstart works out of the box. Per-chain overrides in
MG_EVM_RPC_ENDPOINTS_JSONalways win; setMG_EVM_RPC_USE_DEFAULTS=falseto disable the table entirely. Live broadcast tools (*_live_preflight, Stage 3 harness) ignore defaults regardless — seereference/rpc-defaults.md.
Where to go next
- First movement, dry-run:
docs/quickstart/02-first-movement.md - Template patterns by lane:
docs/quickstart/03-template-cookbook.md - Going live (auth, callbacks, workers, Docker, allowlist):
docs/quickstart/04-going-live.md - API reference:
docs/reference/api/v3-endpoints.md - Runbooks:
docs/runbooks/