pnpm + TypeScript workspace per design doc §13:
- apps/{web,api,worker} skeletons (Next.js 16, Fastify 5, BullMQ)
- packages/{core,solana,prometheus,db,config} (core has real types/DTOs;
solana/prometheus are stubs)
- programs/pyre-core placeholder (future Anchor, v1.0)
- docs/: PYRE_MVP_DESIGN (canonical), ARCHITECTURE, SECURITY, TOKEN_CLASSIFICATION
- CLAUDE.md, README, .env.example (no private-key var by design)
Skeleton + docs only — no Solana/business logic yet. All workspaces typecheck clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
20 KiB
PYRE — Engineering Architecture
Companion to
PYRE_MVP_DESIGN.md. The design document is the canonical source of truth; this file describes how the system is wired together. Where they appear to disagree, the design document wins.
Tagline: Burn the dead. Feed the PYRE. Claim the Spawn.
1. System Overview
PYRE is a Solana wallet-cleanup and ritual meme-rebirth protocol. The MVP runs as three runtime services backed by two stateful stores, and it depends on two classes of external service: a Solana RPC provider and AI APIs.
Runtime services:
apps/web(pyre-web) — Next.js frontend. Wallet connect, scanner UI, cleanup preview, signing, receipt rendering, Prometheus review, admin pages.apps/api(pyre-api) — Node.js/Fastify (or Express) HTTP API. Scan coordination, classification, unsigned transaction building, receipt storage, AI orchestration, admin API. The only service the browser talks to.apps/worker(pyre-worker) — Node.js BullMQ worker. Slow/async jobs: metadata enrichment, AI generation, image prompts, safety/collision checks, confirmation tracking, receipt enrichment.
Stateful stores:
- PostgreSQL — durable record of scans, classifications, receipts, generations, and Spawn records.
- Redis — BullMQ job queue, scan cache, rate limiting, quote cache, generation status.
External dependencies (never self-hosted on the MVP VPS):
- Solana RPC — external provider only. No validator/RPC node on the VPS.
- AI APIs — text, image, and moderation APIs only. No local LLM/image models.
Component / Data-Flow Diagram
┌──────────────┐
│ Wallet │ (Phantom / Solflare via Wallet Adapter)
│ (browser) │ signs locally — keys never leave the client
└──────┬───────┘
│ connect / sign / send
▼
┌──────────────┐ static assets / SSR
│ apps/web │◀───────────────────────────┐
│ (Next.js) │ │
└──────┬───────┘ │
│ HTTPS (JSON) │
▼ │
┌───────────────────────────────────────────────┐ │
│ apps/api │ │
│ scan · classify · build (UNSIGNED) · receipt │ │
│ prometheus/generate · admin │ │
└───┬─────────────┬──────────────┬────────────────┘ │
│ │ │ │
│ SQL │ cache/queue │ getAccounts / simulate / │
▼ ▼ │ sendTx / confirm │
┌──────────┐ ┌──────────┐ ▼ │
│ Postgres │ │ Redis │ ┌──────────────┐ │
│ │ │ (BullMQ) │ │ Solana RPC │ (external) │
└──────────┘ └────┬─────┘ └──────────────┘ │
│ │
│ jobs pulled from queue │
▼ │
┌──────────────┐ ┌──────────────┐ │
│ apps/worker │───▶│ AI APIs │ (external) │
│ (BullMQ) │ │ text/image/ │ │
│ │ │ moderation │ │
└──────┬───────┘ └──────────────┘ │
│ writes results / status │
├───────────────▶ Postgres │
└───────────────▶ Redis ────────────────────┘
(generation status read back by web/api)
The browser only ever talks to apps/web and apps/api. The worker is not
network-exposed; it consumes jobs from Redis and writes results back to Postgres
and Redis. RPC and AI calls flow outbound only.
2. Component Responsibilities
apps/web — User-facing frontend
Next.js + TypeScript + Tailwind + Solana Wallet Adapter, with React Query or Zustand for state. Responsibilities (§11):
- Wallet connect via Solana Wallet Adapter.
- Token-account display and classification grouping (closeable / burnable / transmutable / protected / unsupported).
- User confirmations and transaction preview UI.
- Transaction signing (client-side, via the connected wallet only).
- Receipt rendering and optional share image.
- Prometheus Spawn-package review and public round/Spawn pages.
- Admin / generation review UI.
apps/api — Backend HTTP API
Node.js + Fastify/Express + TypeScript, fronting PostgreSQL, Redis, BullMQ. Responsibilities (§11):
- Token-scan coordination (calls RPC, persists results).
- Classification helpers and route evaluation.
- Builds UNSIGNED Solana transactions — never signs, never holds keys.
- Metadata preparation and AI generation orchestration (enqueues worker jobs).
- Receipt storage and Spawn-record storage.
- Public API and protected admin API.
apps/worker — Background worker
Node.js worker process driven by BullMQ over Redis, with AI API clients. Responsibilities (§11):
- Slow token-metadata enrichment.
- AI generation jobs (Prometheus).
- Image-prompt generation.
- Safety checks and ticker/name collision checks.
- Background confirmation tracking.
- Receipt enrichment.
packages/core — Shared types & business logic
The single home for cross-service domain definitions (§13):
- Classification enums:
EMPTY_CLOSE_ONLY,INCINERATE_ONLY,TRANSMUTABLE,PROTECTED_SKIP,UNSUPPORTED. - Conservative risk rules (the §7 safety rules: classic SPL only, skip Token-2022/NFTs/LP/frozen/delegated, USD threshold, price-impact and stale-quote guards).
- Shared DTOs for the API request/response shapes.
- Receipt schema.
- Prometheus input/output schema.
packages/solana — Solana transaction helpers
Everything that touches the chain at the instruction level (§13):
- Token-account parsing (decode raw account state into the scan model).
- Close-account transaction builder.
- Burn transaction builder.
- Simulation helpers (simulate before signing — §7).
- Transaction decoder (decode the built tx so it can be matched against the preview — §8 step 5, §16).
packages/prometheus — AI generation logic
The creative engine's code (§13), invoked by the worker:
- Prompt templates.
- The meta mixer (probabilistic influence blend — §9).
- Output parser.
- Safety checks (blocked terms, scam/impersonation/copyright filters).
- Image-prompt generator.
packages/db — Database layer
Schema, migrations, and table definitions (§13/§15). Owns the canonical SQL and
migration history; apps/api and apps/worker depend on it for data access.
packages/config — Shared config
Shared configuration and environment loading (§13). Centralizes reading
.env-supplied secrets (RPC URL, AI keys, DB/Redis connection strings) so no
secret is hard-coded.
programs/pyre-core — Future Anchor program
NOT part of the first burner MVP. The future on-chain trust core (rounds, Essence vault, claims, refunds) — built only at Phase 7 / v1.0.
3. Request / Data Flow — The Burner Journey
The core flow is the 8-step burner sequence from §8. The critical trust property: the server builds an UNSIGNED transaction, the client signs it, and the decoded transaction is matched against the preview before signing.
1. Connect ──▶ 2. Scan ──▶ 3. Classify ──▶ 4. Preview ──▶ 5. Build (UNSIGNED)
│
▼
8. Receipt ◀── 7. Confirm ◀── 6. Sign (client) ◀── decode & match against preview
- Wallet Connect — user connects via Solana Wallet Adapter (
apps/web). No keys leave the browser. - Account Scan —
apps/webcallsPOST /api/scan.apps/apiqueries token accounts via the external RPC, capturing for each: owner, ATA address, mint, token program, balance, decimals, rent estimate, metadata (if available), token-program type, frozen/delegated state. Results persist towallet_scans/token_accounts; slow metadata enrichment may be deferred to a worker job. Scan results are cached in Redis. - Classification — each account is classified server-side into the §6 categories and grouped for the UI. Client-submitted classifications are not trusted — the server recomputes where needed (§16).
- Preview — before any signing the user sees: accounts to close, tokens to burn, accounts skipped, estimated rent returned, transaction fees, warnings, and the destination wallet for recovered rent (which is the user's own wallet).
- Build Transaction —
apps/webcallsPOST /api/build/close-empty(and/or/api/build/burn).apps/apiusespackages/solanato build an unsigned transaction and returns it base64-encoded plus the preview. The client decodes the transaction (packages/solanadecoder) and matches it against the preview; any mismatch aborts before signing. - User Signs — locally, with the connected wallet. PYRE never requests private keys and never performs custodial signing.
- Confirmation — the signed transaction is sent and confirmed via RPC. A worker confirmation-tracking job may follow the signature to durable finality.
- Receipt —
apps/webcallsPOST /api/receipt;apps/apirecords and returns the receipt: tx signature, accounts closed, tokens burned, rent returned, accounts skipped, warnings, timestamp, optional share image. A worker receipt-enrichment job may backfill metadata.
All transactions are simulated before final signing (§7), and all build requests are logged (§16).
4. API Surface
Reproduced from §14. All endpoints are served by apps/api. Admin endpoints are
authenticated and protected separately (§16).
POST /api/scan
// in:
{ "wallet": "wallet_pubkey" }
// out:
{
"scanId": "uuid",
"wallet": "wallet_pubkey",
"summary": {
"totalAccounts": 0,
"emptyCloseOnly": 0,
"incinerateOnly": 0,
"transmutable": 0,
"protectedSkip": 0,
"unsupported": 0,
"estimatedRentLamports": 0
},
"accounts": []
}
POST /api/build/close-empty
// in:
{ "wallet": "...", "accountAddresses": ["ata1", "ata2"] }
// out:
{
"transactionBase64": "...",
"preview": {
"accountsToClose": [],
"estimatedRentReturnedLamports": 0,
"rentDestination": "user_wallet_pubkey"
}
}
POST /api/build/burn
// in:
{ "wallet": "...", "items": [{ "tokenAccount": "...", "mint": "...", "amount": "..." }] }
// out:
{
"transactionBase64": "...",
"preview": {
"tokensToBurn": [],
"accountsPotentiallyClosable": []
}
}
POST /api/receipt
// in:
{ "wallet": "...", "txSignature": "...", "scanId": "uuid" }
// out:
{
"receiptId": "uuid",
"txSignature": "...",
"rentReturnedLamports": 0,
"closedAccounts": [],
"burnedTokens": [],
"skippedTokens": []
}
POST /api/prometheus/generate
// in:
{ "receiptId": "uuid", "chaos": 0.25, "operatorSeed": "optional" }
// out:
{
"generationId": "uuid",
"spawnName": "...",
"ticker": "...",
"lore": "...",
"imagePrompt": "...",
"metadata": {},
"riskFlags": []
}
Admin endpoints
Admin / generation-review endpoints (approve/reject generations, record Pump.fun launches, view system events) are protected and not part of the public surface. They back the admin review UI and the Spawn-record workflow (§10, §16).
5. Data Model
Initial PostgreSQL tables (§15)
wallet_scans: id, wallet, status, created_at, completed_at, summary_json
token_accounts: id, scan_id, wallet, ata, mint, token_program,
raw_balance, ui_balance, decimals, symbol, name,
classification, warnings_json, estimated_rent_lamports,
created_at
cleanup_receipts: id, wallet, scan_id, tx_signature, rent_returned_lamports,
closed_accounts_count, burned_tokens_count, status,
created_at, receipt_json
prometheus_generations: id, receipt_id, input_json, output_json, status,
risk_flags_json, created_at, approved_at, rejected_at
spawn_records: id, generation_id, spawn_name, ticker, mint, metadata_uri,
pumpfun_url, launch_tx, status, created_at
Additional initial tables called out in §11/§15: token_classifications,
burn_events, close_account_events, spawn_candidates, and system_events
(audit/event log).
Future tables (NOT in the burner MVP)
These arrive with the Essence ledger and PYRE Core program (Phases 6–7):
pyre_rounds— round state machine.essence_contributions— recorded Essence per wallet per round.claim_records— Spawn claim accounting.refund_records— refunds for failed rounds.influence_fields— meta-influence inputs for Prometheus weighting.
Per §5/§15: Essence may start in the database, but it must not be called a deposit until an on-chain custody model exists, and claims must not be promised until claim logic exists.
6. Redis Usage
Redis serves five roles (§11):
- Job queue — backs BullMQ;
apps/apienqueues,apps/workerconsumes. - Scan cache — caches scan results so repeat views don't re-hit RPC.
- Rate limiting — throttles scan and build endpoints (§16).
- Temporary quote cache — short-lived swap/route quotes; stale quotes are rejected by classification (§7).
- Generation status — live status of in-flight Prometheus jobs, read back by
apps/web/apps/api.
BullMQ Worker Jobs
apps/worker processes these job types (§11):
- Metadata enrichment — slow token name/symbol/metadata lookups.
- AI generation — Prometheus Spawn generation.
- Image prompts — image-prompt generation for the Spawn.
- Safety checks — moderation of generated names/tickers/lore.
- Collision checks — ticker/name duplicate detection.
- Confirmation tracking — follow tx signatures to finality in the background.
- Receipt enrichment — backfill receipt detail after confirmation.
7. Solana RPC Requirements
PYRE uses an external RPC provider only. Per §11/§12, the MVP VPS must not run a Solana validator or RPC node.
Required RPC capabilities (§11):
- Get token accounts by owner.
- Get account info.
- Simulate transactions.
- Send transactions.
- Confirm transactions.
- Parse token-account state.
The RPC endpoint URL is supplied via environment config (packages/config) and
treated as a secret. All chain access flows through packages/solana.
8. AI Services
AI is API-based only (§11/§12). The MVP server must not run local LLMs or local image-generation models.
Service classes used:
- Text generation — Spawn name, ticker, lore, tagline, description, launch copy (§9 outputs).
- Image generation — from the generated image prompt.
- Moderation / safety — filtering hate/explicit/extremist/copyrighted/ impersonation/scam-like output (§16).
All AI calls are made from apps/worker using clients configured via secrets in
packages/config. Prometheus generates a candidate package for human review —
it never launches tokens or controls funds (§9).
9. Infrastructure & Deployment
A single 8GB VPS is sufficient for the MVP (§12). It runs:
pyre-web,pyre-api,pyre-worker- PostgreSQL
- Redis
- nginx (reverse proxy / TLS termination in front of web + api)
- PM2 or systemd (process supervision for the three Node services)
- logs / log rotation
- admin dashboard
The VPS must NOT run (§12):
- a Solana validator,
- a Solana RPC node,
- a large local LLM,
- local image generation,
- heavy indexing at scale.
Base setup already completed (§12/§19): pyre user created, root login
disabled, SSH key auth, UFW firewall, Fail2ban, basic hardening.
Next setup (§12/§19): Node.js 22, pnpm, Git, nginx, PostgreSQL, Redis, PM2, Claude Code, project repo, environment files, backup script, log rotation.
External accounts required (§19): Solana RPC provider, OpenAI/Anthropic API key, image-generation provider, domain name, GitHub repo, Pump.fun creator wallet, optional IPFS/Arweave metadata service.
10. Build-Order Note (Phased Roadmap)
Components map to the §18 development phases so a reader knows what gets built when:
| Phase | Focus | Components touched |
|---|---|---|
| 0 — Server & Repo Setup | VPS, pnpm workspace, web/api/worker skeletons, Postgres + Redis, nginx, env templates | all apps (skeleton), packages/config, infra/ |
| 1 — Wallet Scanner | Wallet connect, scan endpoint, token-account fetch, basic classification, results + protected/skipped UI | apps/web, apps/api, packages/solana (parsing), packages/core (enums/rules), packages/db (wallet_scans, token_accounts) |
| 2 — Close Empty ATAs | Build close-account tx, decode/preview, signing, confirmation tracking, receipt page | packages/solana (close builder + decoder + simulation), apps/api (/build/close-empty, /receipt), apps/worker (confirmation tracking), packages/db (cleanup_receipts, close_account_events) |
| 3 — Burn Junk | INCINERATE_ONLY classification, burn builder, burn-then-close, stronger confirmations, receipt update |
packages/solana (burn builder), apps/api (/build/burn), packages/db (burn_events) |
| 4 — Prometheus Generator | Generation input from receipt, meta mixer, name/ticker/lore + image prompt, safety checks, admin approval UI | packages/prometheus, apps/worker (AI/safety/collision jobs), apps/api (/prometheus/generate, admin), apps/web (review UI), packages/db (prometheus_generations, spawn_candidates) |
| 5 — Manual Pump.fun Launch | Approved package, metadata JSON, operator checklist, record mint/url/tx, public Spawn page | apps/web (public Spawn page), apps/api (admin record endpoints), packages/db (spawn_records) |
| 6 — Essence / Round Prototype | Swap-candidate detection, route quote preview, net Essence estimate, round dashboard, DB-only contribution record (no claim promises) | packages/solana (route eval), apps/api, packages/db (future pyre_rounds, essence_contributions, influence_fields) |
| 7 — PYRE Core Program | Anchor program: create round, contribute Essence, contribution-receipt PDA, lock round, register Spawn, claim, refund, tests | programs/pyre-core, future tables claim_records, refund_records |
The first three phases deliver the trust-building burner (v0.1). The Anchor
program in programs/pyre-core is explicitly not needed until Phase 7 / v1.0.
PYRE returns your rent. The scraps feed the fire.