Skip to main content

CLI

@naturali/cli gives every API operation a command, generated from the OpenAPI specs. An endpoint that exists in the contract is reachable from the shell; one that doesn't, isn't.

pnpm add -g @naturali/cli
export NATURALI_TOKEN=nat_sk_...
naturali list-agents --project-id proj_V1StGXR8Z5jdHi6B

The CLI always talks to https://api.naturali.ai — the only naturali.ai API origin, and not configurable.

Configuration

Credentials and the default project both come from the environment:

VariablePurpose
NATURALI_TOKENBearer credential — a nat_sk_… API key or a session JWT. Required.
NATURALI_PROJECTDefault --project-id for any command that takes one, so you don't have to repeat it. An explicit --project-id still wins.
export NATURALI_TOKEN=nat_sk_...
export NATURALI_PROJECT=proj_V1StGXR8Z5jdHi6B

naturali list-agents

Discovering commands

A command is its operationId in kebab-case — createAgentcreate-agent.

naturali list-commands # every command, with its description
naturali create-agent --help # a command's flags, grouped, plus its docs link

--help lists each flag with its type, whether it is required, and whether the value lands in the URL path, the query string, or the request body — read straight from the spec.

Flags

Flag names are the spec's parameter names. Kebab-case is the convention used throughout these docs, and snake_case and camelCase are accepted too: --project-id, --project_id and --projectId are one flag.

naturali list-agents --project-id proj_V1StGXR8Z5jdHi6B --limit 10

naturali create-agent \
--project-id proj_V1StGXR8Z5jdHi6B \
--provider-id aip_V1StGXR8Z5jdHi6B \
--name support-triage \
--tool-bindings '[{"tool_id":"tool_V1StGXR8Z5jdHi6B"}]'
Value kindHow to pass it
String--name support-triage
Number--temperature 0.7
Boolean--force — a bare flag means true
Object--tool-choice '{"type":"tool","name":"get_weather"}'
Arrayrepeat the flag (--capabilities a --capabilities b) or pass JSON (--tool-bindings '[{"tool_id":"tool_a"}]')

An array-typed field always reaches the API as a list, even with a single value.

Every path parameter a command needs must be passed explicitly — a command that leaves one out stops and names it rather than guessing:

$ naturali get-agent --agent-id agent_V1StGXR8Z5jdHi6B
Missing required path parameter(s): project_id.
Provide with --project-id <value>.

Output

The response body goes to stdout as formatted JSON, ready for jq:

naturali list-agents --project-id proj_V1StGXR8Z5jdHi6B | jq -r '.data[].id'

A non-2xx response prints the error envelope to stderr and exits 1, so a failing command fails a shell script:

{
"status": 403,
"error": { "code": "access_denied", "message": "Not your project" }
}

Scripting example

Create an agent, open a session, and ask it something:

set -euo pipefail
export NATURALI_TOKEN=nat_sk_...

PROJECT_ID=proj_V1StGXR8Z5jdHi6B

AGENT_ID=$(naturali create-agent \
--project-id "$PROJECT_ID" \
--provider-id aip_V1StGXR8Z5jdHi6B \
--name support-triage | jq -r '.id')

SESSION_ID=$(naturali create-session \
--project-id "$PROJECT_ID" \
--agent-id "$AGENT_ID" | jq -r '.id')

naturali add-session-message \
--project-id "$PROJECT_ID" \
--agent-id "$AGENT_ID" \
--session-id "$SESSION_ID" \
--message 'What is our refund window?'

Versioning

@naturali/cli shares its version with the API and with @naturali/sdk — one number, released together. The CLI is generated from the API's OpenAPI specs and bundles the SDK at build time, so @naturali/cli@0.28.0 speaks to API 0.28.0 and pulls in no separate client at runtime.

A consequence worth knowing: a bump can mean the API gained a command, not that anything in the CLI's own behaviour changed. naturali --help is generated from the specs the release was built from, so it is always the authority on what the version you installed can do.