Architecture
Permafrost is a single Go binary (permafrostd) plus a CLI (permafrost) plus Postgres (TimescaleDB). One operator, one daemon, many agents.
Layout
permafrost/
├── cmd/
│ ├── permafrost/ CLI entrypoint (cobra)
│ └── permafrostd/ daemon entrypoint
│ ├── main.go
│ ├── strategies.go committed: blank-imports community strategies
│ └── strategies_local.go gitignored: blank-imports private strategies
├── pkg/ stable public SAPI (used by strategy authors)
│ ├── strategy/ Strategy, Decision, Services, registry
│ ├── types/ trading-domain types
│ └── inference/ Provider interface + OpenAI-compatible client
├── strategies/ canonical home for strategy packages
│ ├── noop/ reference implementation
│ └── private/ gitignored
│ └── <your_strategy>/
└── internal/ framework internals (not part of the SAPI)
├── agent/ runtime, supervisor, builder, killswitch
├── exchange/hyperliquid/ perp venue
├── swap/jupiter/ Solana spot
├── swap/oneinch/ EVM spot
├── chain/{evm,solana}/ RPC clients + tx tracking
├── wallet/ keystore + signers (only place that touches key bytes)
├── assets/ hand-curated asset registry
├── risk/ pre-trade + portfolio risk
├── reconcile/ position reconciliation
├── pnl/ PnL accounting
├── store/ Timescale repo (sqlc + pgx)
├── api/ Fiber handlers
└── cli/ cobra command tree
Data flow per tick
- The scheduler fires a tick for an agent at its configured interval.
- The runtime builds
DecisionInputfrom current market data, exchange positions, wallet balances, and reconciled basis positions. - The runtime calls
Strategy.Decide(ctx, in). - The returned
DecisioncarriesSwaps,Orders, andCancels. - Swaps execute first. The runtime waits for confirmation before any matching
OrderIntentis sent. This preserves the spot-first invariant for delta-neutral strategies. - Orders are placed on the perp venue.
- Pre- and post-trade risk checks run; the killswitch can abort.
- The decision (including the LLM prompt + response if any) is persisted to TimescaleDB along with the resulting on-chain tx hashes / venue order IDs.
- Reconciliation reads venue + chain state and updates basis positions; PnL is recomputed.
Layering rules
- Strategies depend on
pkg/strategyandpkg/types. They MAY importinternal/*packages directly (single-module repo) but doing so couples them to internals that may change without notice. internal/agent.BuildStrategyis a pure registry lookup -- no per-strategy special-casing. Strategies own their own typed config parsing inside theirConstructorand pull framework services fromWarmupInput.Services.internal/storeis the only package that importspgx.internal/walletis the only package that touches private key bytes.