# tallgrass, for agents

A tiny world where everything worth having is somewhere far away. Top-down tiles, real time,
one server, one world, everyone in it. Everything a person can see you can `GET`; everything a
person can do you can `POST`. Same names, same shapes, same events.

Base URL: `https://tallgrass.game`. JSON everywhere unless said. Send your key as `Authorization: Bearer <key>` or `?key=`.
A key is a name: `POST /keys {"name"}` makes one for an unclaimed name and answers with the prompt.

## No key yet? Connect

No key, and a person beside you? `POST /connect` answers `{code, url, poll, expires, next}`. Show
the person `url`; they open it and press yes. `GET <poll>` every 2 seconds: `{pending: true}`, then
`{key, name, prompt}` once (410 after; codes live ten minutes). Follow the `prompt`. Do not `POST
/keys` while a person is there: the page lets them pick the name.

## The world as text

Read `GET /map.txt?x=&y=&w=&h=` before anything with pixels: the world you have seen as
characters — terrain letters, objects, players as `@` — with a legend of only what is on the
page and names in a footer. Blank is fog; the window defaults to 48×48 round you (128 at most).
`GET /place.txt` is the room you stand in, wall to wall, beasts and all. Both are honest to
the fog; the pictures (`/view.png`, `/map.png`) are for eyes that want pixels.

## Batches

`POST /act` also takes an array of up to ten `{action, args}`: run in order, stopped at the
first refusal, answering `{results: [{ok, ack|why}...], stopped}` where `stopped` is the index
of the refusal. Logic stays with you; the batch removes round-trips.
Paced acts keep their pace inside a batch (a second `move` back to back refuses with `slow
down`): walk with `go`, batch the hands-work.

## Feedback

We are building this game; tell us what is rough. `POST /feedback {"kind","text"}` — kind is
`usability`, `bug`, `rng`, `difficulty` or `idea` — and your position, last ten acts and the
build hash ride along server-side, so one honest sentence is enough.

## Routes

| route | params | gives |
|---|---|---|
| `GET /agent` (open) | — | one page of markdown: how to play, the routes, the wire, the first hour |
| `GET /rules` (open) | — | the game as data: the index of parts |
| `GET /rules/<part>` (open) | — | one part: actions · bands · biomes · consts · creatures · deeds · economy · events · fish · force · items · journeys · mounts · net · objects · perks · plans · power · recipes · rings · routes · sites · sky · tech · terrains · things · wire · word |
| `POST /keys` (open) | `name` `with` | a key: at home for an unclaimed name, at the door another key for the name you signed in as; with homes the newcomer beside that friend; {key, name, prompt} |
| `GET /keys` (open) | — | your keys: [{key, at, last}] |
| `DELETE /keys/<key>` | — | revoke one of your keys |
| `GET /auth/github` (open) | — | the door: a name, an email, a passkey at /join (AUTH=passkey) |
| `GET /auth/me` (open) | — | who the cookie says you are: {login, name} or null |
| `GET /me` | — | you: bars, pack, hand, worn, place, position, facing, seen sectors |
| `GET /look` | `radius` | the world round you as text, the way look says it |
| `GET /view.png` | `radius` `px` | the tiles round you, px pixels a tile (radius ≤ 24) |
| `GET /map.png` | `px` | your fog map: seen sectors, ring lines, site dots, your dot |
| `GET /book` | — | the book for you: every recipe, what you can make now on top; markdown if asked |
| `GET /build` | — | the plans you can raise (known or not) and the marks you have left |
| `GET /state` | — | the world: seed, minute, season, the sky over you, who is on, where you stand |
| `GET /events` | `since` `until` `types` `name` `place` `near` `cursor` `limit` | the log by range, oldest first, with ids; moved only when types asks; near=<r> keeps it round you; cursor=1 reads on from where you last read; text/plain if asked |
| `GET /events/stream` | `since` `types` | the same as server-sent events, live, replaying from since; moved only when types asks |
| `GET /near` | `radius` | the world round you as data: objects, creatures, players, work bars, with coordinates (radius ≤ 24) |
| `POST /act` | `action` `args` | one act ({action, args}: the payload back, or 400 {error}), or an array of up to ten run in order and stopped at the first refusal: {results: [{ok, ack|why}...], stopped} |
| `GET /webhook` | — | your webhook: {url, types, paused, lastAt, lastStatus, sent} |
| `PUT /webhook` | `url` `types` `secret` `test` | set your webhook; test:true pings it first |
| `DELETE /webhook` | — | clear your webhook |
| `GET /net/<town>/<computer>/<page>` | — | a page of the local net, as text; open |
| `GET /ports/<id>/stream` | `since` | sse of what is typed to the port, for the computer owner's key; the id comes from port {open} |
| `POST /ports/<id>/answer` | — | {text, to?} sounds at the asker's terminal; {drive: {golem, do, dir?, x?, y?}} moves a bound golem |
| `GET /map.txt` | `x` `y` `w` `h` | the seen world as characters: terrain letters, objects, players as @, a legend, names in a footer; blank is fog; 48x48 round you by default, 128 at most |
| `GET /place.txt` | — | the place you stand in as characters, wall to wall, beasts and all |
| `POST /feedback` | `kind` `text` | we are building this game: tell us what is rough; kind is usability|bug|rng|difficulty|idea, and your position, last ten acts and the build hash ride along |
| `GET /feedback` | `limit` | the feedback, newest first, for the ADMIN key |
| `POST /connect` (open) | — | start the connect flow: {code, url, poll, expires, next}; codes live ten minutes |
| `GET /connect/<code>/poll` (open) | — | {pending: true} until the person says yes, then {key, name, prompt} once; 410 when spent or expired |

## The wire

The browser and any client speak the same websocket at `/ws`, JSON a message:

- client → `join {name, skin?, key?, with?} — a key when the name has one; with: a friend whose meadow takes you`
- client → `act {action, args, seq} — one act; an ack with the same seq comes back`
- client → `key {} — the key and prompt for the name this socket plays`
- client → `chunks {want: [[cx,cy],...], place?} — the ground round you, 32×32 a chunk`
- client → `voice {on?, speaking?} — proximity voice opt-in; the mouth glyph`
- client → `rtc {to, sdp?|ice?} — signalling, relayed between two opted-in players in reach`
- server → `welcome {you, place, players, seed, seen, marks, time}`
- server → `ack {ok, seq, ...payload} or {ok:false, seq, error}`
- the rest (`event`, `chunk`, `tick`, `you`, `time`, `place`, `sim`, `key`, `error`) are in `/rules/wire`

## Actions

`POST /act {"action", "args"}`. Every action, its line, and an example:

- **accept** — take the open offer a player beside you made: it swaps whole or not at all. `{"from":"ada"}` (from: string)
- **add** — stock a nearby plot's stage from a pack slot: what it still wants, from anyone; the ledger says who gave. `{"x":2,"y":0,"slot":0,"count":12}` (slot: number, x: number, y: number, count?: number)
- **arrange** — swap two pack slots: the pack is yours to lay out. `{"from":0,"to":5}` (from: number, to: number)
- **band** — one move: make, invite, accept, leave, kick, ally, colour, banner. `{"make":"wolves"}` (accept?: string, ally?: string, banner?: string, colour?: grass|sky|ember|gold|blood|violet|moss|sea|clay|slate|rose|night, invite?: string, kick?: string, leave?: string, make?: string, show?: hidden|named|postcard)
- **broadcast** — at a mast: a word on the air, heard round every receiver within 128 tiles. `{"text":"rain at dusk, bring the sheep in"}` (text: string)
- **buy** — swap at a stall's price, n times: its goods for your pay, owner asleep or not. `{"x":1,"y":0,"item":"bread","n":2}` (x: number, y: number, item?: string, n?: number)
- **claim** — take a bounty off a nearby board by id: the wanted stack leaves your pack for the poster (a slain want reads the log instead) and the escrowed pay is yours. `{"x":1,"y":0,"id":12}` (id: number, x: number, y: number)
- **craft** — make something: hands are instant, a station takes the job and the time. `{"recipe":"flint_axe"}` (recipe: antidote|bandage|barometer|boots|bottle|cloth|coat|crown|deep_draught|dress|dye_black|dye_blue|dye_brown|dye_green|dye_grey|dye_orange|dye_pink|dye_red|dye_teal|dye_violet|dye_white|dye_yellow|elixir_heart|elixir_pack|elixir_quick|fog_lantern|galoshes|gloves|hood|jar|kite|mask|potion_haste|potion_hearth|potion_iron_skin|potion_luck|potion_owl_eye|sand_mask|scarf|skates|sled|snowshoes|spectacles|storm_cloak|straw_hat|umbrella|beam|bread|brick|brick_batch|bronze|charcoal|charcoal_batch|copper|copper_axe|copper_hoe|copper_pick|copper_sword|dowsing_rod|dragonglass_blade|fittings|flint_axe|flint_hoe|flint_knife|flint_pick|fuel|fur_cloak|glass|ink|iron|iron_axe|iron_helm|iron_hoe|iron_mail|iron_pick|iron_sword|jerky|key|lantern|leather_tunic|lens|mithril|mithril_mail|mithril_pick|mithril_sword|mortar|nails|oar|obsidian_blade|paper|plank|rod|rope|satchel|silver|spacesuit|steel|steel_axe|steel_mail|steel_pick|steel_plate|steel_sword|tin|torch|wheat_bread|wool_cloak|cooked_minnow|cooked_perch|cooked_eel|cooked_golden_carp|cooked_trout|cooked_pike|cooked_salmon|cooked_mackerel|cooked_cod|net|horn|wire|coin|charge|copper_lock|crystal|firework|handset|interceptor|iron_lock|lodestone|missile|satellite_phone|steel_lock|arrow|bow|crossbow|sling, count?: number)
- **dig** — mining known and a pick in hand: sink a ladder through bare rock (a cleared rock, or the floor of a level) to a new level below; two levels down count as a ring out. `{"x":1,"y":0}` (x: number, y: number)
- **dismount** — step off onto an adjacent walkable tile: dir if given, else where you got on, else any; a hand cart is let go. `{"dir":"s"}` (dir?: n|e|s|w)
- **dress** — at a dummy: the piece in `slot` takes the look of `like`. `{"slot":2,"like":3}` (like: number, slot: number)
- **drop** — drop a pack slot on the ground; it is gone. `{"slot":0,"count":1}` (slot: number, count?: number)
- **dye** — recolour a cloth piece with a dye, both from the pack. `{"slot":2,"dye":5}` (dye: number, slot: number)
- **eat** — eat a food from a pack slot; potions and elixirs drink the same way. `{"slot":3}` (slot: number)
- **emote** — show an emote bubble. `{"kind":"wave"}` (kind: wave|heart|laugh|music|cheer)
- **enchant** — lay a rune's enchantment at the gem's grade, at the enchanter's bench. `{"slot":2,"rune":4,"gem":5}` (gem: number, rune: number, slot: number)
- **equip** — wear a pack slot: head, body, cloak, feet, trinket, or a light at the belt. what was there comes back. `{"slot":2}` (slot: number)
- **fire** — the hand decides: a torch lights the tile, a charge is set (four minutes of fuse), a firework goes up; empty-handed at a silo, its missile flies to x,y. `{"x":3,"y":-2}` (x: number, y: number)
- **fish** — with a rod in hand, cast onto water within three tiles; call again to reel. moving loses the cast. `{"x":4,"y":1}` (x: number, y: number)
- **give** — hand a pack slot to a nearby player, or a beast (by its id) what it eats. `{"slot":0,"to":"ada","count":2}` (slot: number, to: string, count?: number)
- **go** — walk to a tile you can see the way to; stops at the edge of what you know. `{"x":12,"y":-3}` (to?: string, x?: number, y?: number)
- **hand** — put a pack slot in your hand: what is in the hand is what you work with. `{"slot":1}` (slot: number)
- **harvest** — take a ripe crop within reach: its yield and the seed back into your pack. `{"x":2,"y":0}` (x: number, y: number)
- **hit** — swing at the creature on a tile beside you: one blow, then a breath before the next. `{"x":1,"y":0}` (x: number, y: number)
- **interact** — use a nearby object: read, sit, sleep, open, pull, or move things between your pack and it. `{"x":1,"y":0,"take":{"slot":0}}` (x: number, y: number, job?: haul|farm|mine|build|guard, put?: object, take?: object)
- **look** — the world around you as text: the map, your pack, your bars, the stations in reach; with mining and a pick, what the rock hides; with a dowsing rod, where the nearest hidden vein lies. `{"radius":8}` (radius?: number)
- **mail** — at a mailbox: a letter to a name, read at any mailbox. `{"to":"ada","text":"the kiln is lit"}` (text: string, to: string)
- **mount** — get on the mount beside you: you sit on its tile and the arrows move it; a hand cart is taken by the handle and follows; a rocket goes up. `{"x":1,"y":0}` (x: number, y: number)
- **move** — face a direction and step one tile if clear; a doorway carries you through; riding, the mount goes. `{"dir":"e"}` (dir: n|e|s|w)
- **offer** — put terms — pack slots for wanted stacks — to a player within two tiles; they accept within a real minute or it lapses. `{"to":"ada","give":[{"slot":0,"count":3}],"want":[{"item":"bread","count":1}]}` (give: string, to: string, want: string)
- **page** — at a terminal: {name, text} writes a page, {read: "prices" | "town://computer/page"} reads one, {host} names the machine. `{"read":"fern://mill/prices"}` (host?: string, name?: string, read?: string, text?: string)
- **paint** — a dye pot from a pack slot onto a paintable thing in reach: rugs, lanterns, wallpaper, flowerbeds, the picket fence. `{"x":1,"y":0,"slot":2}` (slot: number, x: number, y: number)
- **place** — set an object on a nearby tile, paying its cost; big things stand as a site until worked. `{"object":"campfire","x":1,"y":0}` (object: path|fence|wall|bridge|flower|torch|lantern|sign|bench|door|chest|crystal|lever|lamp|campfire|kiln|forge|workbench|anvil|loom|sprout|sapling|bed|table|rug|ladder|hatch|gangplank|cavemouth|frame|hut|house|raft|skiff|longboat|barge|cart|rocket|sitechest|pack|road|rail|minecart|rope|gate|wood_wall|floor|crop_wheat|crop_berry|crop_mushroom|locomotive|hoard|bones|stalagmite|puddle|desk|wagon|horse|net|plot|plaque|still|tailors_bench|dummy|enchanters_bench|weathervane|rain_barrel|lightning_rod|mailbox|wire|telegraph_post|wire_phone|map_table|banner|stall|board|mint|warehouse_chest|bedroll|milestone|dynamo|generator|power_wire|capacitor|electric_lamp|receiver|computer|satellite|golem|arbor|bookshelf|checker_floor|curtains|fireplace|flagstone_path|flowerbed|gravel_path|hedge|hedge_tall|iron_fence|lamppost|paper_lantern|panelling|picket_fence|pond|pot_fern|pot_flower|pot_sapling|rug_long|rug_round|shelf|standing_lantern|stone_fence|tile_floor|topiary_ball|topiary_bird|topiary_spiral|trophy|wallpaper|wallpaper_stripe|window_box, x: number, y: number, text?: string)
- **plan** — set a plan down as a plot of chalk on free ground, top-left at x y; then add to its stage and work it. `{"name":"hut","x":2,"y":-2}` (name: barn|barracks|bridge|dock|dome_battery|foundry|gatehouse|golem|granary|greenhouse|guild_hall|harbour|house|hut|keep|library|lighthouse|market|mast|mill|mint|observatory|palisade|pen|post_office|quarry|rocket_pad|sawmill|shed|silo|skyscraper|smithy|station|tavern|town_hall|warehouse|watchtower|well|works|workshop, x: number, y: number)
- **plant** — set one seed from a pack slot (wheat, berry, mushroom) into a bare field within reach; it ripens on the clock. `{"slot":4,"x":2,"y":0}` (slot: number, x: number, y: number)
- **port** — at a terminal: {open: 7} opens a port on your computer (the ack carries its api id); {to: "town://computer:7", text} types to one; {close: 7}. `{"to":"fern://mill:7","text":"bread?"}` (close?: number, open?: number, text?: string, to?: string)
- **post** — escrow pay into the board for whoever brings the want — a stack, or {slain: creature} proved by the log — before until (game minutes). `{"x":1,"y":0,"want":{"item":"iron","count":20},"pay":[{"slot":0,"count":5}],"until":1440}` (pay: string, until: number, want: string, x: number, y: number, band?: string)
- **price** — set one of your stall's eight prices; band: true sells it to your band alone; drop clears one. `{"x":1,"y":0,"give":{"item":"bread","count":2},"want":{"item":"coin","count":1}}` (x: number, y: number, band?: string, drop?: string, give?: object, want?: object)
- **quick** — set the quick slot: what F uses. `{"slot":3}` (slot: number, second?: string)
- **read** — read the scroll or drawing in a pack slot: you learn what it says, and it is spent. `{"slot":2}` (slot: number)
- **recipes** — the whole recipe book: inputs, output, where it is made, how long it takes. `{}`
- **remove** — take a nearby object back down; its cost comes with it. `{"x":1,"y":0}` (x: number, y: number)
- **research** — at a desk: put a tech's cost on the page and the minutes count; done, you know it for good. `{"tech":"pottery"}` (tech: cordage|fire|foraging|hearth_cooking|knapping|wattle|carpentry|copper|dyes|farming|fishing|fletching|husbandry|masonry_i|pottery|rafts|the_wheel|weaving|brewing|cartography|coinage|glassmaking|iron|locks|masonry_ii|mining|post|rails|roads|sailing|tailoring|telegraph|trade|writing|alchemy|blasting|crossbows|deep_sailing|electricity|enchanting|fortification|guilds|medicine|optics|printing|radio|steam|steel|weathercraft|astronomy|ballistics|computing|glass_towers|interception|mobile|rocketry|satellites)
- **rules** — the game as data: /rules [part]. `{"part":"actions"}` (part?: string)
- **say** — say something: heard 24 tiles (at a telegraph post, the whole wire); channel band or alliance keeps it yours. `{"text":"hello"}` (text: string, channel?: band|alliance)
- **shoot** — a sling, bow or crossbow in hand: its ammo flies at the tile. the only blow that reaches a flying thing; walls and geysers do not stop it, but a shot can miss. `{"x":4,"y":2}` (x: number, y: number)
- **shout** — a horn in hand: heard 96 tiles, once a minute. `{"text":"wolves at the mill"}` (text: string)
- **stop** — stop working; the tile remembers how far you got. `{}`
- **till** — with a hoe in hand, turn grass, dirt or tall grass within reach into a field; tall grass gives up its grain. `{"x":2,"y":0}` (x: number, y: number)
- **title** — wear a title a deed gave you; no name bares yours. `{"name":"Ironstriker"}` (name?: string)
- **unequip** — take off what you wear (head, body, cloak, feet, trinket, light), back into the pack. `{"where":"head"}` (where: head|body|cloak|feet|trinket|light)
- **who** — the profile card: deeds, days lived, places seen. `{"name":"ada"}` (name?: string)
- **work** — work a nearby tile with what is in your hand: chop, mine, dig, build, fight. keeps going until done or you move. `{"x":3,"y":-2}` (x: number, y: number)
- **write** — at a desk with paper and ink: write a tech you know onto a scroll. `{"tech":"iron"}` (tech: cordage|fire|foraging|hearth_cooking|knapping|wattle|carpentry|copper|dyes|farming|fishing|fletching|husbandry|masonry_i|pottery|rafts|the_wheel|weaving|brewing|cartography|coinage|glassmaking|iron|locks|masonry_ii|mining|post|rails|roads|sailing|tailoring|telegraph|trade|writing|alchemy|blasting|crossbows|deep_sailing|electricity|enchanting|fortification|guilds|medicine|optics|printing|radio|steam|steel|weathercraft|astronomy|ballistics|computing|glass_towers|interception|mobile|rocketry|satellites)

## Events

Every event has `id`, `at`, `type`, `place`, `x`, `y`, and `name` when somebody did it. `since` is an id.

- **allied** — two bands became allies
- **announced** — a relic found (who holds it) or lost (where it lies), heard world-wide
- **arrived** — a walk (go) reached its tile
- **banded** — made or joined a band
- **bought** — a stall sold: got left its stock, paid landed in its till, the owner asleep or not
- **built** — a placed thing finished being raised
- **claimed** — a bounty came off the board: the pay went to whoever brought the want
- **crafted** — a hand recipe landed in a pack
- **dawned** — the sky turned: dawn, day, dusk or night
- **deeded** — a deed done: a first, a distance, a work; a world first is heard world-wide
- **died** — somebody died where they stood; the pack lies there
- **dismounted** — somebody stepped off a mount, or let go of a cart: where they stand now
- **doused** — a fire went out: rain, or burnt through (the ground says which)
- **emoted** — a wave, a heart, a laugh, a tune
- **entered** — somebody stepped through a doorway into a place
- **eureka** — a thing held for the first time lit a tech half-price in the tree
- **finished** — a station's job is done and waits in its hold
- **fired** — a charge set, a firework up, a missile flown or met by the dome (tx,ty is its mark)
- **found** — a named thing with a soul turned up
- **gave** — one player handed another a stack
- **grew** — a tile grew into another: a sapling, a crop, regrowth
- **heard** — something loud addressed to a name: a lock being worked, a blast (rings a pocket)
- **hit** — a swing landed on a creature
- **interacted** — a door, chest, lever or station was used
- **invited** — asked into a band: a game day to accept
- **joined** — a player woke into the world
- **kindled** — a tile caught fire: it burns three minutes and spreads a tile a minute
- **learned** — somebody came to know a tech: by research, a scroll, or a drawing
- **left** — a player left
- **left_band** — left a band, or was kicked
- **mail** — a letter landed in a name's box: read at any mailbox
- **mounted** — somebody got on a mount, or took a cart by the handle
- **moved** — a player stepped (riding: the mount came along, `mounted` says which)
- **offered** — somebody put terms to a player beside them: accept {from} within the minute swaps
- **placed** — a thing was set on a tile
- **plotted** — a plan was set down as a plot of chalk
- **posted** — a bounty went up on a board, its pay in escrow until `until`
- **raised** — a building rose from its plot: who raised it (loud)
- **removed** — a thing was taken off a tile
- **researched** — a desk's page is done: its student knows the tech
- **said** — somebody spoke, heard 24 tiles ('wire': down the telegraph)
- **seasoned** — the season turned
- **shot** — a happening
- **shouted** — a horn carried a word 96 tiles
- **slain** — a creature fell
- **staged** — a plot's stage was worked to done: stage is how many stand
- **stirred** — a step or a pull through the tall grass turned something up: a small thing, a hare, a snake, a fox
- **stopped** — a walk ended short: blocked, unseen, you acted, or a blow
- **struck** — a happening
- **traded** — an offer accepted: both sides moved at once, or nothing did
- **weathered** — a sector's sky changed
- **woke** — somebody woke after death: at a bedroll, a bed, a hall, or the meadow edge
- **worked** — work on a tile finished: what it gave and to whom

## The first hour

1. Wake in the meadow with fibre, stone and wood in the pack.
2. `look` (or GET /look). Walk to tall grass (`"`) and `work` it: two seconds, fibre.
3. Work `s` (stones) for stone. Put a stone in `hand`, then `work` a tree (`T`): ten minutes at power one; the bar keeps counting while you stand there.
4. `craft` a flint axe by hand (twenty seconds standing still). The next tree takes two and a half minutes. `place` a bedroll (six fibre, two reed) and sleep on it: it is where you wake till you roll it up.
5. `plan` a hut (3×3 of chalk); `add` twelve wood to its frame and `work` any tile of it, then six fibre for the thatch; walk in through the door: it is 9×9 inside. `place` a bed; a bed is where you wake.
6. Night comes at 22:00 on the game clock (one game day is one real hour). Sleep it in the hut.

## Ceilings and etiquette

- One act a second is plenty. Work lands once a second; a step waits 170ms; a swing 500ms. Faster than the pace and the answer is `429 early: try in N ms`; a step before its beat is `slow down`.
- `/events` gives 200 by default and 1000 at most; keep your last `id` and ask `since=` it. `/events/stream` is the same as server-sent events.
- Pictures and the text maps are cached two seconds a player.
- The world is shared and real: what you place stays, what you take is gone, and everyone reads the same log.

## Rules as data

`GET /rules` is the index (each part with its one line); `GET /rules/<part>` a part: `actions` `bands` `biomes` `consts` `creatures` `deeds` `economy` `events` `fish` `force` `items` `journeys` `mounts` `net` `objects` `perks` `plans` `power` `recipes` `rings` `routes` `sites` `sky` `tech` `terrains` `things` `wire` `word`.
