# Instructions for an Agent Playing an AGE Game

You are being dropped into a text-adventure world served over a small REST API. You
navigate using HTTP requests. The world is described in prose; nothing about it is
shown to you up front. Everything you need to reach the **win condition** is discoverable
by looking, examining, reading, talking, and going carefully — and by remembering what
you learn, because you will be required to remember to win.

These instructions are strictly mechanical. They tell you *how* to operate the game and
the API, not *what* to do in any particular situation. The story, the theme, the
characters and the puzzles are for you to discover.

> **Base endpoint:** `https://age.catbee.ca`. All example URLs below use this. It is the
> `PLAY_BASE_URL` from the service's `.env` (set it if the service is reverse-proxied
> behind nginx); otherwise it defaults to `http://PLAY_HOST:PLAY_PORT`, i.e. wherever
> this service is listening.

---

## 1. Essential mindset

- You are steering a **session** with verbs (**look**, **go**, **take**, **use**, **read**,
  **talk**, and others). The server owns the ground truth of your position and progress.
- **Your notes and memory are your only continuity you can trust absolutely.**
  Read things and *immediately* record what they said — some things can only be read
  once. Your own notes are what survive if you lose context, and they are required to win.
- The game can **end permanently** in two ways: you **win** (`won: true`) or you **die**
  (`dead: true`). In either case the session is destroyed. To keep playing after a death,
  you **create a brand-new session** and start over, using your memory of past runs.
- If an action does nothing interesting, that is information too. Do not repeat choices
  that have already cost you a run.

---

## 2. Finding the games and starting a session

Base endpoint: `https://age.catbee.ca`.

### List available games

```
GET https://age.catbee.ca/play/games
```

Returns an array of game ids. Pick one to play.

### Inspect a game (optional)

```
GET https://age.catbee.ca/play/games/{game}
```

Returns metadata: title, subtitle, genre, the `start_room`, the list of rooms, and the
intro text.

### Create a new session

```
POST https://age.catbee.ca/play/games/{game}/sessions
```

Response contains:

| field          | meaning                                          |
|----------------|--------------------------------------------------|
| `session_id`   | keep this; every later request needs it          |
| `game`         | the game id                                      |
| `title`        | game title                                       |
| `intro`        | the opening prose                                |
| `status`       | `"active"`                                       |
| `start_room`   | the room you begin in                            |
| `observations` | current room, its exits, objects, NPCs           |

**Treat `session_id` as precious.** Lose it and the run is effectively gone (there is no
record to resume by). Record it in your notes.

---

## 3. The action API (the heart of the game)

Every move is:

```
POST https://age.catbee.ca/play/sessions/{session_id}/action
Content-Type: application/json

{"verb": "...", "subject": "...", "object": "..."}
```

- `verb` is *required*. It is a lowercase action word.
- `subject` is the target you act on (an object, a direction, an NPC, or your inventory
  item) — omit or use `null` when not needed.
- `object` is a *secondary* target for compound actions (see "use X on Y" below) — omit
  when not needed.

### Built-in verbs

| verb          | subject                | example                                   |
|---------------|------------------------|-------------------------------------------|
| `look`        | —                      | `{"verb":"look"}`                          |
| `inventory`   | —                      | `{"verb":"inventory"}`                     |
| `go`/`move`/`walk` | a direction     | `{"verb":"go","subject":"north"}`          |
| `take`        | an object              | `{"verb":"take","subject":"lantern"}`      |
| `examine`     | an object / npc / room | `{"verb":"examine","subject":"door"}`      |
| `read`        | a readable object      | `{"verb":"read","subject":"letter"}`       |
| `talk`        | an npc                 | `{"verb":"talk","subject":"the keeper"}`   |
| `use`         | an item (or see below) | `{"verb":"use","subject":"lantern"}`       |

### Compound actions

To use an item *on* a target, put the item in `subject` and the target in `object`:

```
{ "verb": "use", "subject": "blue key", "object": "brass door" }
```

### Custom verbs

Worlds may define their own valid verbs (`open`, `drink`, `ring`, `cross`, `plunge`,
etc.). If a natural verb makes sense for what is in front of you, simply try it.
The API tells you when a verb is invalid for that situation.

### Names

You may refer to things by **id or natural wording**, including substrings and, where
worlds define them, aliases. `"take blue key"` works even if the server calls it
`a scuffed blue key`. When an action resolves ambiguously, prefer the canonical `id` that
the API returns in `observations`.

### Direction shortcuts

The aliases `n`, `s`, `e`, `w`, `u`, `d` mean `go` north/south/east/west/up/down.
`l` = `look`, `i` = `inventory`.

---

## 4. Reading the response

Every action returns an envelope:

```
{
  "status": "active" | "won" | "dead",
  "step": 123,            // how many actions so far this run
  "won": false,
  "dead": false,
  "text": "prose narration of what happens",
  "event": "...",         // which rule fired, or a built-in name
  "observations": { ... },
  "inventory": ["<object ids you carry>"],
  "flags": ["<named flags set so far>"],
  "last_actions": [ ... ] // recent log, helpful for re-orienting
}
```

### `observations`

```
{
  "room": "<room id>",
  "name": "<display name>",
  "description": "<prose>",
  "exits": { "<dir>": { "room": "<room id>", "locked": true|false } },
  "objects": [ { "id": "...", "name": "..." } ],
  "npcs":    [ { "id": "...", "name": "...", "state": "..." } ]
}
```

- **`exits`:** `locked: true` means you cannot pass yet. The locked exit's `room` is where
  it leads once opened. Pay attention to *what* blocks you; the game generally leaves a
  way to satisfy it.
- **`objects`:** what is physically present here (not already in your inventory).
- **`npcs`:** who is in this room and their state.
- Only items you can see here or already carry can be acted upon by `use`/`examine`. You
  cannot use something from another room "from afar."

### Terminal states

- `won: true` → you reached the win condition. Great; the run is over.
- `dead: true` → your last choice killed the run. Note *exactly what you did* so you do
  not repeat it, and start a new session.

---

## 5. Orientation and re-connecting mid-session

If you ever lose what was just said (truncated output, new context), re-orient without
taking a new action:

```
GET https://age.catbee.ca/play/sessions/{session_id}
```

Returns status, `current_room`, `visited`, `inventory`, `flags`, `last_actions`, and
fresh `observations`. Use this to rebuild exactly where you are before continuing.

`look` (`POST` with `{"verb":"look"}`) is also always safe and cheap for re-establishing
your immediate surroundings.

After a `go`, `look` anyway: arrival text gives you the room's description and its deeper
`detail`, but only `look` adds the rotating `ambient` line — and re-reading a room after
you have picked something up is often how a clue finally lands. `observations.previous_room`
tells you which room you just came from; exits are frequently one-way or asymmetric, so
don't assume the reverse direction exists.

---

## 6. Session lifecycle and retrying on failure

- **You win or you die → the server deletes that session immediately.** The
  `session_id` becomes invalid afterwards and any request to it returns **404**.
  There is nothing to resume.
- If you `dead` and want to try again: **create a new session**
  (`POST https://age.catbee.ca/play/games/{game}/sessions`), get a fresh `session_id`, and retry.
- If you decide to abandon a run deliberately:
  ```
  DELETE https://age.catbee.ca/play/sessions/{session_id}
  ```
  This also frees the session. `GET` on it then returns 404.
- A **404** on a session almost always means the session is over (won/dead/abandoned) or
  the id was mistyped. A **404** on a game id means there is no such game.
- **Do not hammer a dead session.** Once you see `dead`/`won`, stop acting on it, note
  the lesson, and start fresh.

---

## 7. Note-taking and memory (read this twice — it is the point)

You will not win by improvising. You will win by **building a durable record** and
consulting it. Record, clearly and permanently (in your running notes / memory):

1. **The `session_id`** of your current run.
2. **Rooms:** id, name, and every exit you observed — and, crucially, **which exits were
   locked and what was implied about opening them**.
3. **Lookable detail** the narration gives you beyond the one-line description.
4. **Objects:** what you found, where, whether you took it, and anything you `read`,
   `examine`, or `use`d it to learn.
5. **Read-once content verbatim.** Some readable things can be read only once and then
   turn to ash / collapse. The instant you read something, **write its full content down**;
   you will not get a second chance to re-read it, and its content is often load-bearing.
6. **NPCs:** who they are, what they said, and their current `state` — before and after
   you interact with them.
7. **Flags:** the names reported in `flags` and which action set them. Flags are the
   server's named checkpoints of your progress; knowing which are set tells you what you
   have and have not changed.
8. **Fatal choices:** every action sequence that ended a run. Keep a "known dangers"
   list and do not repeat those choices in the next run.
9. **Open ends:** unanswered locks, references you have not chased, things the prose says
   you are missing. Keep a list of "what I still need / where I think things go."

You are allowed (and strongly encouraged) to create notes and memories, to summarize your
progress, and to revisit them before each action. Treat the world as state that exists
only as long as your notes say it does.

---

## 8. A minimal curl play-through (patterns to copy)

```bash
# 1. see what is playable
curl -s https://age.catbee.ca/play/games

# 2. start a run and capture the session_id
RESP=$(curl -s -X POST https://age.catbee.ca/play/games/<GAME>/sessions)
SID=$(python3 -c "import json,sys;print(json.loads('''$RESP''')['session_id'])")
echo "$RESP"

# 3. look around
curl -s -X POST https://age.catbee.ca/play/sessions/$SID/action \
  -H 'Content-Type: application/json' -d '{"verb":"look"}'

# 4. take a thing, then use one thing on another
curl -s -X POST https://age.catbee.ca/play/sessions/$SID/action \
  -H 'Content-Type: application/json' -d '{"verb":"take","subject":"lantern"}'
curl -s -X POST https://age.catbee.ca/play/sessions/$SID/action \
  -H 'Content-Type: application/json' -d '{"verb":"use","subject":"lantern","object":"lamp"}'

# 5. move, check state, and keep going
curl -s -X POST https://age.catbee.ca/play/sessions/$SID/action \
  -H 'Content-Type: application/json' -d '{"verb":"go","subject":"north"}'
curl -s https://age.catbee.ca/play/sessions/$SID
```

Read every response. Note the treasures and the tragedies. Retry when it ends.

---

## 9. Summary of invariants

- The server is the authority on your current run; your notes are the authority on
  everything you have learned.
- Win or die, the session is destroyed — always be ready to start a new one and lean on
  your notes.
- Look, examine, read, talk, and use. Compound `use X on Y` is a first-class move.
- Record read-once content immediately.
- A `dead` response is a lesson, not a wall: note it, create a new session, and try again.
