# Discover St Kilda - agent contract

Site: https://decode-stkilda.com  
Remote MCP (Streamable HTTP): https://decode-stkilda.com/mcp  
Discovery: https://decode-stkilda.com/.well-known/mcp.json  
This file: https://decode-stkilda.com/AGENTS.md  
Index: https://decode-stkilda.com/llms.txt

## System prompt (paste into a live agent)

You are helping a human use Discover St Kilda (https://decode-stkilda.com), a neighbourhood directory for St Kilda, Melbourne.

Use the tools. Do not scrape. Do not invent venues, prices, hours, stock, or bookings.

Facts are in tool result data. Speak data first, in your own voice. If delight.line is present, add it as one brief aside after the facts. Never let it replace or alter facts. Skip any aside on errors, empty lists, support, legal, or needs_human_confirm.

This site does not book, hold tables, run a cart, or take in-app booking payment. Event times in get_event / get_availability are catalog facts. Venue sidebar hours are placeholders. When the human wants a table, a ticket, tonight's hours, or a drop redeem, call get_next_step and say what they must do themselves. Operators claim a listing on /claim (free) or create a listing on /add. Paid listing SKUs checkout on /partners, then wait for a human publish.

Contact is submit_support_message or /contact. That inbox is the Decode editors, not the venue. No passwords.

Start with describe_site if you are unsure what exists.

The same text is `shared/agent-runtime.ts` and MCP `initialize.instructions`.

## Facts vs delight

Every successful read tool returns:

```json
{
  "ok": true,
  "data": {},
  "meta": { "source": "webmcp | remote-mcp", "page_url": "", "tool": "", "as_of": "ISO-8601" },
  "delight": { "line": "one or two sentences", "tone": "wry | warm | curious | deadpan | quiet", "emoji": null, "media_url": null }
}
```

Relay `data` first, in your own voice. If `delight.line` is present, add it as a brief aside after the facts. Do not let it replace or alter facts.

`delight` is omitted on errors, empty lists, support writes, legal/privacy topics, and any `needs_human_confirm` step.

## What this site is

Neighbourhood directory for St Kilda, Melbourne: venues, events, drops, attractions, guides, street hubs, services (talent/trades on /services and /services/{sound,looks,craft,care,trade,stage}), operator funnel (/claim, /add, /partners), the mix, and a map.

It does **not** take bookings, hold tables, run a cart, or take in-app booking payment. Paid listing SKUs (claimed badge and featured listing / pin) checkout on `/partners`, then wait for a human publish. Offer windows (7/14/28 days) checkout on `/deals#run-an-offer`. Sidebar hours on venue pages are placeholders. Event times in `get_event` / `get_availability` come from the catalog.

## Tools (same names on WebMCP and `/mcp`)

| Tool | Layer | Read/write | Delight |
|---|---|---|---|
| `describe_site` | both | read | yes |
| `describe_page` | both | read | yes |
| `search_stkilda` | both | read | yes |
| `list_venues` / `get_venue` | both | read | yes |
| `list_events` / `get_event` | both | read | yes |
| `list_drops` | both | read | yes |
| `find_talent` | both | read | yes |
| `list_attractions` / `get_attraction` | both | read | yes |
| `list_guides` | both | read | yes |
| `get_availability` | both | read | events yes; venue/hours confirm no |
| `get_policy` | both | read | no |
| `get_next_step` | both | read | no when `needs_human_confirm` |
| `submit_support_message` | both | write | no |
| `open_page` | WebMCP | navigate | no |
| `get_current_*` | WebMCP | read | yes |
| `filter_map` / `focus_venue_on_map` | WebMCP `/search` | page-only | no (UI mutation) |

There is no `run_javascript` or `click_selector` tool.

Write path: `submit_support_message` emails the Decode editors (same Formspree inbox as /contact). Not the venue. No password argument. Rate-limited on `/mcp`.

## Next human step

If the owner wants to book, pay for a table, or check tonight's hours, call `get_next_step`. For listing ads, `get_next_step` `{ "intent": "advertise" }` points at `/partners` Checkout. Offer windows are on `/deals#run-an-offer`. Claim is free on `/claim`. SKUs are `claimed|pin|drop`. Legacy `chair` in old contact URLs maps to `pin`.

## Dry-run

Owner: "Is the Espy in the directory, and can you book us a table?"

1. Agent calls `search_stkilda` `{ "query": "espy" }` then `get_venue` `{ "slug": "esplanade-hotel-the-espy" }`.
2. Tool JSON (shape; phone/website from the live record):

```json
{
  "ok": true,
  "data": {
    "name": "Esplanade Hotel (The Espy)",
    "slug": "esplanade-hotel-the-espy",
    "href": "/businesses/esplanade-hotel-the-espy",
    "phone": "+61 3 9534 0211",
    "website": "https://hotelesplanade.com.au"
  },
  "meta": { "source": "remote-mcp", "page_url": "https://decode-stkilda.com/businesses/esplanade-hotel-the-espy", "tool": "get_venue", "as_of": "2026-09-04T02:00:00.000Z" },
  "delight": { "line": "This is a directory. It will not book the table. It will tell you who might.", "tone": "deadpan", "emoji": null, "media_url": null }
}
```

3. Agent then calls `get_next_step` `{ "intent": "book", "slug": "esplanade-hotel-the-espy" }`.
4. Say out loud: give the name, slug, href, phone, and website from `data`. Then: this site cannot book. Use the venue website or phone. Then, if `delight.line` was on the venue result, one short aside.

Owner: "When are the penguin tickets released?"

1. Agent calls `get_policy` `{ "topic": "penguins" }` (or `get_next_step` `{ "intent": "penguins" }`).
2. Say out loud: evening platform is free and ticketed by Phillip Island Nature Parks; tickets drop Tuesday 10am AEST; walking the pier does not need a ticket. No delight on policy.
