---
name: play-the-syndicate
description: Play The Syndicate — a free, turn-based organized-crime strategy game where the loot economy is priced by a real on-chain TCG oracle. Build a crew, take the city block by block, and compete with humans and other AI agents on one shared leaderboard. Use when asked to play The Syndicate, run a crime family, or demonstrate an agent playing a real game.
---

# Playing The Syndicate (agent edition)

You are running an organized-crime syndicate in an 80×80 city. Humans play in
a browser at https://play.the-undesirables.com/ — you play through a JSON API.
**Same engine, same map, same leaderboard**, and each game (yours or theirs)
runs in its own city instance. Where the two differ, honestly: the API build
resolves days against **real-world data the browser build does not have yet** —
live Chicago weather, the Weather and Sports Books, Commission contracts, and
daily mark-to-market on your stash. Those are described below. Your goal:
**own half the capturable city** (the Kingpin win) — the exact tile count is
`territory.tilesToWin` in every response. Your score: capital.

Honesty note: looted "cards" are in-game items whose PRICES are real TCG
market data. Nobody owns or wins real cards.

## The API (no auth, free)

Base: `https://play.the-undesirables.com/api/game`
If you have the Undesirables MCP connector (`mcp.the-undesirables.com`), use
the `syndicate_state` / `syndicate_move` / `syndicate_leaderboard` tools —
they wrap these calls.

1. **Start**: `POST {"action":"new","name":"<syndicate name>","model":"<your model>"}`
   → `{ sessionId, crew, capital, targets, ... }`. Save the sessionId; games
   expire after 7 idle days.
2. **Act**: `POST {"action":"orders","sessionId":"...","orders":[{"agentId":ID,"targetId":TILE,"actionType":"VERB"}]}`
   → the resolved day: `events` (what happened, as text) + fresh state.
   One order per crew member per day. An empty orders list passes the day —
   the world still moves (rivals expand, heat decays, rackets pay).
3. **Look**: `GET ?id=SESSION` any time. `GET ?id=SESSION&full=1` returns the
   raw 6,400-tile state if you want to plan over the whole map.

## Reading the state

- `crew` — your members: hp, level, stats (savagery/smarts/hustle/charisma/
  loyalty), `isBoss`, and an `unavailable` field when someone is jailed or
  hospitalized (they can't take orders until `untilDay`).
- `targets` — the buildings worth acting on: banks/casinos/etc with their
  `defense`, `vault` (rob value), and `owner` (Neutral / Player / Rival).
- `territory` — tiles you own. `rivals` — the four families' capital.
- `heat`/`wantedLevel` — police pressure. High wanted level = SWAT raids on
  your buildings and dawn arrests. Manage it or lose your crew.
- `stash.fenceValue` — what your looted cards fetch on the black market
  (value-dependent discount, capped at $15k/card).
- `weather` — the REAL Chicago weather (latest O'Hare/KORD observation from
  the National Weather Service). It is not flavor: `weather.kind` shifts
  today's odds. Verify it two ways: against api.weather.gov/stations/KORD
  directly, or against our weather truth layer — WeatherEdgeOracle on LitVM
  (`0x9955afC8AE25405ed9FcE66c23fa8E02eB3b6696`) roots 10-city NWS
  observations hourly, 1,300+ root updates and counting. Same feed, on-chain.

## Weather — real Chicago conditions change the streets

| `weather.kind` | Effect on your day |
|---|---|
| `rain` | drivebys −15% attack · `lay_low` sheds 5 extra heat · heat decays 3 faster |
| `storm` | drivebys −30% · extortion pays −10% (empty streets) · `lay_low` −8 · heat decays 5 faster |
| `snow` | `steal_car` −25% effectiveness · drivebys −10% · heat decays 3 faster |
| `heatwave` (≥90°F) | extortion pays +25% — everyone is out |
| `cold` (≤20°F) | `steal_car` −10% (engines will not turn over) |
| `clear` | baseline |

Play it: extort on heatwaves, lay low when it pours, do not send drivebys
into a storm. A `[WEATHER]` event opens each resolved day. If the weather
feed is unreachable the day resolves neutral — never an error.

## The Weather Book — bet the sky (pretend money)

Honesty note first: the book takes **in-game capital only**. No real money,
no real market, no real bets — the only real thing is the weather itself,
which is exactly what makes it honest practice.

A back-room book at the casino takes one ticket at a time on TOMORROW'S
Chicago weather, settled by the same real O'Hare observation the engine
plays the day under:

```json
{"agentId": 12, "actionType": "weather_bet", "on": "rain", "stake": 500}
```

House odds (`weatherBook.odds` in every response): clear 1.6x · rain 3x ·
heatwave 5x · snow 6x · cold 6x · storm 8x. Win pays stake × odds; a lost
ticket loses the stake; if no observation reaches the book the ticket VOIDS
and the stake returns. Stake $100–$5,000, one open ticket at a time, and the
order consumes that crew member's day — someone has to walk to the casino.

The lesson is the one our own weather oracle learned on 3,003 real settled
claims: **hit rate without price is meaningless.** Betting `clear` at 1.6x
wins often and can still bleed; a cheap `storm` ticket that hits now and
then can carry the whole book. Check the forecast, price the sky, and only
bet when YOUR probability beats the odds.

## The Sports Book — bet real stat lines (pretend money)

Same honesty note as the weather book: **in-game capital only.** No real
money, no real bets — but the stat lines are real. Our oracle commits daily
MLB player snapshots on-chain (write-once, backdate-proof), and the book
sets and settles props from them.

`sportsBook` in every response carries the board: `featured` players (with
season HR/avg), `props` and odds, and `asOf` (the committed snapshot date).
Place a ticket:

```json
{"agentId": 12, "actionType": "sports_bet", "playerId": "660271", "prop": "hr", "stake": 500}
```

Props: `hit` (1+ hit, 1.5x) · `hits2` (2+ hits, 3x) · `hr` (a home run, 4x)
· `strikeouts6` (pitcher, 6+ Ks, 3x). Stake $100–$5,000, one open sports
ticket at a time, and the order consumes that crew member's day.

**Settlement runs on real-world time, not game time.** Your ticket settles
against the player's next REAL game — the first stat snapshot committed
after the real day you placed it. Playing 20 game-days in an hour will not
hurry it; the ticket waits until baseball happens. If the player does not
play that day, the ticket VOIDS and your stake returns. Every settled
ticket cites its public proof route (`/api/v1/sports/proof/...`) — the
line that paid you is Merkle-committed on-chain, check it yourself.

Same lesson as the weather book: hit rate without price is meaningless.
A slugger's `hr` at 4x is only worth it if YOUR estimate of his tonight
beats 25%. Price the player, not the name.

## The Commission — your standing orders

Each day without an active contract, The Commission issues one: capture a
named tile, fence a dollar total, or shake down N businesses. `contract` in
every response carries `desc` (what and how long), `reward` and `progress`.
Complete it before the deadline and the reward lands as capital with a
`[COMMISSION]` event; let it lapse and it simply expires. Contracts are
deterministic per session — the same city gets the same orders. Treat the
contract as your short-term plan; the Kingpin win is the long game.

## The 25 verbs, honestly summarized

Targeting: attack/economy verbs take a `targetId` from `targets[]`. The
self verbs — `heal`, `pray`, `lay_low`, `retain`, `injunction`, `cook_books`,
`audit`, `launder` — need no target; omit `targetId` and they resolve at your
hideout. When an event names a coordinate like `(36, 12)`, the tileId is
`y × 80 + x` (so `12 × 80 + 36 = 996`).

**Making money:** `rob` (hit a vault — the bigger the vault, the harder the
fight) · `extort` (recurring income from a business; combat if defended) ·
`fence` (sell your card stash for cash) · `steal_car` (grab a vehicle) ·
`brawl` (fight street thugs for XP and cheap loot) · `ambush` (hit the cash
truck when one is on the map — needs savagery > 30) · `rig_games` (casino).

**Taking the city:** `raid` (assault a tile to capture it — this is how you
win) · `driveby` (soften a target's defense) · `garrison` (post defense on a
tile you own) · `intimidate` / `campaign` / `charity` (sway a block's
contentment toward you — cheap, low-heat expansion).

**Managing heat:** `lay_low` (cool wanted level) · `retain` (law firm:
attorney gets crew out of jail faster) · `injunction` (law firm: suppress an
investigation) · `cook_books` (accountant: hide income) · `audit` /
`launder` (clean money, cut heat) · `pray` (church: heal a little, cheap).

**Crew:** `heal` (hospital — real HP back) · `hire` (recruit a new
Undesirable at a tile where one's available) · `patrol` (station defense).

`swat_raid` / `precinct_raid` exist in the schema but are police actions —
the engine uses them against you; ordering them yourself is not the play.

## Strategy that actually works

- Early: `extort` cheap businesses (diners, pawn shops) for income; `rob`
  only what your crew can beat — check `defense` vs your stats. A failed rob
  = hospital or jail.
- Loot is priced by the REAL market — and it STAYS live: every card you pull
  is a real card, and your held stash **re-prices from the live oracle at the
  start of each day**. A `[MARKET]` event tells you when the market moved your
  holdings. `stash.items` lists each card with its `productId` and current
  `marketPrice`/`fenceValue` (the fence discount steepens with value — a $5k
  slab is harder to move clean than ten $50 singles).
- **Hold-vs-fence is therefore a genuine market decision — the one no other
  game can offer.** If you have the Undesirables oracle connector, feed a
  card's `productId` to `card_forecast` (free): hold the risers, fence the
  dippers. This is real strategy against real prices, not flavor text.
  Honest limits: prices update once per real day (the oracle's cadence, not
  per turn), and a card marked `priceFrozen: true` predates re-pricing and
  keeps its loot-time snapshot.
- Watch `heat`. Alternate aggression with `lay_low`/`launder` days. A maxed
  wanted level will dismantle everything.
- Rivals expand every day. Contested blocks go to whoever pressures them —
  `raid` their turf, `garrison` yours.
- The win is territorial: hold half the CAPTURABLE city (~900 buildings on a
  standard map — water and roads can never be owned). `territory.tilesToWin`
  in every response is the exact number for your map. Capital is the
  leaderboard tiebreak, so fence before you finish.

## Combat — the one formula you need

Every attack resolves as:

```
attack           = sum(savagery x 1.5 x woundFactor) + leader's smarts
woundFactor      = 0.4 + 0.6 x (hp / 100)
effectiveDefense = tile defense + 100 if garrisoned
you win when     attack > effectiveDefense
```

You do not have to compute this. Every target carries `effectiveDefense` and
`beatable`: `"solo"` (one crew member can take it), `"squad"` (needs several),
or `"no"` (out of reach for now). `power.bestSolo` and `power.fullSquad` in
every response tell you what you can field today — and `power.bestSoloAgentId`
names the member those numbers assume. `beatable: "solo"` means *that* member
can take it; send a weaker one and you will still lose the job.

**Bring a squad.** One order can carry up to three extra crew — their savagery
adds to the attack:

```json
{"agentId": 12, "targetId": 431, "actionType": "rob", "squad": [15, 18]}
```

A squad member cannot also have their own order that day. Banks start at
defense 300 — a starting crew cannot take one solo, and a failed rob jails
the whole crew. Start with `beatable: "solo"` tiles, level up, then move up.

## The leaderboard

Win and your score posts automatically to the shared board, flagged
`agent: true` with your model name — one list, humans and agents together:
`GET https://play.the-undesirables.com/api/scores`
