const INSTRUCTIONS: &str = "\
featherbit is an API gateway whose behavior is declared as node-graph POLICIES referenced by ROUTES.
- A policy is a graph of typed nodes (plugins) joined by edges `from: node.port` → `to: node.in`. It has exactly one `listener` (entry) and one `client` (exit).
- Every node's `success`/`out` port AND every declared outcome port (`denied`, `redirect`, `limited`, `broken`, `preflight`, `abort`, `routed`, `hit`, `true`/`false`, …) MUST be wired, or the policy fails to compile. Only `error` ports may be left unwired (they fall back to the policy's `error_handler`).
- Plugin config keys are documented per node type: call `get_node_type(<type>)` before writing a node's `config`. `list_node_types` lists them all.
- Variables: any string config value can reference request data, either as legacy `$var` (`$uri`, `$http_x_tenant`, `$arg_page`, `$cookie_sid`, `$msg_<key>`) or as a `{{namespace.path}}` template (`{{request.path}}`, `{{request.headers.x-tenant}}`, `{{request.query.page}}`, `{{message.user}}`, `{{client.ip}}`, `{{env.NAME}}`). Both resolve per request. Conditions use the bare var name: [\"arg_channel\", \"==\", \"beta\"]. To derive a value (a path segment, a JSON body field, a regex capture) add a `set-vars` node — it writes `context.message`, readable as `$msg_<name>`. Call `list_vars` for the full catalog, the template namespaces and the fields that are NOT templated (regexes, IP lists, schemas, Lua, upstream targets, route match rules); the reference pages are `featherbit://docs/reference/templates` and `featherbit://docs/reference/context-vars`.
- Authoring loop: get_node_type → write YAML → validate_policy → put_*(dry_run=true) → put_*. Payloads may be JSON objects or YAML strings. A successful put_*/delete_* is LIVE immediately — never call reload_config to 'apply' it: reload_config re-reads gateway.yaml from disk and discards live edits (it refuses unless discard_unsaved=true). With the file config source, ask the operator to persist edits to gateway.yaml (export_config gives the YAML) or they vanish on restart.
- Debugging: list_traces / get_trace / get_trace_step (context before/after a node, its exit port, the diff) and run_sandbox (execute a policy against a synthetic request). They need `debug.enabled` in system.yaml; the tools tell you if it is off. run_sandbox takes `policy` OR `nodes` plus a FLAT `context` {method, path, host, headers{name: value}, query_params{name: value}, body (text or JSON object), message{}, response{status_code, headers, body}} — never nested under `request`, `path` not `uri`, `query_params` not a query string.
- Supernodes are reusable subgraphs with input/output/error boundary nodes; `featherbit://docs/concepts/supernodes` explains the rules.
- Writing a `script` node: get_node_type(\"script\") carries the `ctx` table shape, and `featherbit://docs/guides/lua-scripting` the worked examples. Mutate the table you were given and `return ctx`; to answer the request from the script, prepare `ctx.response` and `return ctx, \"respond\"` — the node's `respond` port must be wired (to `client`, usually); headers and query params are maps of name -> array of strings (a bare string is accepted); bodies are strings. A failure names the offending field (`LUA_UNMARSHAL_ERROR`). For plain extraction — a path segment, a header, a JSON body field — prefer a `set-vars` node over a script.
- Every how-to guide is a resource: `featherbit://docs/guides/{lua-scripting,debugging,routing,configuration,tls,stream,observability,admin-api,web-ui,deployment,mcp}`.
- `${ENV_VAR}` placeholders in config are intentional and stay unresolved; never replace them with literal secrets.
- If your token is read-only, write tools are hidden (or return `forbidden`): finish by returning validated YAML for a human to apply.
Use the prompts (troubleshoot_trace, explain_trace, why_this_port, why_this_response, review_policy, design_policy, design_supernode, design_route, diagnose_route) for the common questions.";Expand description
Orientation sent to every client at initialize.