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

# nika:fetch

> Usage, declared contract and source links for this Nika builtin.

export const Ecosystem = () => <CardGroup cols={3}>
    <Card title="Documentation" icon="book" href="/introduction">
      Guides, reference contracts and working examples.
    </Card>
    <Card title="Nika Lab" icon="diagram-project" href="https://github.com/supernovae-st/nika-lab">
      Internal workspace and graph projections of the spec, documentation and code.
    </Card>
    <Card title="Language spec" icon="file-contract" href="https://github.com/supernovae-st/nika-spec">
      the nine-key envelope, Apache-2.0. The contract these docs explain.
    </Card>
    <Card title="Engine source" icon="gem" href="https://github.com/supernovae-st/nika">
      Rust, AGPL-3.0-or-later. Every commit public.
    </Card>
    <Card title="TypeScript SDK" icon="code" href="/sdk/overview">
      Use one typed lifecycle locally or against authenticated nika serve HTTP.
    </Card>
    <Card title="Editor extension" icon="puzzle-piece" href="https://marketplace.visualstudio.com/items?itemName=supernovae.nika-lang">
      VS Code · Cursor · Windsurf: check-as-you-type, DAG view, trace replay.
    </Card>
    <Card title="Homebrew tap" icon="beer-mug-empty" href="https://github.com/supernovae-st/homebrew-tap">
      `brew install supernovae-st/tap/nika` for the latest tagged CLI release.
    </Card>
    <Card title="SuperNovae" icon="star" href="https://supernovae.studio">
      The Paris studio crafting Nika. 🦋
    </Card>
  </CardGroup>;

[Builtins catalog](/reference/builtins) / `nika:fetch`

<CardGroup cols={2}>
  <Card title="Network" icon="layer-group">Tool family from the canonical registry.</Card>
  <Card title="invoke" icon="code" href="/reference/language/words/invoke">Call this builtin through the invoke verb.</Card>
</CardGroup>

## Read this contract

This reference preserves the specification at the revision linked below. Source examples are **fragments**: their surrounding tasks, inputs and permissions are not supplied here. Consult [engine status](/reference/status) and `nika catalog --tools --json` for the installed implementation; a registry declaration is not a runtime qualification.

## Usage and behavior

HTTP request + content extraction (reached via `invoke:` because fetching a URL is *calling a tool*, not a verb · see `02-verbs.md`).

```yaml illustration theme={"system"}
invoke: { tool: "nika:fetch", args: { url: "https://example.com/article", mode: article } }
```

| Arg                | Notes                                                                                                                                                                                                                                                |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`              | required · may use `${{ ... }}`                                                                                                                                                                                                                      |
| `method`           | `GET` (default) · `POST` · `PUT` · `DELETE` · `PATCH` · `HEAD`                                                                                                                                                                                       |
| `headers` · `body` | extra headers · body (objects auto-JSON) · auth rides `headers` (`x-api-key: "${{ secrets.KEY }}"` · masked)                                                                                                                                         |
| `form`             | `application/x-www-form-urlencoded` object of scalar fields (string · number · boolean — nesting refused · reshape with `nika:jq`) · body-bearing method required                                                                                    |
| `multipart`        | `multipart/form-data` parts array · `{name, value}` text XOR `{name, path, filename?, content_type?}` file · every `path` rides the `permits.fs` READ boundary (`NIKA-SEC-004` on escape) · ≤64 parts · ≤32 MiB total · body-bearing method required |
| `mode`             | extraction mode · see `extract-modes-v0.1.md` · default `markdown`                                                                                                                                                                                   |
| `jq`               | a jq expression · only with `mode: jq` (structured JSON extraction · replaces the former JSONPath mode)                                                                                                                                              |
| `traverse`         | bounded same-origin crawl · `{ max_pages: 1..=25 (required), respect_robots?: bool (default true) }` · GET only · excludes `mode`/`selector`/`jq`/`body`/`form`/`multipart`                                                                          |

**Payload exclusivity (normative)** · at most ONE of `body` · `form` ·
`multipart`; `form`/`multipart` require a body-bearing method (`POST` ·
`PUT` · `PATCH`) and OWN their `content-type` (a user-supplied
`content-type` header alongside them is a refused conflict).

**The data-as-code sink (normative pointer · NEP-0006)** · a fetch whose
resolved URL path names a code-bearing class (serialized-executable ·
script/interpreter · executable binary/module · the closed list in
`10-authority.md` §the data-as-code sink) is refused at check
(`NIKA-SEC-008`) and at run (`NIKA-SEC-004`) unless the task declares the
read inert (`lift: [{law: data-as-code, because: "…"}]` · the honest
door · it never lifts the host boundary or the SSRF floor).

**`traverse` semantics (normative)** · same-origin BFS from `url` ·
fragment-stripped dedup · per-page output is the fixed page digest
`&#123;url, status, title, description, headings ≤16, links ≤30, images ≤24,
colors ≤20, text ≤4000&#125;` · crawl output is `&#123;url, page_count, pages[],
assets: &#123;images ≤40, colors ≤30&#125;&#125;` · `robots.txt` honored by default
(RFC 9309 group semantics · `User-agent: *` `Disallow` prefixes · the
probe's outcome follows RFC 9309 §2.3.1: a 4xx is *unavailable* and
allow-all · a 5xx or a transport failure is *unreachable* and a COMPLETE
DISALLOW, refused loudly and transiently before a page is spent · rules
are per origin, so a root that lands on another origin re-reads that
origin's robots before any descendant is enqueued · a disallowed ROOT is
a loud failure · disallowed descendants are silently skipped) · the page
digest passes the same depth admission every HTML mode passes (a
depth-bomb root is a loud failure · a depth-bomb descendant is an honest
`{url, status, error}` entry) · discovery reads every link a page
carries (the `links ≤30` facet is a preview, never the frontier's bound)
· every hop rides
the engine's SSRF defense · a failing descendant page becomes an honest
`{url, status|error}` entry and the crawl continues · the effect
certificate bounds logical GET calls per invocation: `max_pages` with
literal `respect_robots: false`, otherwise `max_pages + 2` (the seed's
robots, then at most one probe of the landed root's different origin).
An unchanged origin needs only one robots probe, but a literal initial
URL and the same-origin link filter do not exclude a root redirect;
an unknown final origin therefore requires the two-probe bound. Dynamic
page bounds use the valid runtime maximum 25, hence at most 27 logical
GETs (25 with literal robots false); dynamic robots options reserve both
probes. Invalid resolved options still refuse before any GET. These are
logical calls, not a bound on physical transmissions, redirect hops or
transport retries; aggregate saturation is not a proven global bound.
`crawl`/`http`/`website` are intentions, not
tools — they all route HERE (no `nika:crawl`).

**Non-2xx is failure (normative)** · a non-2xx response throws
`NIKA-BUILTIN-FETCH-001` (`category: network_error` · `transient: true` for
5xx/408/429 · `false` for other 4xx · `details.status_code` carries the
status) — **with the effect-safe carve-out (normative · issue #1371)**: a
keyless effect-capable method (`POST` · `PUT` · `DELETE` · `PATCH` without
an `idempotency-key` header) is `transient: false` on EVERY failure,
status-table and transport alike — the failure may be ambiguous (the
server may have committed before the socket dropped or the error was
emitted) and a blind retry replays the effect; a declared `retry:` on such
a call is the static `NIKA-SEC-016` refusal ([05 §the effect-safe retry
law](https://github.com/supernovae-st/nika-spec/blob/f8c5df2127c7867b2e51a2cd5712fa9d8461e73e/spec/05-errors.md#the-effect-safe-retry-law-normative--issue-1371)).
`GET`/`HEAD` and keyed calls keep the status table.
To poll a pending resource · the jq-error pattern
([08 H19](https://github.com/supernovae-st/nika-spec/blob/f8c5df2127c7867b2e51a2cd5712fa9d8461e73e/spec/08-out-of-scope.md)), not status-code inspection.
Redirects follow up to an engine cap · the FINAL status decides.

**Security (engine MUST)** · SSRF defense (reject private-net + cloud-metadata `169.254.169.254` unless configured) · honor task-level `timeout` · reject self-signed TLS by default.

## Related concepts

<CardGroup cols={2}>
  <Card title="Arguments" icon="sliders" href="/reference/language/words/args">Pass the values required by the tool contract.</Card>
  <Card title="Permissions" icon="shield" href="/concepts/security">Understand authority before granting effects.</Card>
  <Card title="Errors and recovery" icon="rotate" href="/reference/error-codes">Read diagnostics and choose a recovery policy.</Card>
  <Card title="Workflow templates" icon="file-code" href="/guides/templates">Put the fragment inside a complete workflow.</Card>
</CardGroup>

## Contract provenance

[Read the pinned specification](https://github.com/supernovae-st/nika-spec/blob/f8c5df2127c7867b2e51a2cd5712fa9d8461e73e/stdlib/builtins-v0.1.md#L353) · [Canonical registry](https://github.com/supernovae-st/nika-spec/blob/f8c5df2127c7867b2e51a2cd5712fa9d8461e73e/canon/builtins.yaml).

Tool identity: `nika:fetch`. Specification revision: `f8c5df2127c7`.
The Lab language identity is `language:tool:fetch`; the registry view is `ecosystem:tool/nika:fetch`. They refer to this contract without merging their graph identities.

<Ecosystem />
