Skip to main content

01 - Local Setup

Start the QTG server locally and confirm the health check.
QTG CLI and MCP quickstart

QTG local setup in the CLI.


Prerequisites: a container engine

The API-only quick path starts PostgreSQL through Docker Compose, so you need a running container engine first. Install one of: Confirm it works before starting the local PostgreSQL service:
If docker is missing or docker info fails, install or launch the engine above before continuing. Start Core locally in API-only mode first. qtg.main accepts a configured RemoteSignerProxy for EVM movement lanes; it rejects in-process local signer and extra-signer settings. A signer is therefore not required for this API-only walkthrough, but on-chain operation needs the private signer-service setup described in Signer Protocol.
Before starting anything, edit .env to replace its template values:
  • Set MG_DATABASE_URL to the host connection URL whose password matches Compose. The Compose service uses qtg when QTG_DB_PASSWORD is unset; if you choose another password, provide it as QTG_DB_PASSWORD when starting Compose and use the same password in MG_DATABASE_URL.
  • Replace MG_CALLBACK_HMAC_SECRET=CHANGE_ME with a local secret and keep MG_CALLBACK_ALLOWED_HOSTS_CSV limited to the local callback hosts you will use.
  • Set MG_NETWORK_MODE to mainnet or testnet. The shipped template selects mainnet; that selector determines the one network migration bucket to apply.
The template’s MG_AUTH_ENABLED=false and MG_WORKERS_ENABLED=false values are intentional for this local API-only walkthrough. They are template values, not the Settings auth default or an operational deployment recommendation. Create the external data volume only on a genuinely first-time local install, then start PostgreSQL and wait for its health check:
The Postgres data volume is declared external so a stray docker compose down -v cannot delete it — which also means Compose will not create it for you. 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. Apply the global schema and exactly one network bucket matching MG_NETWORK_MODE:
Leave MG_LOCAL_SIGNER_*, MG_EXTRA_SIGNERS_JSON, and MG_REMOTE_SIGNER_* empty for this API-only start, then run Core:
For an on-chain Core route, configure the private signer service and the MG_REMOTE_SIGNER_* values; see Private Signer Service. The containerized app services intentionally blank local signer configuration. This page does not configure Compose signing or a live signer.

Optional: local signer inputs for explicit tools

The retained qtg init development renderer requires explicit --legacy-dev-config --network mainnet and can offer 1Password or plaintext local-signer inputs, but those MG_LOCAL_SIGNER_* values are not a compatible qtg.main runtime configuration: Core rejects them. Use local signer inputs only when an explicit tool’s documentation says it supports them; see Local Private-Key Signer. If using qtg init --legacy-dev-config --network mainnet --force for such a tool, its mode-0600 .env.bak.* backup can retain sensitive configuration and is not deleted automatically. For plaintext non-interactive tool setup, prefer QTG_DEV_SIGNER_KEY over a --signer-key argument, which lands in shell history and process listings (ps); pair it with --legacy-dev-config --yes --network mainnet, not the offline preview flags.

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:
Protected --connection-file handoff is available only for an already issued HMAC credential. It can run auth check (and an administrator’s exact revoke), but it does not bootstrap an administrator, create an agent, activate authority, or make a pending key usable. See the CLI reference for its closed command list and file-permission contract.
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.
To tear down docker: ./scripts/quickstart.sh --down

Troubleshooting PostgreSQL bring-up

After PostgreSQL is healthy, rerun the global migration and the one network migration selected by MG_NETWORK_MODE; do not migrate both mainnet and testnet into the same database.

Manual path

If you prefer to configure each step yourself:

Step 1: Clone and install

Step 2: Configure environment

Open .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 set MG_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. The Free adapter reads ordinary account balances; QTG Pro registers the privileged master-signed sub-account balance read that calls /sapi/v3/sub-account/assets. That Pro read requires the master API key’s 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.
After that, you can use an alias such as 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 run qtg 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:
If Compose reports that the external volume is missing on a machine that has been running QTG before, do not create it and start over — the database volume is gone and recovering it comes first. If you would rather point at a PostgreSQL you already run, set MG_DATABASE_URL to it instead and skip this step; the migrations below then apply to that database.

Step 4: Migrate and start the server

Database schema is managed by Alembic migrations. Migrate the global bucket plus the one network bucket matching MG_NETWORK_MODE — a single database holds exactly one network bucket (the schema guard rejects the second):
For an API-only Core start, leave MG_LOCAL_SIGNER_*, MG_EXTRA_SIGNERS_JSON, and MG_REMOTE_SIGNER_* empty:
Local signer inputs are only for explicit tools that document their support. An on-chain Core route instead requires the private signer service and MG_REMOTE_SIGNER_* configuration described in Private Signer Service.

Step 5: Health Check

Expected response:

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)

The dashboard is available at 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