[
  {
    "code": "bad_request",
    "origin": "vault",
    "http": 400,
    "exit": 2,
    "next": {
      "say": "Fix the request as the message says; `mehen <command> --help` shows the options."
    },
    "means": "The request was malformed or failed validation: an unknown provider, a template of another kind, a new item without a template or proposed binding, a run naming variables the vault does not know, a plain value that looks like a secret, a request with nothing for the relay to do.",
    "do": "Fix it as the message says; `mehen <command> --help` shows the options."
  },
  {
    "code": "unauthenticated",
    "origin": "vault",
    "http": 401,
    "exit": 6,
    "next": {
      "command": "mehen doctor",
      "say": "The vault did not recognise this machine; `mehen doctor` says whether it is enrolled and what to do."
    },
    "means": "No proof, or this machine is not enrolled.",
    "do": "Run `mehen status`; the machine may need `mehen enrol --workspace <slug>`."
  },
  {
    "code": "proof_invalid",
    "origin": "vault",
    "http": 401,
    "exit": 6,
    "next": {
      "command": "mehen doctor",
      "say": "The vault did not accept this machine's signature, often because the clock is more than 60 s off; `mehen doctor` checks the clock and the key."
    },
    "means": "The vault did not accept this machine's signature: clock skew over 60 seconds, a replay, or a URL, method or body that does not match what was signed.",
    "do": "Check the machine's clock; `mehen doctor` checks the clock and the key. Do not hand-craft requests; use `mehen`."
  },
  {
    "code": "device_pending",
    "origin": "vault",
    "http": 403,
    "exit": 4,
    "next": {
      "command": "mehen pending",
      "say": "This machine's enrolment has not been approved yet; relay its link to the owner (`mehen pending` shows it)."
    },
    "means": "This machine's enrolment has not been accepted yet.",
    "do": "Write the human the enrolment block (`mehen pending` shows it again), then `mehen wait <enrolment>`."
  },
  {
    "code": "device_revoked",
    "origin": "vault",
    "http": 403,
    "exit": 6,
    "next": {
      "say": "This machine was revoked. Stop and tell the human; only they can let it enrol again."
    },
    "means": "This device was revoked.",
    "do": "Stop. Tell the human; only they can let it enrol again."
  },
  {
    "code": "forbidden",
    "origin": "vault",
    "http": 403,
    "exit": 5,
    "next": {
      "command": "mehen status",
      "say": "This machine is not allowed to do that. Tell the human; only they can widen its scope in the vault."
    },
    "means": "This device's scope or its owner's rights do not cover the item, project or action (a guest's or a team's machine creating a project, a machine limited to named projects running `mehen init`, a workspace home proposed by a member's machine), the item is disabled or never sent by the relay, a method-override header or parameter was sent, or only an owner or admin may do this.",
    "do": "Tell the human; only they can widen a scope or a share."
  },
  {
    "code": "not_found",
    "origin": "vault",
    "http": 404,
    "exit": 1,
    "next": {
      "command": "mehen ls",
      "say": "Check the name with `mehen ls`; ask for a missing credential with `mehen request`."
    },
    "means": "No such item, intake, approval, connection, project, run or route, or one outside this machine's reach: another member's private credential, a project not shared with your owner, a workspace credential from a guest's or a team's machine. Absent and out of reach answer the same, so nothing can be learnt by naming.",
    "do": "Check the slug or id with `mehen ls`; ask for a missing credential with `mehen request`."
  },
  {
    "code": "conflict",
    "origin": "vault",
    "http": 409,
    "exit": 1,
    "next": {
      "command": "mehen pending",
      "say": "This clashes with something that already exists or is already open; `mehen pending` lists this machine's open asks."
    },
    "means": "The request clashes with existing state: a name not available (in use anywhere in the workspace, including by a credential you cannot see), an item of another kind, a project or remote already taken, or an open intake or connect for the same slug with other details, from this machine or another; or a rotation proposing a different home.",
    "do": "Pick another slug, wait on the open link (`mehen pending` lists this machine's), or ask again with `--new` to replace your own."
  },
  {
    "code": "ambiguous",
    "origin": "vault",
    "http": 409,
    "exit": 2,
    "next": {
      "say": "Name one item by its slug; if you are not sure which account is meant, ask the human."
    },
    "means": "Reserved: several items could serve. The vault does not raise it today, because every request names its item.",
    "do": "Pick one slug from `choices`; if you are not sure which account is meant, ask the human."
  },
  {
    "code": "binding_refused",
    "origin": "vault",
    "http": 403,
    "exit": 5,
    "next": {
      "say": "The vault will not send this credential there. Use a host and a plain URL from `mehen show <item>`; only a human can change where it may go."
    },
    "means": "The destination is outside the item's binding, or the URL is one the vault will not guess at: an encoded slash, dot or backslash, `..`, `//`, a username in the URL, a scheme other than http or https, or an IP address or loopback name not bound exactly.",
    "do": "Use a host and a plain URL from `mehen show <item>`. If the host really is needed, ask the human to change the binding; only they can."
  },
  {
    "code": "surface_refused",
    "origin": "vault",
    "http": 403,
    "exit": 5,
    "next": {
      "say": "Remove the placeholder from the body, query or header it is in; the vault injects the credential itself."
    },
    "means": "A run's placeholder appeared outside its item's declared header or query parameter, or at a host it is not bound to. It is recorded as a tripwire.",
    "do": "Remove the placeholder from the body, query or header it is in; the vault injects the credential itself."
  },
  {
    "code": "policy_denied",
    "origin": "vault",
    "http": 403,
    "exit": 5,
    "next": {
      "say": "The item's policy refuses this. Do not work around it; tell the human what you tried, or use another route."
    },
    "means": "The item's policy denies this method or path.",
    "do": "Do not work around it. Use the alternative the template names, or tell the human what you tried."
  },
  {
    "code": "approval_required",
    "origin": "vault",
    "http": 409,
    "exit": 3,
    "next": {
      "say": "This needs a human's approval in the vault; relay the link, wait for it, then repeat the same request."
    },
    "means": "A human must approve this exact request: a send, a delete, a production run, any use of a protected item. The error carries the approval id, the link, a binding code and `expiresAt`.",
    "do": "Tell the human in one message what you are trying to do, then write the block from `ask`; the check is the binding code. Run `mehen wait <approval>`, and when it is approved repeat exactly the same request from the same machine (the same item, method, URL, headers and body). If it is denied or expires, stop and ask the human what they want instead; do not retry in a loop."
  },
  {
    "code": "mode_refused",
    "origin": "vault",
    "http": 403,
    "exit": 5,
    "next": {
      "say": "The vault will not use this credential that way. Use `mehen fetch` or `mehen run`, and keep a request that needs approval small and uncompressed."
    },
    "means": "The item's exposure ceiling does not allow this use, a lease was asked for that the item, the device or the run does not allow, or a request that needs approval cannot be shown in full (a compressed body, a body over 64 KiB, a command line over 4096 characters).",
    "do": "Use relay (`mehen fetch`) or placeholders (`mehen run`), and send anything that needs approval uncompressed and small."
  },
  {
    "code": "environment_refused",
    "origin": "vault",
    "http": 403,
    "exit": 5,
    "next": {
      "say": "That environment is protected or fenced. Use an unprotected one, or run with a literal --env <name> and expect an approval."
    },
    "means": "A protected environment without a literal `--env`, a device allowed for it or an owner with the protected right; a protected credential used without a project context naming the protected environment that references it, or outside an approved protected run; an agent setting a protected variable; an OAuth client a protected environment relies on, used by anyone but an owner or admin; or a host fenced to another environment.",
    "do": "Use an unprotected environment, or type `--env <name>` and expect an approval; give `mehen fetch` the context with `--project <prj_id> --env <name>`. For a fence, run in the environment the host belongs to."
  },
  {
    "code": "remote_mismatch",
    "origin": "vault",
    "http": 403,
    "exit": 5,
    "next": {
      "say": "This checkout's origin remote is not the one bound to the project in mehen.toml. Check you are in the right clone."
    },
    "means": "This checkout's `origin` remote is not the one bound to the project id in `mehen.toml`.",
    "do": "Check you are in the right clone."
  },
  {
    "code": "needs_reauth",
    "origin": "vault",
    "http": 424,
    "exit": 4,
    "next": {
      "say": "The credential no longer works; a human must reconnect or replace it in the vault. Tell them which one."
    },
    "means": "The OAuth connection is dead (revoked, expired, password changed, client secret rejected), or the item must be replaced.",
    "do": "Write the human the block (a reconnect link pinned to the same account, with `expiresAt`), then `mehen wait`. When the vault's link is the item's own page (a broken OAuth client, or a non-OAuth item that must be replaced), the block opens that page and has no wait: the human replaces the credential there, then you try again."
  },
  {
    "code": "refresh_retrying",
    "origin": "vault",
    "http": 503,
    "exit": 7,
    "next": {
      "say": "The provider did not answer the vault's token refresh; retry shortly."
    },
    "means": "The provider did not answer the vault's token refresh: a transient OAuth failure.",
    "do": "Retry after `retryAfter` seconds."
  },
  {
    "code": "intake_required",
    "origin": "vault",
    "http": 404,
    "exit": 4,
    "next": {
      "command": "mehen request --help",
      "say": "The credential does not exist yet; ask the human for it with `mehen request`."
    },
    "means": "Reserved: the credential does not exist yet. The vault answers `not_found` today.",
    "do": "Ask the human for it with `mehen request`, write them the block, then `mehen wait <intake>`."
  },
  {
    "code": "frozen",
    "origin": "vault",
    "http": 423,
    "exit": 4,
    "next": {
      "say": "The vault is frozen. Stop and tell the human; they review the audit log and unfreeze it in the vault."
    },
    "means": "The whole workspace is frozen: every use is refused until an owner unfreezes it.",
    "do": "Stop. Tell the human; they review the audit log and unfreeze it in the vault."
  },
  {
    "code": "rate_limited",
    "origin": "vault",
    "http": 429,
    "exit": 7,
    "next": {
      "say": "Too many requests; slow down and retry shortly."
    },
    "means": "Too many requests; also this machine's 20 open asks, or too many unavailable names tried in an hour.",
    "do": "Slow down, settle an open ask, and retry after `retryAfter` seconds when given."
  },
  {
    "code": "too_large",
    "origin": "vault",
    "http": 413,
    "exit": 1,
    "next": {
      "say": "Send or ask for less: the vault caps requests and responses."
    },
    "means": "The request or the upstream's response is too large; responses are capped at 32 MiB.",
    "do": "Send or ask for less."
  },
  {
    "code": "upstream_failed",
    "origin": "vault",
    "http": 502,
    "exit": 7,
    "next": {
      "say": "The vault could not get an answer from the upstream; retry later, and check whether the request took effect first."
    },
    "means": "The vault could not reach the upstream, or the upstream answered in a compression the vault cannot check for leaked credentials. In the compression case the request itself was sent.",
    "do": "Retry later; in the compression case, check whether the request took effect before sending it again."
  },
  {
    "code": "internal",
    "origin": "vault",
    "http": 500,
    "exit": 1,
    "next": {
      "say": "Something broke inside the vault. Retry once; if it happens again, tell the human the time it happened."
    },
    "means": "Something broke inside the vault, or inside `mehen`.",
    "do": "Retry once; if it happens again, tell the human the time it happened. For a failure inside `mehen`, `mehen doctor` checks this machine."
  },
  {
    "code": "account_pending",
    "origin": "vault",
    "http": 403,
    "exit": 4,
    "next": {
      "say": "Account security changes are pending. Ask the human to check their account security page."
    },
    "means": "The human's account has a security change (a recovery, a factor removal) still being installed across their workspaces; anything that widens access waits until it has.",
    "do": "Wait; the human can see it on their account page."
  },
  {
    "code": "owner_inactive",
    "origin": "vault",
    "http": 403,
    "exit": 4,
    "next": {
      "say": "The machine owner is not active. Ask a workspace owner or admin to check their membership."
    },
    "means": "The member who owns this machine is suspended, removed or not yet confirmed, or its team is gone; a machine never outlives its owner's standing.",
    "do": "Stop. Tell the human; an owner or admin must act on the membership."
  },
  {
    "code": "identity_required",
    "origin": "vault",
    "http": 403,
    "exit": 4,
    "next": {
      "say": "The human must verify their Google identity in the workspace before continuing."
    },
    "means": "The workspace requires a verified Google identity for the human's role, and their sign-in is not fresh enough for what was asked. It is raised to humans in the browser, and reaches a machine only through an operation that needed the human's standing.",
    "do": "Tell the human to open `https://app.mehen.dev/w/<slug>/` and complete the sign-in it asks for, then repeat the step. You cannot clear it yourself."
  },
  {
    "code": "project_unshared",
    "origin": "vault",
    "http": 403,
    "exit": 4,
    "next": {
      "say": "Ask the owner or a project manager to share the project with this machine's owner."
    },
    "means": "The project in `mehen.toml` exists but is not shared with this machine's owner, or no longer is.",
    "do": "Ask an owner or a project manager to share the project with this machine's owner."
  },
  {
    "code": "cli_outdated",
    "origin": "vault",
    "http": 426,
    "exit": 1,
    "next": {
      "command": "mehen update",
      "say": "This machine's mehen is older than the vault supports; update it, then run the command again."
    },
    "means": "An identified `mehen` is below the vault's minimum supported version (HTTP 426); freeze and self-revoke are exempt. The vault refused the request before doing anything.",
    "do": "Follow the returned `next`: after `mehen` has updated itself, it names the original command to run again; if the update did not run or failed, run `mehen update --json`, report any refusal, and never reinstall to get round a signature failure."
  },
  {
    "code": "usage",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "Bad arguments; also `mehen connect` finding several OAuth clients, with `choices`.",
    "do": "Run `next.command`, the command's `--help`, and fix the arguments; with several OAuth clients, name one with `--client`."
  },
  {
    "code": "network",
    "origin": "mehen",
    "http": null,
    "exit": 7,
    "next": null,
    "means": "The vault could not be reached.",
    "do": "Check the network connection and the vault URL (`MEHEN_VAULT_URL`), then retry. With `mehen fetch --max-time`, the request may still have reached the upstream: check before sending it again."
  },
  {
    "code": "timeout",
    "origin": "mehen",
    "http": null,
    "exit": 4,
    "next": null,
    "means": "`mehen wait` ran out of time while a human has not acted.",
    "do": "Run `next.command` again; the ask comes back with the error so you can relay it again. A connect link the human signed in to with an unexpected account also ends this way: ask them what the callback page said."
  },
  {
    "code": "stale",
    "origin": "mehen",
    "http": null,
    "exit": 5,
    "next": null,
    "means": "`mehen wait` found the approval or policy proposal stale: access changed under it (a share expired, a role changed, a protected reference was added, the decider lost their basis).",
    "do": "Do not repeat the old approval; follow `next` and ask again from the start."
  },
  {
    "code": "denied",
    "origin": "mehen",
    "http": null,
    "exit": 5,
    "next": null,
    "means": "The human denied the approval.",
    "do": "Do not retry without asking them what they want instead."
  },
  {
    "code": "rejected",
    "origin": "mehen",
    "http": null,
    "exit": 5,
    "next": null,
    "means": "The human rejected this machine's enrolment, or five wrong hidden groups were typed on its page.",
    "do": "Stop and tell the human; enrol again only when they ask you to."
  },
  {
    "code": "mismatch",
    "origin": "mehen",
    "http": null,
    "exit": 4,
    "next": null,
    "means": "`mehen wait` reports it when a connect link's status says the human signed in as an account other than the one expected. In the current release the vault does not record that status: it refuses an unexpected account at the provider's callback with `forbidden`, overwrites nothing, and the link stays open, so the wait goes on until it times out or the link expires.",
    "do": "Ask the human what the callback page said, tell them which account was expected, and start a fresh connection with `--new` before relaying a new link."
  },
  {
    "code": "client_missing",
    "origin": "mehen",
    "http": null,
    "exit": 4,
    "next": null,
    "means": "`mehen connect` found no OAuth client for the provider. `request` and `setup` carry the exact arguments for the client and the redirect URI.",
    "do": "Run `next.command`, the exact `mehen request oauth-client ...`, or repeat the connect with `--request-client` to ask for the client and the connection at once."
  },
  {
    "code": "expired",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "An intake, approval, connection or enrolment expired.",
    "do": "When this machine asked, `next.command` is the exact command to run again (for an enrolment, `mehen enrol --workspace <slug>`); run it and relay the new link."
  },
  {
    "code": "cancelled",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "An intake, approval, connection or enrolment was cancelled. An intake you replaced with `--new` is `cancelled`.",
    "do": "Ask the human before asking again; `mehen pending` lists a newer link when you made one."
  },
  {
    "code": "failed",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "An intake, approval, connection or enrolment failed; also another `mehen` holding a lock for 30 seconds (the message names its process id), and an unfinished migration of `MEHEN_HOME`.",
    "do": "When this machine asked, run `next.command`. For a lock, retry shortly. For a migration, `next.command` is `mehen doctor --json`: run it and tell the human."
  },
  {
    "code": "upstream_status",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "`mehen fetch --fail` was used and the upstream answered 4xx or 5xx.",
    "do": "Read the status and the body; the request reached the upstream."
  },
  {
    "code": "already_enrolled",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "The vault activated a second device for a workspace this machine already holds a device in. Nothing was revoked or deleted.",
    "do": "Relay `next.say`, which names both devices and how to keep one."
  },
  {
    "code": "not_available",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "The Secure Enclave helper is missing.",
    "do": "Enrol with `--backend software`, or ask the human to fix the helper."
  },
  {
    "code": "helper_failed",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "The Secure Enclave helper failed.",
    "do": "Enrol with `--backend software`, or ask the human to fix the helper."
  },
  {
    "code": "key_insecure",
    "origin": "mehen",
    "http": null,
    "exit": 6,
    "next": null,
    "means": "The device key file, a file beside it or the state directory is a symlink, is owned by someone else, or can be read by other users; or this user's home directory in the system's user database cannot be found or is unsafe, so `mehen` cannot tell whether the host is managed.",
    "do": "The message says which; follow `next`, and tell the human when it is theirs to fix."
  },
  {
    "code": "key_scope",
    "origin": "mehen",
    "http": null,
    "exit": 6,
    "next": null,
    "means": "The device key on disk was made for another vault. Once a workspace is selected, a key scope naming another origin or workspace is `workspace_mismatch` instead.",
    "do": "Run `next.command`, `mehen enrol --workspace <slug> --fresh-key`, or set `MEHEN_VAULT_URL` back."
  },
  {
    "code": "command_failed",
    "origin": "mehen",
    "http": null,
    "exit": 1,
    "next": null,
    "means": "A `mehen env` call made through `vault_env` failed.",
    "do": "The message says why and names the fix."
  },
  {
    "code": "pin_outdated",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "A managed host's agent configuration is out of date. Selection fails closed; nothing is signed or sent.",
    "do": "This host uses an outdated managed-agent configuration. Stop and contact the harness owner. Relay the refusal and its next step; do not edit the pin, identity files or launch environment yourself."
  },
  {
    "code": "workspace_unbound",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "The checkout's `mehen.toml` names no `workspace`, and this machine is enrolled in more than one.",
    "do": "Run `mehen workspace bind` in the checkout."
  },
  {
    "code": "workspace_mismatch",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "Two things name different workspaces or origins: the selector and the manifest, `MEHEN_VAULT_URL` and the enrolment, the key scope and the config, a `vault_env` cwd and the server's workspace, or a selection on a managed host that is not its pin; nothing is signed or sent. Also an enrolment the vault activated in another workspace, with another owner kind or an incomplete scope than asked, or into a directory another enrolment took meanwhile: `mehen` has then contacted the vault, attempted to revoke the new device and written no config.",
    "do": "Give one selection and fix the other. After an enrolment mismatch, read the message: it says whether the revocation succeeded, and when it did not it names the device for a human to revoke."
  },
  {
    "code": "workspace_unknown",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "No enrolment on this machine is in the workspace named by `--workspace`, `MEHEN_WORKSPACE` or the checkout's `mehen.toml`.",
    "do": "Run `next.command`, `mehen enrol --workspace <slug>`, or `mehen wait <enrolment>` for a pending one."
  },
  {
    "code": "context_ambiguous",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "Several workspaces could serve and nothing selects one. Also a bare entry of `MEHEN_WORKSPACES` that matches workspaces at two vaults.",
    "do": "Name one with `--workspace <slug>`; `next.say` lists them. Never pick a workspace on the human's behalf. For the `MEHEN_WORKSPACES` case, the human writes the entry as `<vault>/<slug>`."
  },
  {
    "code": "workspace_not_allowed",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "The workspace named is outside `MEHEN_WORKSPACES`.",
    "do": "Tell the human, who changes the harness; nothing inside `mehen` widens it."
  },
  {
    "code": "config_dir_retired",
    "origin": "mehen",
    "http": null,
    "exit": 2,
    "next": null,
    "means": "The harness sets `MEHEN_CONFIG_DIR`, a retired variable, pointing inside Mehen's state or disagreeing with `MEHEN_HOME`.",
    "do": "Relay `next.say`, which names the `MEHEN_HOME` to set instead; tell the human."
  }
]
