07 — Deployment & Environments
Topology
flowchart TB
subgraph Edge["Vercel (edge)"]
WWW[drpxbt.xyz]
APP[app.drpxbt.xyz — planned<br/>terminal]
PA[hunter-platform<br/>serverless]
end
subgraph Cluster["Our infrastructure"]
GW[hunter-gateway<br/>gateway ×N]
AG[hunter-agent]
MCPS[MCP servers]
WK[hunter-workers]
PG[(Postgres + pgvector)]
RD[(Redis)]
VLLM[vLLM on GPUs]
end
subgraph Chain["Base"]
CT[Contracts]
end
WWW --> APP --> GW
APP --> PA
APP --> CT
GW --> VLLM
GW --> PG
GW --> PA
AG --> GW
AG --> MCPS
AG --> PG
WK --> AG
WK --> RD
WK --> CT
WK --> PA
Static and serverless surfaces run on Vercel; anything that touches the GPUs or holds long-lived state runs on our own infrastructure. The GPU subnet is not publicly routable — the gateway is the only ingress.
Environments
| Environment | Chain | Models | Purpose |
|---|---|---|---|
Local (hunter-demo) |
anvil | Small local model or mock | Full-stack development |
| Staging | Base Sepolia | One small model | Integration, contract rehearsal |
| Production | Base mainnet | Full roster | Live |
Config is environment-variable only — no environment-specific code paths. Every
service ships .env.example documenting its full surface.
Local development
hunter-demo composes the stack. [PLANNED] additions: gateway + CPU model
backend, Postgres/pgvector, Redis, an anvil node with contracts deployed by a
bootstrap script, and a seed script that locks tokens for a demo wallet so the
whole tier → API key → inference path works offline.
Individually:
# Gateway
cd hunter-gateway && uv venv && uv pip install -e ".[dev]"
uv run uvicorn hunter_server.main:app --reload --port 8080
# Agent
cd hunter-agent && uv sync --extra dev
CONFIG_FILE=./characters/hunter.json uv run uvicorn hunter.main:app --reload
# Contracts
cd hunter-contracts && npm ci && npm test
# Frontends
cd hunter-terminal && npm ci && npm run dev
CI/CD
Every repository gates merges on GitHub Actions (push + pull_request):
| Repo | Job | Gate |
|---|---|---|
hunter-contracts |
npm ci → compile → test |
full contract suite |
hunter-gateway |
uv venv → pytest | tests |
hunter-agent |
uv sync → pytest and pylint | tests + lint |
hunter-platform |
pytest + app-factory import | routes register |
hunter-mcps |
pytest (mcp-twitter) | tests |
airdropio-scraper |
uv sync → pytest | tests |
drpxbt.xyz, hunter-terminal |
tsc --noEmit → build |
typecheck + build |
hunterpods-frontend |
build (tsc && vite build) |
typecheck + build |
hunter-workers, hunter-podcast, hunter-scrapers |
compileall + pytest-if-present | syntax |
Two runner-environment rules learned the hard way and encoded in every workflow:
- Never
uv pip install --system— GitHub runners' Python is externally managed (PEP 668) and rejects it. Create a project venv. - Invoke pytest as
python -m pytest— barepytestdoes not put the repository root onsys.path, soimport app/import srcfails in CI while passing locally.
Python dependency management is uv (uv.lock) for actively developed
services. Poetry workflows were removed: poetry install does not install PEP
621 [project.optional-dependencies], which silently produced an environment
with no test runner — See ADR-005 for why the toolchain moved to uv.
Contract deployment
cd hunter-contracts && cp .env.example .env # RPC, key, addresses
npm run deploy:sepolia
npm run deploy:base # only after audit
Compilation pins the npm solc wasm build via a Hardhat subtask override, so
builds are deterministic and work behind proxies/offline where
binaries.soliditylang.org is unreachable (ADR-007).
Runtime configuration
| Service | Critical variables |
|---|---|
hunter-gateway |
HUNTER_DATABASE_URL, HUNTER_JWT_SECRET_KEY, HUNTER_MODELS_CONFIG, HUNTER_TIER_CREDITS, HUNTER_ENTITLEMENTS_URL, HUNTER_X402_* |
hunter-agent |
CONFIG_FILE, DB_URI, JWT_SECRET_KEY, MCP_CONFIG, ACP_SERVICE_TOKEN, OPENAI_BASE_URL (→ gateway) |
hunter-platform |
DB_*, API_TOKEN, API_VERSION |
hunter-mcps |
TWITTERAPI_IO_KEY |
drpxbt.xyz |
VITE_BASE_RPC_URL, VITE_DRPXBT_ADDRESS, VITE_TIERLOCK_ADDRESS, VITE_STAKING_ADDRESS |
hunter-terminal |
VITE_BACKEND_API_URL, VITE_WALLETCONNECT_PROJECT_ID, token-gate vars |
JWT_SECRET_KEY must be identical in hunter-agent and hunter-gateway —
that shared secret is what makes one SIWE session work across both.
Scaling
| Component | Strategy | First bottleneck |
|---|---|---|
| Gateway | Horizontal (stateless) | Postgres write throughput on the ledger |
| vLLM | Add GPU nodes to the pool | GPU memory / concurrent sequences |
| Agent | Horizontal per room | Long tool chains — needs checkpointing |
| Workers | One process per queue | Redis, then external API rate limits |
| Platform API | Serverless auto-scale | Connection pool |
| Postgres | Vertical, then read replicas | Usage-ledger inserts |
Known scaling work, in the order it will bite: usage-ledger partitioning by month, Redis token buckets for per-key rate limiting (today only monthly credit quotas exist), LangGraph Postgres checkpointing for resumable pipelines, and a health-checked multi-node upstream pool in the gateway.