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

38
packages/config/README.md Normal file
View File

@@ -0,0 +1,38 @@
# @pyre/config
Shared configuration and environment loading for PYRE.
## Purpose
Per §13: shared config and environment loading. Provides a typed `Env` interface
and a `loadConfig()` loader that maps the variables in the repo-root
`.env.example` into typed config.
## Trust rule
There is intentionally **no** wallet private-key / mnemonic variable here, and
there never will be (§3). All signing happens client-side in the user's wallet.
## Variables (mirrors `.env.example`)
- **Solana** — `SOLANA_RPC_URL`, `SOLANA_RPC_WS_URL`, `SOLANA_CLUSTER`
- **Database** — `DATABASE_URL`
- **Redis** — `REDIS_URL`
- **AI** — `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `IMAGE_GEN_PROVIDER`,
`IMAGE_GEN_API_KEY`
- **App URLs / ports** — `WEB_PORT`, `API_PORT`, `WEB_PUBLIC_URL`,
`API_PUBLIC_URL`
- **Admin / security** — `ADMIN_API_TOKEN`, `RATE_LIMIT_SCAN_PER_MIN`
- **Classification thresholds** — `PROTECTED_USD_THRESHOLD`,
`MAX_PRICE_IMPACT_BPS`, `QUOTE_MAX_AGE_MS`
- **Optional / later phases** — `IPFS_OR_ARWEAVE_ENDPOINT`,
`IPFS_OR_ARWEAVE_TOKEN`, `PUMPFUN_CREATOR_WALLET_PUBKEY` (public key only)
## Status
**Skeleton.** Defines `Env`; `loadConfig()` is a stub.
## TODO
- Implement `loadConfig()` — read `process.env`, validate/coerce, apply defaults,
fail fast on missing required values. Never hardcode secrets.

View File

@@ -0,0 +1,17 @@
{
"name": "@pyre/config",
"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,72 @@
/**
* @pyre/config — shared config & environment loading (SKELETON).
*
* Responsibilities (§13): shared config and environment loading. Variables mirror
* `.env.example` at the repo root.
*
* TRUST RULE (§3): there is intentionally NO wallet private-key / mnemonic
* variable here, and there never will be. All signing happens client-side.
*
* Do NOT hardcode secrets — values come from the process environment at runtime.
*/
export type SolanaCluster = "mainnet-beta" | "devnet" | "testnet";
/**
* Typed view of the supported environment variables.
* Mirrors `.env.example` (sans the deliberately-absent private-key var).
*/
export interface Env {
// ---- Solana ----
solanaRpcUrl: string;
solanaRpcWsUrl?: string;
solanaCluster: SolanaCluster;
// ---- Database (PostgreSQL) ----
databaseUrl: string;
// ---- Redis (queues, cache, rate limiting) ----
redisUrl: string;
// ---- AI services (Prometheus) ----
anthropicApiKey?: string;
openaiApiKey?: string;
/** e.g. "openai" | "stability" | "replicate". */
imageGenProvider?: string;
imageGenApiKey?: string;
// ---- App URLs / ports ----
webPort: number;
apiPort: number;
webPublicUrl: string;
apiPublicUrl: string;
// ---- Admin / security ----
adminApiToken?: string;
rateLimitScanPerMin: number;
// ---- Classification safety thresholds ----
/** Skip tokens valued above this (USD). */
protectedUsdThreshold: number;
/** Skip swap routes above this price impact (basis points). */
maxPriceImpactBps: number;
/** Skip stale quotes older than this (ms). */
quoteMaxAgeMs: number;
// ---- Optional: metadata / launch (later phases) ----
ipfsOrArweaveEndpoint?: string;
ipfsOrArweaveToken?: string;
/** Public key ONLY — operator signs Pump.fun launches manually in the MVP. */
pumpfunCreatorWalletPubkey?: string;
}
/**
* Load and validate configuration from the process environment.
*
* TODO: read from `process.env` (mapping the variables in `.env.example`),
* validate/coerce types, apply defaults, and fail fast on missing required
* values. Never hardcode secrets. There is intentionally no private-key var.
*/
export function loadConfig(): Env {
throw new Error("not implemented");
}

View File

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

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"]
}

44
packages/db/README.md Normal file
View File

@@ -0,0 +1,44 @@
# @pyre/db
Database schema, migrations, and table definitions for PYRE (PostgreSQL).
## Purpose
Per §13: the schema, migrations, and table definitions. Uses `pg` for
connectivity. Connection details come from `DATABASE_URL` via `@pyre/config`
**never** hardcode credentials.
## Tables (§15)
### Initial MVP tables
- `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
### Future tables
- `token_classifications`
- `burn_events`
- `close_account_events`
- `spawn_candidates`
- `system_events`
## Status
**Skeleton.** Exports table-name constants and a connection-factory stub. No
queries, no schema DDL, no migrations yet.
## TODO
- Implement the `createPool()` connection factory (read `DATABASE_URL` via
`@pyre/config`).
- Add SQL migrations under `migrations/` and a migration runner.
- Add typed table definitions and a query layer.

View File

View File

@@ -0,0 +1,15 @@
# Migrations
SQL migrations for the PYRE PostgreSQL database.
**Empty for now** (skeleton). Migration files and a runner will be added here.
## Convention (TODO)
- One forward migration per file, ordered/timestamped (e.g.
`0001_init.sql`, `0002_<change>.sql`).
- The first migration creates the initial MVP tables listed in the package
README (§15): `wallet_scans`, `token_accounts`, `cleanup_receipts`,
`prometheus_generations`, `spawn_records`.
- A migration runner (in `@pyre/db`) applies pending migrations against
`DATABASE_URL`.

22
packages/db/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "@pyre/db",
"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)\""
},
"dependencies": {
"@pyre/config": "workspace:*",
"pg": "^8.13.1"
},
"devDependencies": {
"@types/pg": "^8.11.10",
"typescript": "^5.7.2"
}
}

44
packages/db/src/index.ts Normal file
View File

@@ -0,0 +1,44 @@
/**
* @pyre/db — database schema, migrations, and table definitions (SKELETON).
*
* Responsibilities (§13): database schema, migrations, table definitions.
* Schema reference: §15 (MVP Database Schema) of `docs/PYRE_MVP_DESIGN.md`.
*
* No queries are implemented here yet — only table-name constants and a
* connection-factory stub.
*/
import type { Pool } from "pg";
/**
* Canonical table names. Centralized so query/migration code references a single
* source of truth.
*/
export const TABLES = {
// Initial MVP tables (§15)
WALLET_SCANS: "wallet_scans",
TOKEN_ACCOUNTS: "token_accounts",
CLEANUP_RECEIPTS: "cleanup_receipts",
PROMETHEUS_GENERATIONS: "prometheus_generations",
SPAWN_RECORDS: "spawn_records",
// Future tables (§15)
TOKEN_CLASSIFICATIONS: "token_classifications",
BURN_EVENTS: "burn_events",
CLOSE_ACCOUNT_EVENTS: "close_account_events",
SPAWN_CANDIDATES: "spawn_candidates",
SYSTEM_EVENTS: "system_events",
} as const;
export type TableName = (typeof TABLES)[keyof typeof TABLES];
/**
* Connection-factory stub.
*
* TODO: create and cache a `pg` Pool from DATABASE_URL (resolved via
* `@pyre/config` — never hardcode credentials). Then add a migration runner and
* typed table-definition / query layer. No queries are implemented yet.
*/
export function createPool(): Pool {
// TODO: const { databaseUrl } = loadConfig(); return new Pool({ connectionString: databaseUrl });
throw new Error("not implemented");
}

View File

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

View File

@@ -0,0 +1,36 @@
# @pyre/prometheus
AI generation logic for the Prometheus meta mixer.
## Purpose
Generates Spawn **identity** (name, ticker, lore, image prompt, metadata) from
cleanup receipts. Per §13 its responsibilities are:
- Prompt templates.
- Meta mixer.
- Output parser.
- Safety checks.
- Image-prompt generator.
See §9 (meta mixer) and §10 (Pump.fun creator workflow). Prometheus never
controls funds; it only produces creative identity for **manual, human-reviewed**
launch in the MVP.
## Design rules
- Meta influence is probabilistic, not deterministic.
- Produce inspired mutations, not direct clones — reject exact copyrighted or
existing meme identities.
## Status
**Stubs only.** Every exported function throws `Error("not implemented")`.
## TODO
- Implement `buildPrompt`, `runMetaMixer`, `parseOutput`, `runSafetyChecks`,
`generateImagePrompt`.
- The AI client (Anthropic / OpenAI / image-gen provider) is configured via
`@pyre/config` and injected here. This package adds **no** SDK dependencies of
its own.

View File

@@ -0,0 +1,20 @@
{
"name": "@pyre/prometheus",
"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)\""
},
"dependencies": {
"@pyre/core": "workspace:*"
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,72 @@
/**
* @pyre/prometheus — AI generation logic (STUBS ONLY).
*
* Responsibilities (§13): prompt templates, the meta mixer, output parser,
* safety checks, and the image-prompt generator. See §9 (Prometheus AI Meta
* Mixer) and §10 (Pump.fun Creator Workflow) of `docs/PYRE_MVP_DESIGN.md`.
*
* Design notes:
* - Prometheus generates Spawn *identity* only — it never controls funds.
* - Meta influence is probabilistic, not deterministic.
* - Do not allow users to force exact copyrighted/existing meme identities;
* produce inspired mutations, not direct clones.
*
* TODO: the AI client (Anthropic / OpenAI / image-gen provider) is configured
* via `@pyre/config` and injected here — this package adds NO SDK dependencies
* of its own. Wire the client through function parameters or a small interface.
*
* Nothing here is implemented yet — every function throws "not implemented".
*/
import type { PrometheusInput, PrometheusOutput } from "@pyre/core";
const NOT_IMPLEMENTED = "not implemented";
/**
* Build the text-generation prompt from mixer input.
*
* TODO: apply prompt templates and the probabilistic meta-influence weighting
* (burned archetypes / Essence themes / chaos mutation / operator seed).
*/
export function buildPrompt(_input: PrometheusInput): string {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Run the meta mixer end-to-end: build prompt, call the AI client, parse, and
* run safety checks, producing a Spawn package.
*
* TODO: orchestrate buildPrompt -> AI client -> parseOutput -> runSafetyChecks.
* The AI client is injected (configured via @pyre/config).
*/
export function runMetaMixer(_input: PrometheusInput): Promise<PrometheusOutput> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Parse a raw model response into a structured `PrometheusOutput`.
*
* TODO: validate/normalize the model JSON into the output schema.
*/
export function parseOutput(_raw: string): PrometheusOutput {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Run safety/compliance checks over generated output.
*
* TODO: moderation + copyright/clone guards; return risk flags. Must reject
* attempts to clone exact copyrighted or existing meme identities.
*/
export function runSafetyChecks(_output: PrometheusOutput): Promise<string[]> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Generate an image prompt for the Spawn artwork.
*
* TODO: derive an image prompt from the Spawn identity, honoring the same
* anti-clone safety rules.
*/
export function generateImagePrompt(_output: PrometheusOutput): string {
throw new Error(NOT_IMPLEMENTED);
}

View File

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

33
packages/solana/README.md Normal file
View File

@@ -0,0 +1,33 @@
# @pyre/solana
Solana transaction helpers for PYRE.
## Purpose
Token-account reading and **unsigned** transaction construction for the burner
flow. Per §13 its responsibilities are:
- Token-account parsing.
- Close-account transaction builder.
- Burn transaction builder.
- Simulation helpers.
- Transaction decoder (for preview matching).
## Trust rules (load-bearing)
- PYRE never holds private keys — this package builds **unsigned** transactions;
signing happens client-side in the user's wallet.
- Recovered ATA rent defaults to the user's own wallet.
- Always simulate, then **decode** and match against the user-facing preview
before requesting a signature.
- Classic SPL only in the MVP. Skip Token-2022, NFTs, and unsupported layouts.
## Status
**Stubs only.** Every exported function throws `Error("not implemented")`.
## TODO
- Implement `parseTokenAccounts`, `buildCloseEmptyAccountsTx`, `buildBurnTx`,
`simulateTransaction`, and `decodeTransaction`.
- Wire classification through `@pyre/core`.

View File

@@ -0,0 +1,22 @@
{
"name": "@pyre/solana",
"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)\""
},
"dependencies": {
"@pyre/core": "workspace:*",
"@solana/web3.js": "^1.98.0",
"@solana/spl-token": "^0.4.9"
},
"devDependencies": {
"typescript": "^5.7.2"
}
}

View File

@@ -0,0 +1,94 @@
/**
* @pyre/solana — Solana transaction helpers (STUBS ONLY).
*
* Responsibilities (§13): token-account parsing, close-account tx builder, burn
* tx builder, simulation helpers, and a transaction decoder.
*
* IMPORTANT (trust rules, §3/§7/§16):
* - PYRE never holds private keys; these helpers build **unsigned** transactions
* only. Signing happens client-side in the user's wallet.
* - Recovered ATA rent must default to the user's own wallet.
* - Every transaction must be simulated and **decoded**, then matched against the
* preview shown to the user before any signature is requested.
* - Classic SPL only in the MVP. Skip Token-2022 / NFTs / unsupported layouts.
*
* Nothing here is implemented yet — every function throws "not implemented".
*/
import type { Connection, PublicKey } from "@solana/web3.js";
import type {
TokenAccountDto,
BuildCloseEmptyPreview,
BuildBurnPreview,
BurnItem,
} from "@pyre/core";
const NOT_IMPLEMENTED = "not implemented";
/**
* Parse a wallet's SPL token accounts into classified DTOs.
*
* TODO: fetch token accounts via RPC, decode account state (balance, decimals,
* frozen/delegated, token program), resolve metadata, and hand off to the
* classifier in `@pyre/core`. Classic SPL only.
*/
export function parseTokenAccounts(
_connection: Connection,
_wallet: PublicKey,
): Promise<TokenAccountDto[]> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Build an UNSIGNED transaction that closes the given empty ATAs, returning rent
* to the user wallet.
*
* TODO: assemble CloseAccount instructions, set fee payer + rent destination to
* the user, return a base64 transaction plus a matching preview.
*/
export function buildCloseEmptyAccountsTx(
_connection: Connection,
_wallet: PublicKey,
_accountAddresses: PublicKey[],
): Promise<{ transactionBase64: string; preview: BuildCloseEmptyPreview }> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Build an UNSIGNED transaction that burns the given token balances (optionally
* closing accounts that become empty).
*
* TODO: assemble Burn (and optional CloseAccount) instructions, return a base64
* transaction plus a matching preview.
*/
export function buildBurnTx(
_connection: Connection,
_wallet: PublicKey,
_items: BurnItem[],
): Promise<{ transactionBase64: string; preview: BuildBurnPreview }> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Simulate a transaction before signing.
*
* TODO: run `connection.simulateTransaction`, surface logs/errors, and confirm
* the simulation succeeds. All transactions must be simulated before signing.
*/
export function simulateTransaction(
_connection: Connection,
_transactionBase64: string,
): Promise<unknown> {
throw new Error(NOT_IMPLEMENTED);
}
/**
* Decode an unsigned transaction so its contents can be matched against the
* preview shown to the user (accounts to close, tokens to burn, rent amount,
* rent destination, fees, warnings).
*
* TODO: deserialize the transaction, decode SPL instructions, and return a
* structured, human-comparable summary.
*/
export function decodeTransaction(_transactionBase64: string): unknown {
throw new Error(NOT_IMPLEMENTED);
}

View File

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