01 - Local Setup
Start the QTG server locally and confirm the health check.
QTG local setup in the CLI.
Prerequisites: a container engine
qtg init brings up PostgreSQL via Docker Compose, so you need a running
container engine first. Install one of:
- Docker Desktop (macOS / Windows / Linux), or
- OrbStack (macOS — lighter, faster Docker engine).
qtg init:
docker is missing or docker info fails, install/launch the engine above;
qtg init will still write your .env but will skip bring-up.
Quick path (recommended)
qtg init is the single front door. It interactively writes a signing-capable
dev .env and optionally brings up PostgreSQL + runs migrations:
external so a stray docker compose down -v
cannot delete it — which also means Compose will not create it for you. Create it once
on a first install. If Compose reports it missing on a machine that has run QTG before,
do not create it: the database volume is gone, and recovering it comes first.
qtg init prompts for:
- Network mode (
mainnet/testnet) — and overlays the matching Circle Gateway / CCTP Iris endpoints automatically. - Signer private-key storage — 1Password (recommended) is the default.
Select an existing secret, store an operator-generated development key in a new
1Password item, or enter an
op://reference. QTG never generates the key; it validates the resolved signer against the confirmed public EVM address and stores only the reference and non-secretOP_ACCOUNTaccount pin in.env. Plaintext .env (development only) remains an explicit, warned alternative for a low-value key; it writes that key unencrypted to.env. - Exchange API keys — a multi-select for the Free venues (Upbit / Binance / OKX / Bybit / Coinbase); skip any you don’t need yet.
op mode removes the EVM signer private key from the .env; it does not move
callback, exchange, database, RPC, or other application secrets. That broader
configuration/secret boundary is out of scope here.
Useful flags: --network mainnet|testnet, --no-bringup (write .env only),
--force (overwrite an existing .env, backed up first), --yes (non-interactive,
requires --network + a plaintext key when the signer source is omitted),
--repo-root <path>. Non-interactive 1Password setup is local-reference-only: it
does not create, edit, or delete an item. Supply all of its public inputs:
--op-account may instead be supplied by ambient OP_ACCOUNT when it agrees with
an explicit value. The expected address is required so QTG can fail closed if the
reference resolves to another signer. In --yes mode, omitting --signer-source
preserves the compatible plaintext flow.
For plaintextThen start the dev server. For the recommended 1Password source, the local 1Password app/session and configured--yesmode, prefer supplying the key via theQTG_DEV_SIGNER_KEYenvironment variable rather than--signer-key— a CLI argument lands in shell history and process listings (ps). The interactive path always uses a hidden prompt and never touches argv.
op executable must remain available at
bootstrap and whenever QTG signs. Use the source-aware command; it clears ambient
account and unsupported unattended selectors so the OP_ACCOUNT pin in .env is
authoritative:
--env-file command instead:
Treat an edit to the selected 1Password item as signer rotation, not a transparent configuration change: verify the signer address before use. Ifdocker compose up <app>is not the dev signing path — the containerized app services intentionally blank the signer config. Use the matching localuvicorncommand above for a signing-capable dev server; this onboarding does not configure Compose signing or unattended 1Password access.
qtg init --force
replaces an existing .env, its mode-0600 .env.bak.* backup can still contain a
plaintext key or other sensitive configuration and is not deleted automatically.
Check the CLI surface
The current QTG control plane has three entry points:
After you seed an operator or agent HMAC key, point the CLI at the local API:
qtg-agent and qtg-mcp are read + propose surfaces. They can inspect
balances, movements, timelines, authority state, and template proposals, but
they do not run an approved movement by themselves../scripts/quickstart.sh --down
Troubleshooting bring-up
qtg init writes your .env first, then attempts bring-up — so a bring-up
failure never loses your config. If it prints Bring-up skipped (…), your
.env is already in place; fix the engine and run the migrations manually
(below). Common causes:
Re-run migrations manually after fixing the engine (global bucket + your
network only — see Step 4):
Manual path
If you prefer to configure each step yourself:Step 1: Clone and install
Step 2: Configure environment
.env and set at least these three values:
MG_NETWORK_MODE has no default — the server refuses to boot if it is
unset. Set it to mainnet or testnet. The shipped .env.example uses
mainnet.
Key Environment Variables Summary
RPC endpoints — pre-populated
QTG ships a curated PublicNode-based default RPC table covering ~24 EVM chains. You do not need to setMG_EVM_RPC_ENDPOINTS_JSON for the quickstart
to talk to lanes like Base Sepolia, Arbitrum One, Ethereum mainnet, etc.
When you go to production, override per-chain with a paid provider — see
04-going-live.md and
rpc-defaults.md.
For the full environment variable list, see the Bootstrap reference.
Binance Master / Sub Logical Venue Alias Example
To use a Binance main account and an experimental sub-account at the same time, set.env like this.
The sub binding must use a credential-less shape, and balance reads use the master key to call
/sapi/v3/sub-account/assets. Because of that, the master API key needs the
Enable Sub-Account Management permission.
Binance sub-account asset/transfer APIs take the sub-account email in the
email / fromEmail parameter, not a numeric subUserId. Because of that,
the current sub_account_uid field name stays the same, but the value must be an email.
source_exchange: "binance_lab" directly in template/runtime bindings.
By contrast, the external-withdrawal proving adapter cannot be created directly from a sub binding and must use the master binding or the capital transfer subsystem.
Step 3: Start PostgreSQL
The manual path does not runqtg init, so nothing has started a database yet.
Bring up the same Compose service the quick path uses — no external PostgreSQL is
required, and the credentials match the MG_DATABASE_URL default above:
MG_DATABASE_URL
to it instead and skip this step; the migrations below then apply to that database.
Step 4: Start the Server
Database schema is managed by Alembic migrations. RunIf youruv run qtg init(which runs migrations automatically) or apply manually. Migrate the global bucket plus the one network bucket matchingMG_NETWORK_MODE— a single database holds exactly one network bucket (the schema guard rejects the second):
.env uses the recommended 1Password signer source, use the source-aware
command from the quick path so the file’s OP_ACCOUNT pin is not overridden. If you
explicitly configured a local plaintext development signer, pass --env-file .env
so the non-MG_-prefixed key variable lands in the process env:
Step 5: Health Check
Understand the Run Modes
QTG runs in two modes:
The quickstart starts in API-only mode. Real exchange/chain integrations are covered in 04-going-live.md.
Dashboard (Optional)
http://localhost:5173 (dev) or http://localhost:3000 (Docker).
See operator-network-access.md for production exposure topology.
Verification Commands
Next: 02-first-movement.md - register your first template and create a movement