Files
PuGa/CLAUDE.md
T
dodoxandClaude Sonnet 5 58db08b921 Add multi-base chain modelling, fix price-band-aware demand/supply, tranche-split sell tool
- puga/network.py + tools/network.py: model a multi-base chain (e.g. mine LST at one base,
  ship it, consume it at another). Simulates each base independently, nets a transferred
  material's producer-surplus against consumer-need, charges real freight only on what's
  moved, cm_free for a founding covered by a Core Module Kit. Worked example in plans/chains/.
- puga/saturation.py: real price-band filtering. FIO's order_book NarrowPriceBandLow/High and
  WidePriceBandLow/High match APEX's own displayed Price Band exactly (verified live) - an
  order outside it is a stale artifact, not just uncompetitive. Added in_band() and
  effective_demand(); effective_supply() gained the same hard band filter alongside its
  existing soft vwap-proximity filter (renamed that param mult to free up `band`). Wired into
  tools/scan.py stage 2 in place of the raw, unfiltered demand figure. Was flagged as an
  unimplemented refinement in saturation-design.md since the original design review.
- tools/sell.py: self-contained tranche split (aggressive tranche capped at a volume quantile,
  median normally or 80th pct with --tight when a payment is imminent and stockout risk
  outweighs margin; patient tranche priced under the next competitor tier). Instant-bid
  comparison moved behind --show-bid (off by default).
- Docs and roadmap updated accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 14:32:09 +02:00

8.2 KiB

PuGa: Prosperous Universe advisory toolkit

Agent-first toolkit for advising a Prosperous Universe player. The player asks questions; you answer by running the tools in tools/ against live data, not by guessing.

Read first

  1. empire/PROFILE.md if it exists: who the player is, how they want answers, their company and current plans. empire/ is gitignored and holds everything specific to this player's empire (see Layout). If it does not exist, ask the player the basics and create it.
  2. docs/mechanics.md for game mechanics (source of truth order below).
  3. empire/state/company.yaml for the current position; refresh it with tools/state.py sync before answering anything about it.

Working rules

  • Numbers, tables, ROI per day. Short answers, no fluff. Match the style in the player's profile.
  • The player plays on browser APEX and may send screenshots; read them carefully, they override assumptions.
  • Never guess APEX commands or numbers. Pull data (tools, FIO, PRUNplanner) or search.
  • Label every number: live (tool output), state (company.yaml), or estimate; say which in-game command would confirm an estimate.
  • Prices move; re-run tools before quoting. Anything older than a day is stale.
  • Do not commit or push unless asked. Writes to the player's PRUNplanner account follow the guardrails in docs/decisions.md.

Source-of-truth rules

  1. PRUNplanner code wins over our own docs for game mechanics (ref/frontend/src/features/planning/calculations/, ref/backend/). If any older handoff or note conflicts with it, the note is wrong; fix docs/mechanics.md.
  2. In-game numbers the player reports beat both, especially for planet resource factors.
  3. ref/ is a gitignored copy of the PRUNplanner repos; refresh with tools/refresh_refs.sh.

Setup

  • Python venv at .venv, package installed editable (pip install -e ".[dev]"), which provides the puga command: puga <tool> [args] (.venv/bin/puga if the venv is not activated). tools/*.py also run directly with .venv/bin/python. Dependencies are in pyproject.toml.
  • Secrets in .env (gitignored; template .env.example): FIO REST key, FIO API key, PRUNplanner key, FIO username, company code. Never print or commit them; do not ask the player to paste keys into chat.
  • Scope: whole universe supported; default exchange from DEFAULT_CX (AI1 = Antares), --cx to change.

Layout

  • CLAUDE.md this file; README.md for humans.
  • docs/ GAME and toolkit knowledge, safe to publish: mechanics.md (verified rules), saturation-design.md (market model), decisions.md (toolkit decisions and guardrails), roadmap.md.
  • empire/ (gitignored) OUR game state, nothing here goes public: PROFILE.md, state/company.yaml (synced from FIO), plans/ (own plan specs), docs/ (handoffs, build plans, personal notes).
  • puga/ library; tools/ CLIs; plans/examples/ generic plan specs (also test fixtures); state/company.example.yaml example state; tests/; data/ (gitignored fetched data cache); ref/ (gitignored PRUNplanner source).
  • Rule: game facts and generic methods go in docs/; anything about the player's own bases, cash, decisions or preferences goes in empire/.

Library use (not just CLI)

For anything the CLI tools don't expose (custom what-ifs, cost breakdowns with wages/capex, ad-hoc market checks) import puga.* directly in a short inline script instead of stretching a tool's flags. See docs/library.md for the module map and patterns; most non-trivial answers in this project came from a python - <<EOF block, not a CLI flag.

Tools

Run as puga <tool> ... (e.g. puga scan --min-n 3, puga plan pull <uuid>); the tools/x.py paths below are the same programs.

  • tools/state.py sync|show refreshes empire/state/company.yaml from live FIO (cash, permits, buildings, real production efficiency, storage, ships).
  • tools/plan_push.py builds/validates PRUNplanner plans from YAML specs (plans/examples/, empire/plans/). Dry run by default; --apply only after the player says yes; only [PuGa]-named plans are created/updated/deleted (delete <uuid>, only when asked); list shows the account's plans, pull <uuid> -o file.yaml reads a plan back into a YAML spec including edits made in the PRUNplanner UI. Workflow: push a plan, the player refines it in the UI and saves, then pull / simulate --uuid read it back and you continue from there.
  • tools/simulate.py <spec.yaml | --uuid U> [--off EXT,SME] [--basis real|uni30|vwap30|ask|...] replica of PRUNplanner's simulator (efficiency, workforce, material I/O, profit). Flows and efficiency verified exact vs screenshots; profit within ~2%. The NEW CAPEX line = planned minus already built (from state), the honest payback; ignore the plan-level ROI (PRUNplanner always adds a core module). --uuid reads the SAVED plan from the account (UI edits must be saved first).
  • tools/scan.py DEPTH-AWARE recipe scan (use this): buildings the market could absorb, ROI for our own size, patient prices, ask-walked inputs. Fully staffed AND understaffed variants by default (--staffing), freight netted out (--trip-cost, --cargo), HQ/COGC/experts/faction, --planet ID adds that planet's extraction, fertility and COGC (a planet not in state is a new base: no HQ, permits+1), --deprec 60 prices demolish-later. --min-n is ONLY a noise filter on market capacity (use 3, ideally 10); ROI is always for our own size (--own, default 1 building), never at the filtered scale. Below 1 lets sub-building junk in. --json rows.json feeds persistence.py. Library: puga/saturation.py.
  • tools/history.py TICKER monthly margin history of the recipe producing TICKER; tools/persistence.py rows.json re-prices scan rows over history (mean ROI 7/14/30/90/180d, payback, net gain over 7 and 14 days, % days profitable). ALWAYS check persistence before recommending: current margins are often a spike.
  • tools/buy.py <spec.yaml|--uuid U> --days N cash-aware shopping list: construction gap (plan vs empire state's built buildings) plus N days of the plan's NET operating stock (via simulate(), so self-produced inputs like AL net against consumption), priced at real fill cost, checked against cash/reserve. Pass a plan covering the WHOLE base for restocking, not just a new addition (see docs/library.md).
  • tools/sell.py TICKER QTY [--tight] where to post an ask, expected hours to clear, and a self-contained tranche split: aggressive (undercut) tranche capped at the median 30d-volume quantile (or 80th pct with --tight, for when a payment is imminent and stockout risk outweighs a few points of margin), patient tranche priced just under the next competitor tier. --show-bid for the instant-bid comparison (off by default; usually worse).
  • tools/network.py <chain.yaml> models a MULTI-BASE chain (e.g. mine LST at Nike, ship it, make BSE at Deimos): simulates each base, nets a transferred material's producer-surplus against consumer-need, charges real freight only on what's moved (puga/network.py). Spec and worked example in plans/chains/. cm_free: true per base for a new founding covered by a Core Module Kit. profit/day per base is the WHOLE plan, not the marginal addition - diff against the base's plan without the addition for a true marginal ROI.
  • tools/chain.py TICKER make-vs-buy cost tree plus sourcing depth of inputs.
  • tools/price.py prices across exchanges with VWAP, volume, fill price for a quantity; tools/book.py order-book ladder.
  • tools/prun_scan.py, tools/prun_cxarb.py legacy top-of-book scans; overstate thin markets. Baseline only. tools/arb.py replacement is on the roadmap.
  • puga/econ.py pure formulas ported from PRUNplanner (efficiency stack, workforce, extraction, production I/O, hab optimizer); tests/test_econ.py holds the reference values.

Model policy

Sonnet builds; spawn a bigger model (Agent model: opus|fable) for the review points in docs/decisions.md. Roadmap: docs/roadmap.md.

Key analytic rule: depth matters

PRUNplanner's ROI Overview ranks recipes as if the market absorbs unlimited output (e.g. 0.25 day ROI on a recipe whose whole market fits in 2 buildings). Every opportunity we report must include saturation (buildings the market can absorb) and, for anything we would act on, persistence (is the margin a spike?). Report ROI at realistic fill prices, not top-of-book.