chore: scaffold PYRE MVP monorepo (structure + docs)

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>
This commit is contained in:
2026-05-31 02:20:55 +00:00
parent e86b57e00f
commit c20094ab56
65 changed files with 13834 additions and 1 deletions

32
packages/core/README.md Normal file
View File

@@ -0,0 +1,32 @@
# @pyre/core
Shared types and business logic for PYRE / Prometheus Protocol.
## Purpose
The canonical home for cross-cutting type definitions and (eventually) pure
business logic shared by `apps/*` and the other `packages/*`. Per §13 its
responsibilities are:
- **Classification enums** — `TokenClassification` (§6).
- **Risk rules** — conservative safety-rule types/constants (§7). _Placeholder._
- **Shared DTOs** — request/response shapes for the HTTP API (§14).
- **Receipt schema** — `CleanupReceipt` (§8, §15).
- **Prometheus I/O schema** — `PrometheusInput` / `PrometheusOutput` (§9).
This package carries **real type definitions** but **no application logic** in
the skeleton.
## Modules
- `src/classification.ts``TokenClassification` enum.
- `src/dto.ts` — API request/response DTOs.
- `src/receipt.ts` — cleanup receipt schema.
- `src/prometheus.ts` — Prometheus meta-mixer input/output.
- `src/risk.ts` — risk-rule placeholder.
## TODO
- Define concrete risk-rule identifiers, threshold shapes, and pure evaluators.
- Tighten DTO shapes flagged `TODO` once the scan/classify/build pipeline lands.
- Define the concrete token `metadata` JSON shape used by receipts and Prometheus.

View File

@@ -0,0 +1,17 @@
{
"name": "@pyre/core",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc --noEmit",
"lint": "echo \"lint: ok (placeholder)\"",
"test": "echo \"test: ok (placeholder)\""
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,45 @@
/**
* Conservative token-account classification categories.
*
* See §6 (Token Classification) and §7 (Token Safety Rules) of
* `docs/PYRE_MVP_DESIGN.md`. The classifier must be conservative — it must never
* assert that a token is "safe", only that it "appears eligible based on current
* checks". Anything that cannot be reasoned about safely defaults to
* `PROTECTED_SKIP` / `UNSUPPORTED` ("Unknown means skip").
*/
export enum TokenClassification {
/**
* Zero balance; the associated token account (ATA) can be closed.
* Action: close the ATA and return the recovered rent to the user wallet.
*/
EMPTY_CLOSE_ONLY = "EMPTY_CLOSE_ONLY",
/**
* Has a balance but no safe swap route; the balance may, however, be burnable.
* Action: the user may burn the balance to zero; if the account then becomes
* empty it can be closed, and recovered rent returns to the user.
*/
INCINERATE_ONLY = "INCINERATE_ONLY",
/**
* Has a safe swap route and passes risk checks.
* Action: the user may swap the token into SOL; net swapped SOL may become
* Essence ONLY if the user explicitly opts in.
*/
TRANSMUTABLE = "TRANSMUTABLE",
/**
* Not touched by default. Examples: SOL/WSOL special cases, USDC/USDT/major
* assets, valuable meme tokens, NFTs, LP tokens, receipt tokens, staked
* tokens, suspicious tokens, frozen accounts, delegated accounts, and
* high-value balances. Requires explicit manual opt-in to act on.
*/
PROTECTED_SKIP = "PROTECTED_SKIP",
/**
* The system cannot safely reason about the account. Examples: Token-2022 in
* the MVP, unknown token program, bad metadata, unsupported account layout, or
* accounts with extension behavior not yet handled.
*/
UNSUPPORTED = "UNSUPPORTED",
}

172
packages/core/src/dto.ts Normal file
View File

@@ -0,0 +1,172 @@
/**
* Shared API DTOs for the PYRE HTTP API.
*
* Shapes are derived from §14 (API Design) of `docs/PYRE_MVP_DESIGN.md`.
*
* NOTE: lamport amounts are represented as `string` (not `number`) to avoid
* precision loss with large u64 values, matching the design doc's JSON shapes.
*
* TODO: several shapes below are approximate and will be tightened once the
* scan/classify/build pipeline is implemented. Approximations are flagged inline.
*/
import type { TokenClassification } from "./classification.js";
// ---------------------------------------------------------------------------
// POST /api/scan
// ---------------------------------------------------------------------------
export interface ScanRequest {
/** Wallet public key (base58). */
wallet: string;
}
export interface ScanSummary {
totalAccounts: number;
emptyCloseOnly: number;
incinerateOnly: number;
transmutable: number;
protectedSkip: number;
unsupported: number;
/** Total estimated recoverable rent across closeable accounts, in lamports. */
estimatedRentLamports: string;
}
export interface TokenAccountDto {
/** Associated token account address (base58). */
ata: string;
/** Owner wallet (base58). */
owner: string;
/** Token mint (base58). */
mint: string;
/** Owning token program (base58). Classic SPL only in the MVP. */
tokenProgram: string;
/** Raw on-chain balance (u64 as string). */
rawBalance: string;
/** Human-readable balance (raw / 10^decimals). */
uiBalance: number;
decimals: number;
/** Token symbol, if metadata is available. */
symbol?: string;
/** Token name, if metadata is available. */
name?: string;
classification: TokenClassification;
/** Human-readable warnings surfaced to the user (e.g. "frozen account"). */
warnings: string[];
/** Estimated rent recoverable by closing this account, in lamports. */
estimatedRentLamports: string;
/** Whether the account is frozen, if known. TODO: confirm availability. */
frozen?: boolean;
/** Whether the account is delegated, if known. TODO: confirm availability. */
delegated?: boolean;
}
export interface ScanResponse {
/** UUID of the persisted scan. */
scanId: string;
wallet: string;
summary: ScanSummary;
accounts: TokenAccountDto[];
}
// ---------------------------------------------------------------------------
// POST /api/build/close-empty
// ---------------------------------------------------------------------------
export interface BuildCloseEmptyRequest {
wallet: string;
/** ATA addresses to close (must be EMPTY_CLOSE_ONLY). */
accountAddresses: string[];
}
export interface BuildCloseEmptyPreview {
accountsToClose: string[];
estimatedRentReturnedLamports: string;
/** Destination for recovered rent — must default to the user's own wallet. */
rentDestination: string;
}
export interface BuildCloseEmptyResponse {
/** Unsigned transaction, base64-encoded. Signed client-side only. */
transactionBase64: string;
preview: BuildCloseEmptyPreview;
}
// ---------------------------------------------------------------------------
// POST /api/build/burn
// ---------------------------------------------------------------------------
export interface BurnItem {
/** Token account holding the balance to burn (base58). */
tokenAccount: string;
/** Mint of the token being burned (base58). */
mint: string;
/** Raw amount to burn (u64 as string). */
amount: string;
}
export interface BuildBurnRequest {
wallet: string;
items: BurnItem[];
}
export interface BuildBurnPreview {
tokensToBurn: BurnItem[];
/** Accounts that may become closeable once their balance reaches zero. */
accountsPotentiallyClosable: string[];
/** TODO: include estimated rent and fees once the builder is implemented. */
estimatedRentReturnedLamports?: string;
}
export interface BuildBurnResponse {
/** Unsigned transaction, base64-encoded. Signed client-side only. */
transactionBase64: string;
preview: BuildBurnPreview;
}
// ---------------------------------------------------------------------------
// POST /api/receipt
// ---------------------------------------------------------------------------
export interface ReceiptRequest {
wallet: string;
/** Confirmed transaction signature. */
txSignature: string;
/** UUID of the originating scan. */
scanId: string;
}
export interface ReceiptResponse {
receiptId: string;
txSignature: string;
rentReturnedLamports: string;
/** Addresses of accounts that were closed. */
closedAccounts: string[];
/** Mints (or token accounts) that were burned. TODO: confirm element shape. */
burnedTokens: string[];
/** Accounts intentionally skipped. TODO: confirm element shape. */
skippedTokens: string[];
}
// ---------------------------------------------------------------------------
// POST /api/prometheus/generate
// ---------------------------------------------------------------------------
export interface PrometheusGenerateRequest {
receiptId: string;
/** Chaos factor 0..1 controlling mutation strength. */
chaos: number;
/** Optional manual operator theme seed. */
operatorSeed?: string;
}
export interface PrometheusGenerateResponse {
generationId: string;
spawnName: string;
ticker: string;
lore: string;
imagePrompt: string;
/** Token metadata JSON blob. TODO: define concrete metadata shape. */
metadata: Record<string, unknown>;
/** Safety/compliance flags raised during generation. */
riskFlags: string[];
}

View File

@@ -0,0 +1,5 @@
export * from "./classification.js";
export * from "./dto.js";
export * from "./receipt.js";
export * from "./prometheus.js";
export * from "./risk.js";

View File

@@ -0,0 +1,43 @@
/**
* Prometheus AI meta-mixer I/O schema.
*
* Input/output shapes from §9 (Prometheus AI Meta Mixer) of
* `docs/PYRE_MVP_DESIGN.md`. Prometheus generates Spawn *identity* only — it
* never controls funds.
*/
/** A token contributing to a Spawn, summarized from a cleanup receipt. */
export interface PrometheusTokenRef {
mint: string;
symbol?: string;
name?: string;
}
export interface PrometheusInput {
burnedTokens: PrometheusTokenRef[];
transmutedTokens: PrometheusTokenRef[];
tokenSymbols: string[];
tokenNames: string[];
metadataDescriptions: string[];
/** Dominant thematic archetypes inferred from the inputs. */
dominantArchetypes: string[];
/** Chaos factor 0..1 controlling mutation strength. */
chaosFactor: number;
/** Optional manual operator theme seed. */
manualThemeSeed?: string;
}
export interface PrometheusOutput {
spawnName: string;
spawnTicker: string;
spawnLore: string;
spawnTagline: string;
spawnDescription: string;
imagePrompt: string;
/** Token metadata JSON blob. TODO: define concrete metadata shape. */
metadataJson: Record<string, unknown>;
/** Marketing/launch copy. */
launchCopy: string;
/** Safety/compliance flags raised during generation. */
riskFlags: string[];
}

View File

@@ -0,0 +1,60 @@
/**
* Cleanup receipt schema.
*
* Models the receipt produced after a confirmed burner transaction. Fields are
* drawn from §8 (Burner Transaction Flow — step 8) and §15 (cleanup_receipts
* table) of `docs/PYRE_MVP_DESIGN.md`.
*
* This is the canonical, enriched receipt persisted as `receipt_json`; the API
* surfaces a subset via `ReceiptResponse` in `dto.ts`.
*/
export interface ClosedAccountEntry {
/** ATA address that was closed (base58). */
ata: string;
mint: string;
/** Rent reclaimed from closing this account, in lamports. */
rentLamports: string;
}
export interface BurnedTokenEntry {
tokenAccount: string;
mint: string;
/** Raw amount burned (u64 as string). */
amount: string;
symbol?: string;
name?: string;
}
export interface SkippedTokenEntry {
ata: string;
mint: string;
/** Why this account was skipped (classification + warnings). */
reason: string;
}
export interface CleanupReceipt {
/** Receipt UUID. */
receiptId: string;
/** Originating scan UUID. */
scanId: string;
/** Owner wallet (base58). */
wallet: string;
/** Confirmed transaction signature. */
txSignature: string;
/** Total rent returned to the user, in lamports. */
rentReturnedLamports: string;
/** Destination wallet for recovered rent — defaults to the user's wallet. */
rentDestination: string;
closedAccounts: ClosedAccountEntry[];
burnedTokens: BurnedTokenEntry[];
skippedTokens: SkippedTokenEntry[];
/** Network/transaction fees paid, in lamports. */
feeLamports?: string;
/** Warnings shown to the user before signing. */
warnings: string[];
/** ISO-8601 timestamp the receipt was finalized. */
createdAt: string;
/** Optional shareable receipt image URL. */
shareImageUrl?: string;
}

15
packages/core/src/risk.ts Normal file
View File

@@ -0,0 +1,15 @@
/**
* Risk-rule types and constants (placeholder).
*
* The conservative safety rules from §7 (Token Safety Rules) live here once the
* classifier is implemented. Thresholds are operator-tunable via `@pyre/config`
* (e.g. PROTECTED_USD_THRESHOLD, MAX_PRICE_IMPACT_BPS, QUOTE_MAX_AGE_MS).
*
* Guiding principle: the system must never assert a token is "safe" — only that
* it "appears eligible based on current checks". Unknown means skip.
*
* TODO: define risk-rule identifiers, a RiskRuleResult type, threshold config
* shape, and the (pure) evaluation function signatures. No implementation yet.
*/
export {};

View File

@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}