> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alakazam.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Editing with natural language

> Describe a change in prose and the kernel agent authors it — validated fail-closed, results only, never the authoring brain.

A world is a **programmable graph**, and you don't always want to hand-script
every node and edge. `POST /v1/worlds/{id}/edit` lets you **describe a change in
plain language** — "add a locked vault behind the cellar and wire a key that
opens it" — and the server-side **kernel agent** authors it for you, then hands
the result through the exact same validation gate every deterministic write
passes.

This is the natural-language tier of the [Graph-Editing API](/graph-editing).
Both tiers — the deterministic CRUD/ops surface and this one — funnel through one
fail-closed kernel gate, so a world edited either way behaves identically in the
editor and at runtime.

<Note>
  `/edit` needs a **secret** (`sk_`) key with `worlds:write`. It is real LLM
  spend: each call reserves one unit against your daily `edit` quota. Never ship a
  secret key to a browser.
</Note>

## The authoring brain stays server-side

This is the load-bearing guarantee of the endpoint. The kernel agent — its system
prompt, its op grammar, its lexicon, the model that drives it, and the raw op
trace it produces — **never leaves the server**. The response is **results
only**: exactly `world`, `diagnostics`, and `reply`, and nothing else.

```json theme={null}
{
  "world": { "id": "…", "name": "…", "entrance": { … }, "scene": { … } },
  "diagnostics": [],
  "reply": "Added a 'vault' state behind the cellar and a 'Turn the brass key' transition gated on the key item."
}
```

* **`world`** — the new, kernel-validated world. Identical in shape to what
  `GET /v1/worlds/{id}` returns.
* **`diagnostics`** — advisory (`warning`/`info`) findings on the persisted
  world, the same set the [validate/lint](/graph-editing#validate-and-lint-without-saving)
  endpoints return.
* **`reply`** — the agent's natural-language summary of what it did.

The new revision comes back as the `ETag` header — hold onto it for your next
write (see [optimistic concurrency](/graph-editing#optimistic-concurrency)).

## The validation gate applies, unconditionally

The agent can propose anything; it cannot **persist** anything invalid. Whatever
graph it authors is run through the kernel grammar and the full doctrine lint
suite **fail-closed** before it is saved. If the result would be invalid, the
call returns `422` with the blocking `diagnostics` and **nothing is persisted** —
and your quota reservation is refunded. Even a hostile instruction cannot push an
off-doctrine world past the gate.

## A basic edit

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST 'https://api.alakazam.gg/v1/worlds/WORLD_ID/edit' \
    -H 'Authorization: Bearer sk_live_…' \
    -H 'Content-Type: application/json' \
    -H 'Idempotency-Key: edit-vault-001' \
    -d '{
      "instruction": "Add a locked vault behind the cellar and wire a brass key that opens the door."
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch(
    "https://api.alakazam.gg/v1/worlds/WORLD_ID/edit",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer sk_live_…",
        "Content-Type": "application/json",
        "Idempotency-Key": "edit-vault-001",
      },
      body: JSON.stringify({
        instruction:
          "Add a locked vault behind the cellar and wire a brass key that opens the door.",
      }),
    },
  );
  const { world, diagnostics, reply } = await res.json();
  console.log(reply);
  console.log(Object.keys(world.scene.states), "states; rev", res.headers.get("ETag"));
  ```

  ```python Python theme={null}
  import requests

  res = requests.post(
      "https://api.alakazam.gg/v1/worlds/WORLD_ID/edit",
      headers={
          "Authorization": "Bearer sk_live_…",
          "Content-Type": "application/json",
          "Idempotency-Key": "edit-vault-001",
      },
      json={
          "instruction": "Add a locked vault behind the cellar and wire a brass key that opens the door.",
      },
  )
  body = res.json()
  print(body["reply"])
  print(list(body["world"]["scene"]["states"]), "states; rev", res.headers["ETag"])
  ```
</CodeGroup>

Either `instruction` or `message` is accepted for the prose. Send a missing or
empty instruction and you get a `400` before any spend.

## Clarifying questions

The agent has an **ask-gate**: when an instruction is ambiguous, it returns its
question in `reply` and **leaves the world unchanged** (the response is still
`200`, and `world` is the world you already had). Treat a `reply` that ends in a
question as a prompt for more detail rather than a confirmation, then call again
with a sharper instruction.

```json theme={null}
{
  "world": { … },
  "diagnostics": [],
  "reply": "Which existing room should the vault connect to — the cellar or the hallway?"
}
```

## Idempotency and concurrency

Because `/edit` is metered LLM spend, retries matter.

* **`Idempotency-Key`** — a retried `/edit` with the same key returns the
  original result without a second LLM call (and without a second charge). Always
  send one for safe retries.
* **`If-Match`** (or an `expectedRev` body field) — guards against clobbering a
  concurrent edit. If the `rev` you assert is stale, the call returns `409`, the
  reservation is refunded, and you should reload and retry.

## Metering

`/edit` reserves one unit of the `edit` kind against your daily quota **before**
the agent runs (fail-closed). The reservation is **refunded** on a validation
reject (`422`), an agent failure (`502`), or a concurrency conflict (`409`), and
**recorded** only on a successful persist. Usage shows up under the `edit` key in
[`GET /v1/usage`](/pricing).

## Status codes

| Status | Meaning                                                                                                                         |
| ------ | ------------------------------------------------------------------------------------------------------------------------------- |
| `200`  | Edit applied (or a clarifying question in `reply` with no change). The new `rev` is the `ETag`.                                 |
| `400`  | Missing instruction. No spend.                                                                                                  |
| `402`  | Daily `edit` quota exceeded.                                                                                                    |
| `404`  | The world doesn't exist, or isn't yours.                                                                                        |
| `409`  | The `rev` you asserted is stale — reload and retry. Reservation refunded.                                                       |
| `422`  | The agent's world failed the kernel gate. The body carries the blocking `diagnostics`; nothing persisted; reservation refunded. |
| `502`  | The authoring agent failed. Reservation refunded.                                                                               |
| `503`  | The authoring or quota backend is unavailable (fail-closed).                                                                    |
