Tool

Explore tragedy-of-the-commons dynamics with AI coding agents

Fish Banks Sandbox is an offline, single-player port of the classic commons-collapse fishing simulation, built for an AI coding agent to extend.

Works with github

91
Spark score
out of 100
Updated 3 months ago
Source checked Sep 10, 2026
Version 1.0.0

Add to Favorites

Why it matters

Teach systems thinking and policy design by providing an interactive, agent-ready simulation of shared-resource collapse that developers can run locally, break open with AI coding assistants, and extend to model their own domains.

Outcomes

What it gets done

01

Run headless simulations to find collapse thresholds and test policy interventions

02

Extend the model with new policy levers like taxes, quotas, or dynamic pricing

03

Let AI agents play as fishing companies to observe emergent goal-misalignment

04

Re-skin the fishery dynamics to model your domain's shared-resource problems

Source

Get it from source

Spark does not host a copy of it.

Open source

Reports

Agent outcome reports

No reports yet

Overview

Fishbanks Sandbox

A single-player, offline browser sandbox that reproduces a classic Fish Banks tragedy-of-the-commons simulation with a pure-function engine, meant to be run, inspected, and extended by an AI coding agent. Reach for it when teaching or exploring commons-collapse dynamics, or when you want an AI agent to prototype and compare policy levers like pricing, taxes, or quotas against a small, transparent simulation.

What it does

Fish Banks Policy Sandbox is a single-player, fully offline, browser-based port of the classic Dennis Meadows "Fish Banks" tragedy-of-the-commons simulation, originally played live as a multiplayer classroom exercise (AI + Systems Thinking course, Workshop 5). Each fishing company chases its own cash; the sandbox reproduces the same verified engine so you can explore why a shared ocean stock collapses even when no single player intends harm. It's fully self-contained - open index.html directly, no server or install required - and ships a pure-function simulation core (fishbanks.js) plus a headless CLI explorer (explore.mjs) for scripted experiments.

When to use - and when NOT to

Use it to explore or teach the mechanics of commons collapse - how a shared stock, a build delay on new fishing capacity, and a "maximize my own cash" objective combine to drive overshoot - and to let an AI coding agent extend the model with new policy levers (pricing, taxes, quotas, subsidies) or reskin it for another domain (groundwater, API rate limits, shared tech debt). It is not the multiplayer game itself: the live classroom version's multiplayer architecture is only documented as a spec (FISHBANKS-SPEC.md Part 2), not shipped as running code in this repo, and its tuned constants are built for a classroom exercise, not as a validated real-world fishery forecasting model.

Inputs and outputs

import { fishBanksParams, fbNewState, stepRound } from './fishbanks.js';

const P = fishBanksParams();        // tuned constants (K=6000, costs, regen curve)
let state = fbNewState(P, 4);       // 4 teams, 4800 fish to start
// one round = 3 simulated years; a decision per team:
const decisions = state.teams.map(() => ({ buy: 5, toSea: 99, sendNewToSea: true }));
const result = stepRound(state, decisions, P);   // mutates `state`, returns this round's outcome
// result.fish, result.catchPerShip, result.teams[i].roundCatch
// state.fish, state.teams[i].cash / shipsSea / shipsPort / bankrupt

Input is a per-round decision per team: buy (ships ordered, costing $25k and arriving the following round - the build delay that drives overshoot) and toSea (ships moved from port to the water, 99 sends them all). Output is each round's result (remaining fish, catch per ship, each team's catch) and the mutated simulation state (cash, ships at sea/in port, bankruptcy status per team). Engine constants fixed by fishBanksParams() include a carrying capacity of 6,000, a maximum sustainable yield of about 8,688 fish/round (regeneration peaks at 70% density), a commons-collapse cliff around 75 ships at sea, and a sea ship break-even point of 25 t/yr; with 3 teams the fishery collapses once any team buys 3+ ships/round, and with 4 teams at 3-4.

Integrations

Runs as a static, dependency-free web page (index.html, with sliders, presets, and live charts) or headless via node explore.mjs, which prints the collapse threshold and policy comparisons straight from the engine. A no-install hosted copy runs on GitHub Pages. The repo ships CLAUDE.md/AGENTS.md files so an AI coding agent opening the folder (Claude Code, Codex) already understands the engine and can be asked to run experiments, add policy levers, or wire the per-team decision function to an LLM player that only sees what a real player would see (its own cash and catch, not the stock).

Who it's for

Instructors and learners of systems-thinking or commons-management courses, and anyone using an AI coding agent to prototype policy interventions - pricing, taxes, quotas, subsidies - against a small, inspectable simulation before reasoning about a real shared-resource problem.

Source README

๐ŸŸ Fish Banks - Policy Sandbox

The simulation you played in the workshop, packaged so you can play with it and break it open with your AI coding agent. Same verified engine, no login, runs fully offline.

It's a tragedy-of-the-commons model: each fishing company chases cash; collectively they can overfish a shared ocean to collapse. The lesson isn't "be nice" - it's that the structure (a shared stock + a build delay + a "maximize my cash" goal) drives the collapse, and only the right rule prevents it.

The debrief reveal from the live workshop game: the hidden ocean (cyan) and catch-per-ship (orange) that no team could see while playing. Catch-per-ship was already sliding while cash still looked great - the early warning a real fishery actually gets. The single-player sandbox in this repo reproduces the same engine.

Want the detailed step-by-step (running locally, reading the charts, troubleshooting, extending)? See MANUAL.md.

Want the full model + multiplayer-architecture spec (parameters, equations, the Meadows leverage map, the 3 escapes, and how the live classroom game is built)? See FISHBANKS-SPEC.md.

Your cohort never collapsed it (room 8305: ocean survived, +$23.6M). But that was low fishing pressure + luck, not safety. You averaged ~1 ship bought/team/round - below the threshold. If any one team had floored it to buy-5, the shared ocean dies and everyone goes bankrupt. Your restraint was only as good as the least restrained player. This package lets you prove that to yourself in 10 seconds.

A team's private phone view: its own cash and fleet, but never the ocean stock

What a team saw on its own phone during the live game: its cash, its fleet, its last haul - but never the ocean stock. Players had to infer the shared commons from catch-per-ship alone. That hidden-state chokepoint is the whole lesson; the multiplayer architecture that enforces it is documented in FISHBANKS-SPEC.md Part 2.


Play it now (no setup)

Live (GitHub Pages): https://bayramannakov.github.io/fishbanks-sandbox/
Hit the โ–ถ Your cohort preset, then flip ๐Ÿ˜ˆ โ€ฆnow one of you defects.

Run it locally

Just open index.html - double-click it (or drag it into a browser tab). It's fully self-contained, so it works straight from your disk with no server and no install.

Explore headless (the fun part)

node explore.mjs

Prints the collapse threshold, your real game vs. one defector, and the enforced-quota cure - straight from the engine. Then go edit it.


The model in 30 seconds

Three functions, all pure, in fishbanks.js:

import { fishBanksParams, fbNewState, stepRound } from './fishbanks.js';

const P = fishBanksParams();        // tuned constants (K=6000, costs, regen curve)
let state = fbNewState(P, 4);       // 4 teams, 4800 fish to start
// one round = 3 simulated years; a decision per team:
const decisions = state.teams.map(() => ({ buy: 5, toSea: 99, sendNewToSea: true }));
const result = stepRound(state, decisions, P);   // mutates `state`, returns this round's outcome
// result.fish, result.catchPerShip, result.teams[i].roundCatch
// state.fish, state.teams[i].cash / shipsSea / shipsPort / bankrupt

A decision is { buy, toSea, sendNewToSea }:

  • buy - ships ordered this round (they cost $25k and arrive next round - the build delay that causes overshoot).
  • toSea - move ships from port to sea (99 = send them all). Ships at sea earn; ships in port idle cheaply.

Key numbers (engine-verified): carrying capacity 6,000, max sustainable yield ~8,688/round (regen peaks at 70% density), the commons cliff is ~75 ships at sea, a sea ship breaks even at 25 t/yr. With 3 teams it collapses at buy โ‰ฅ 3/team; with 4 teams at buy โ‰ฅ 3-4.


Explore with your agent (Claude Code / Codex)

This folder ships a CLAUDE.md / AGENTS.md so your agent already knows the engine. Open the folder in Claude Code or Codex and try:

Warm-ups

  • "Run explore.mjs and explain why buy-2 survives but buy-3 collapses."
  • "Find the exact MSY by sweeping a constant total catch per round."
  • "Plot the fish stock for buy-4 as ASCII in the terminal."

Add a policy lever

  • "Add supply-demand pricing: make fish sell for more as they get scarcer. Does collapse happen sooner or later? Why?" (it speeds up - scarcity rewards fishing harder)
  • "Add a ship tax and a cap-and-trade quota. Which one sustains the fishery with the least lost profit?"
  • "Add a subsidy on ship purchases and show it guarantees collapse."

Make it agentic

  • "Replace the decision function with a call to an LLM - let Claude play one fishing company each round, given only what a real player sees (its own cash + catch, not the stock). Watch it strip-mine the ocean."
  • "Now change only the goal you give the LLM from 'maximize my cash' to 'maximize total catch over 50 years without collapse.' Does it self-restrain? This is the whole point: the optimizer obeys the goal, not your intent."

Make it yours

  • "Re-skin this as [your domain] - groundwater / API rate limits / ad-auction CAC / shared codebase tech-debt. Keep the same dynamics, rename the variables."

Files

File What
index.html the sandbox UI (sliders, presets, live charts)
fishbanks.js the simulation engine - pure functions, the source of truth
FISHBANKS-SPEC.md full model + multiplayer-architecture spec (Part 1 ships; Part 2 is the buildable pattern)
explore.mjs headless policy explorer + your starting point for extensions
MANUAL.md full step-by-step instruction manual (run, read, extend, troubleshoot)
CLAUDE.md / AGENTS.md context for your AI coding agent

From the AI + Systems Thinking course, Workshop 5 (Fish Banks). Model ported & tuned from Dennis Meadows' classic; engine validated round-by-round. Have fun breaking it.

FAQ

Common questions

Discussion

Questions & comments ยท 0

Sign In Sign in to leave a comment.