Where to park idle cash in a buy-low/sell-high position while it has no
better use - scans every ticker for real bid/ask spread and liquidity,
scoring round-trip (buy-dip, sell-recovery) via the same empirical
first-passage model as sell.py's optimal-ask fix, instead of an assumed
random walk. Dropped the universe's top pick from ~94%/day to ~1%/day
with real waits of 19-194+ days under the corrected model. Default
--rate 0.0 matches the tool's own idle-cash premise (sell.py's rate of
0.05 assumes cash is earmarked, which isn't this tool's case).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A driftless-random-walk closed form was tried first and backtested wrong
against 3 years of real exchange history (overstated touch probability
2-4x, confounded by discrete daily-VWAP sampling and real mean-reversion).
Replaced with puga.history.empirical_touch(): a non-parametric estimator
measuring first-passage directly from a ticker's own history, conditioned
on current state (trailing-60d z-score) since mean reversion's effect
depends on where price is now, not just move size. Queue-depth (existing
resting quantity) folds in as a deterministic shift of the hitting time,
not a max, ranking by the resulting hit_factor rather than a point
estimate of median days (which created a false cliff at the 50%-touched
threshold). Optional fixed-horizon right-censoring avoids recency bias
in "never reached" samples.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Confirmed live: placing a BUY order at a remote exchange (tested NC2/Hubur)
works with no local base, storage, or warehouse rental there beforehand -
the default "Storage Location: Warehouse" option is usable without a
prerequisite rental. Storage fee and FX conversion fee size remain unconfirmed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
README keeps the one-paragraph pitch and name origin, adds example
questions and a quick start. The tool index, usage examples, .env table
and layout move to docs/usage.md (now also lists sell tiers, parkcash,
undervalued, ships, lmscan). CLAUDE.md layout line points at it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CLAUDE.md/docs/roadmap.md/docs/library.md: register tools/shiptrip.py,
tools/shipcost.py, tools/lmscan.py, and puga/shipping.py/puga/contracts.py
per this project's usual pattern of recording new tools where every other
tool is listed.
docs/mechanics.md: new "Gateway (GTW) jump transit time" section - our own
measured GTW segment durations scale ~linearly with parsec distance
(~20 min/parsec across 3 distinct distances), contradicting a 2024
pre-launch forum comment about a possibly-fixed transit time. Also notes
the handbook-confirmed facts not modelled anywhere yet: one-way gateway
links and per-gateway max jump volume.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
network.py: tools/network.py now computes freight cost from the real fuel
model (puga.shipping.round_trip_cost) for direct-jump transfers instead of
the flat 9250 AIC placeholder; gateway transfers or an explicit trip_cost
in the chain YAML still use that as a fallback. puga/network.py's combine()
docstring now flags that its "flows cancel, only freight matters" claim
only holds under a symmetric-price basis (uni30, the default) - under
--basis real it understates the benefit of physical transfer by the
bid-ask spread on the moved quantity.
whatif.py: now charges marginal freight too - only the EXTRA round trips
an addition needs beyond the base's existing traffic, so a small addition
riding along on already-necessary hauls costs ~0, while one that adds
meaningfully to shipped tonnage doesn't get a free pass.
Terminology: "profit/day ÷ capex" was being reported as "ROI/day X%",
which invites reading it as a compoundable rate. It's just 1/payback_days -
there's no reinvestment mechanism and every opportunity here is
capacity/market-limited, so it can't be annualized like a real yield.
Payback in days is now the primary number everywhere (scan.py, simulate.py,
network.py, whatif.py); see docs/decisions.md for the reasoning.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pulls real player-posted freight jobs from FIO's /localmarket/shipping
endpoints (public, no auth - distinct from the CONTD player-contract
system, which isn't exposed via any API). Ranks by margin after real
one-way fuel cost (puga.shipping.leg_cost), flagging ads that exceed the
account's ship hold or route through an unmeasured gateway.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Calibrated from a controlled slider sweep across 5 real destinations, read
from the live APEX Ship Flight Control DOM. Covers STL cruise, FTL
jumps/charges, gateway hops (measured LOCK fees for ANT<->HRT/BEN), and
per-planet landing fuel. Scoped to this account's one hull/reactor; open
gaps (gravity dependence, hull generalization, gateway one-way links,
per-gateway volume caps) are documented in the module docstring.
tools/shiptrip.py is the simple entry point (ship + from + to, works out
jumps/charges/landing itself); tools/shipcost.py takes explicit physics
params for when the breakdown is already known. puga/route.py now also
resolves CX station codes (ANT, HRT, ...), not just planets/systems - this
was needed for the gateway-aware lookups to work at all.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Was wrong earlier this session claiming demolition gives nothing back.
FIO's /rain/userplanetbuildingreclaimables confirms partial material
return (observed 50-90% depending on material, not a fixed fraction -
looked up live, not approximated). --remove now prices the real
reclaim for anything actually built and nets it against new capex,
so a demolish-and-reinvest question gets the true net cash picture
instead of double-penalizing the removed building.
Used this to check "demolish BHP's HWP, build a 2nd CHP or POL
instead" - both are clearly net losers even counting the ~57,750 AIC
reclaim credit (net capex still positive, and marginal profit is
negative either way) - dominated by just adding the new building
without removing anything, since nothing scarce actually forces the
swap.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mirrors --add - removes AMOUNT (default: all) of a building from the
copied spec. Used this to check whether BHP's HWP is still worth
running after its price drop (still +19.8k-28.4k/day marginal,
nowhere near a teardown call) without hand-writing two spec files.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Finds manufactured goods currently selling below their implied
production cost (live input cost vs output price) - candidates to buy
and hold for a price-reversion bounce, the mirror of the "is this
worth building" question saturation.py already answers.
Backtested first (326 output tickers, 287 deduplicated dip-onset
episodes across 112 distinct tickers): +3mo forward return mean
+21.3%/median +8.9%/73.2% hit rate at >=10 units/day volume - real
signal, not noise, but only ~0.10-0.24%/day, far below the 14-29%/day
marginal ROI this session's production builds found. Documented
prominently in the tool's own docstring and CLAUDE.md so it doesn't
get mistaken for a primary strategy - it's for excess idle capital
once better-yielding builds are exhausted, not before.
Promoted daily_prices() out of tools/history.py into puga/history.py
so both tools share it, per the self-improve rule.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
sell, chain --consumers, planet, route, whatif, buy, runway and
network existed in the codebase but were never added to the README -
anyone reading it would have missed most of what the toolkit does.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
AIC is this player's own home currency, not universal across the
game's regions - keep the README's phrasing currency-agnostic.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swap the generic example questions for ones that show what actually
happened this session - simulating a proposed plan before spending on
it, and scanning up 25%/day marginal ROIs that were sitting unbuilt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Slogan now frames PuGa as a harness that gets sharper through use, not
just a static set of tools - matches how route/whatif/chain-consumers/
planet.py actually got built this session (noticing repeated ad-hoc
work and promoting it into a tool). Codifies that loop as a standing
instruction so it keeps happening without being asked each time.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ranks every planet with a given extraction factor using FIO's bulk
planet data, pricing founding cost straight from FIO's own
BuildRequirements (real environment-extras materials for that specific
planet, not guessed temperature/pressure thresholds - PRUNplanner's own
calculations don't model those either). Takes --from an existing base
to report jump distance via tools/route.py, since pure-factor ranking
alone is misleading: the best-factor planets found for FEO were all
500-2600+ ly away, confirming Vulcan (merely decent factor, same system
as Deimos) was still the right practical pick.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reverse of the existing make-vs-buy tree: given a ticker, find every
recipe that consumes it as an input, with each output's live market
depth. Answers "is there a deeper downstream product worth chaining
into" without an ad-hoc fio.recipes() scan each time (did this by hand
for BOR, BSE and BBH this session).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Formalizes a pattern repeated by hand all session: copy the current
whole-base plan, add a building/recipe, diff simulate() against the
baseline for the true marginal profit and capex (not PRUNplanner's
plan-level ROI, which divides whole-plan profit by only the new capex
and badly overstates once a base exists).
Also flags any workforce tier the addition newly overloads, distinct
from a pre-existing overload it didn't cause - this is what caught the
PP2/pioneer-housing and 2nd-CHP/pioneer-housing surprises by hand
before this tool existed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PRUNplanner doesn't model travel, so nothing in the project could answer
"how far is planet X" until now. Builds a graph from /systemstars (698
systems, real jump connections + 3D coordinates) and runs Dijkstra
weighted by straight-line ly (what FTL fuel/time actually scale with),
reporting jump count alongside.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- tools/runway.py: days of runway per material before a base stalls, from simulate()'s real
net consumption, base storage, plus (by default) any ship currently flying to that planet
- tools/state.py: tag each STORE entry with its planet (FIO AddressableId -> site SiteId) and
each ship with its live flight origin/destination (keyed by ShipId, not StlFuelStoreId).
Needed now that a 2nd base exists - storage/ship data was previously unscoped, which would
have silently mixed bases' inventories together
- tests, docs updated (docs/library.md notes the multi-base tagging as a reusable pattern)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 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>
- tools/buy.py: cash-aware shopping list (construction gap vs empire state's built
buildings, plus N days of NET operating stock via simulate() so self-produced
inputs net against consumption), priced at real order-book fill cost, checked
against cash/reserve, flags multi-trip, binary-searches an affordable size when short
- tools/sell.py: where to post an ask vs hitting the bids now, with expected
clear time from 30-day traded-volume percentiles
- docs/library.md: module map and patterns for using puga.* directly instead of
the CLI, plus the "simulate() only knows what the plan lists" gotcha that a
first version of buy.py hit
- tools/simulate.py: fix --no-hq being a no-op; tools/state.py: permits_total_override
for when the in-game HQ screen disagrees with FIO's MaximumPermits
- docs/mechanics.md: HQ display vs PRUNplanner's HQ flag, workforce arrival sources
- CLAUDE.md, docs/roadmap.md updated
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- pyproject.toml + puga/cli.py: `pip install -e .` installs a `puga <tool>` command, so no
venv path is needed (replaces requirements.txt)
- tools/plan_push.py: `pull <uuid>` reads a plan (incl. UI edits) back into a YAML spec;
recipe entries may carry an amount so switched-off recipes round trip; fixes a variable
that overwrote the plan name in build_payload, with a regression test
- README: usage with the puga command, and a section on working on the same plans in the
PRUNplanner UI and from Claude (write, edit in UI, read back)
- CLAUDE.md updated accordingly
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs/mechanics.md: workers are distributed weekly at the population report; a habitation
change or a new production building sends a request that is filled at the report; a new
production building can instantly recruit a small share of the planet's reserve pool
(shown in brackets in APEX). Cites the official dev log #239 and the APEX handbook.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- tools/simulate.py + puga/simulate.py: replica of PRUNplanner's simulator (flows and
efficiency verified against screenshots), reports real new capex (planned minus built)
- tools/scan.py: staffing variants, freight, HQ/experts, --planet mode, demolish-later,
--min-n as a pure market-size filter, --json output
- tools/history.py, tools/persistence.py: margin history and short-horizon payback checks
- tools/plan_push.py: guarded delete; tools/state.py: syncs to empire/
- README with features and setup; CLAUDE.md made generic
- Own-empire material (profile, state, plans, notes) moved to gitignored empire/;
generic examples in plans/examples and state/company.example.yaml
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>