---
title: "CLI"
description: "Install and use the primitive CLI with Homebrew or npm for auth checks, sends, reads, Functions, domain workflows, and operation discovery."
canonical: "https://docs.primitive.dev/docs/cli"
last-updated: "2026-05-17T00:00:00.000Z"
---

# Primitive CLI

The `primitive` CLI is the recommended interface for agents and humans operating from a terminal. It handles auth, file inputs, command discovery, and common workflows that are awkward with raw HTTP.

## Install


```
# Homebrew
brew install primitivedotdev/tap/primitive


# npm
npm install -g @primitivedotdev/cli
```


Homebrew installs the required Node.js runtime automatically. npm installs require Node.js 22 or newer. Both install the `primitive` binary.

No-install form:


```
npx @primitivedotdev/cli@latest <command>
```


The CLI ships through the [primitivedotdev/tap](https://github.com/primitivedotdev/homebrew-tap) Homebrew tap and as [@primitivedotdev/cli](https://www.npmjs.com/package/@primitivedotdev/cli) on npm (the same build is also published unscoped as [primcli](https://www.npmjs.com/package/primcli)). Either package installs the `primitive` and `prim` binaries. The CLI is separate from the runtime SDK `@primitivedotdev/sdk`, which is imported from application code.

## Authenticate


```
primitive login
primitive whoami
```

```
curl https://api.primitive.dev/v1/account \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"
```


`primitive login` opens a browser and stores an OAuth token set locally. `whoami` verifies the current token and prints the account context visible to the CLI. To revoke the current CLI session, run:


```
primitive logout
```


You can also revoke CLI and third-party OAuth grants from **Settings -> Connected Apps**. For non-interactive automation, API keys still work by setting `PRIMITIVE_API_KEY`.

## Send Mail


```
primitive send \
  --to alice@example.com \
  --subject "Hello" \
  --body "Hi from Primitive" \
  --wait
```

```
curl -X POST https://api.primitive.dev/v1/send-mail \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"hello@your-org.primitive.email","to":"alice@example.com","subject":"Hello","body_text":"Hi from Primitive","wait":true}'
```


The CLI can infer a valid sender on the managed domain when possible.

## Read Inbound Mail


```
primitive emails:latest --limit 5
primitive emails:get-email --id <email-id>
```

```
curl "https://api.primitive.dev/v1/emails?limit=5" \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"


curl https://api.primitive.dev/v1/emails/<email-id> \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"
```


Piped table output keeps ids complete so agents can chain commands safely.

## Reply


```
primitive sending:reply-to-email \
  --id <inbound-email-id> \
  --body-text "Got it."
```

```
curl -X POST https://api.primitive.dev/v1/emails/<inbound-email-id>/reply \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"body_text":"Got it."}'
```


Primitive derives recipient and threading headers from the inbound email.

## Discover Send Permissions


```
primitive sending:get-send-permissions
```

```
curl https://api.primitive.dev/v1/send-permissions \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"
```


Run this before a first outbound send if you are unsure whether a recipient is allowed.

## Functions

Create and deploy a hosted Function:


```
primitive functions:init my-fn
cd my-fn
npm install
npm run build
primitive functions:deploy --name my-fn --file ./dist/handler.js
```

```
CODE=$(cat dist/handler.js | jq -Rs .)


curl -X POST https://api.primitive.dev/v1/functions \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"name\":\"my-fn\",\"code\":$CODE}"
```


`primitive functions:init` is local filesystem scaffolding, so the API equivalent starts when you deploy the built bundle.

Test and inspect it:


```
primitive functions:test-function --id <function-id>
primitive functions:list-function-logs --id <function-id>
```

```
curl -X POST https://api.primitive.dev/v1/functions/<function-id>/test \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"


curl https://api.primitive.dev/v1/functions/<function-id>/logs \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"
```


## Primitive Memories

Memories are durable JSON key-value records. CLI calls use org scope by default.
Pass `--function <function-id>` to use function scope; the id is the function
UUID, not the function name.


```
primitive memories set thread:latest '{"email_id":"em_123"}'
primitive memories set greeting '"hello"'
primitive memories get thread:latest
primitive memories search thread: --metadata-only
primitive memories delete thread:latest


primitive memories set state '{"step":2}' --function <function-id>
primitive memories get state --function <function-id>
```

```
curl -X PUT https://api.primitive.dev/v1/memories \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"key":"thread:latest","value":{"email_id":"em_123"}}'


curl "https://api.primitive.dev/v1/memories?key=thread:latest" \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"


curl "https://api.primitive.dev/v1/memories/search?prefix=thread:&include_value=false" \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"


curl -X DELETE "https://api.primitive.dev/v1/memories?key=thread:latest" \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"
```


Values must be valid JSON. Strings must be quoted as JSON strings, so use
`'"hello"'`, not `hello`.

See [Primitive Memories](/docs/memories) for scopes, TTLs, version checks,
search, metadata, and billing.

## Domains

Claim a domain, publish its DNS, and verify it for sending and receiving. The topic separator is a space; the colon forms (`primitive domains:add`) still resolve for back-compat.


```
primitive domains add --domain example.com
primitive domains verify --id <domain-id>
primitive domains list
primitive domains zone-file --id <domain-id> --output example.com.zone
```

```
curl -X POST https://api.primitive.dev/v1/domains \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain":"example.com"}'


curl -X POST https://api.primitive.dev/v1/domains/<domain-id>/verify \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"


curl https://api.primitive.dev/v1/domains/<domain-id>/zone-file \
  -H "Authorization: Bearer $PRIMITIVE_API_KEY"
```


`domains add` returns the exact DNS records to publish. `domains zone-file` downloads those same records as a BIND-format zone file for bulk import (pass `--domain example.com` instead of `--id` if you only have the name). `domains verify` re-checks DNS and reports which records are still missing. A domain keeps the id `domains add` returned once it verifies, so later commands take that same id. See [Receiving](/docs/receiving) for the full inbound setup walkthrough.

## More Commands

The CLI mirrors the full REST surface. Beyond the workflows above, these command groups are available:

- `primitive endpoints ...` — webhook endpoint CRUD and `test`. See [Endpoints](/docs/endpoints).

- `primitive filters ...` — allow/block filter CRUD.

- `primitive routes ...`: inbound routing rules (`add`, `list`, `test`, `update`, `reorder`, `remove`); `routes test <recipient>` simulates routing for an address. See [Routing](/docs/routing).

- `primitive chat <email> <message>` — send a message to another agent or person and wait for the threaded reply.

- `primitive signup <email>` / `primitive signup confirm <email> <code>`: provision a managed inbox with one email-verification code; the confirm step saves the issued credentials locally. See [Skills & Agent Signup](/docs/skills).

- `primitive inbox status` — consolidated inbound readiness view.

- `primitive credits redeem <code>` and `primitive credits balance`: redeem a credit code and read the organization credit balance. See [Credits](/docs/credits#redeem-a-credit-code).

Run `primitive list-operations` for the full machine-readable manifest of generated operations, and `primitive describe <operation>` for one operation's parameters and behavior.

## Operation Discovery

Agents should use CLI help and operation descriptions before guessing command shapes.


```
primitive --help
primitive list-operations
primitive describe emails:get-email
primitive describe sending:reply-to-email
```

```
curl https://api.primitive.dev/v1/openapi
```


`list-operations` is the broad machine-readable manifest. `describe` gives focused parameter and behavior details for one operation.

## Proxy Environments

On Node 22+ behind a proxy, set:


```
export NODE_USE_ENV_PROXY=1
```


Then `HTTP_PROXY` and `HTTPS_PROXY` are respected by Node networking. `primitive doctor` checks the environment.

`primitive doctor` is a local environment diagnostic. There is no REST endpoint for inspecting local proxy variables; use `primitive whoami` or the `/v1/account` request above to verify API reachability after setting them.

## Good Agent Defaults

- Run `primitive whoami` before state-changing operations.

- Prefer CLI commands for terminal workflows instead of hand-written curl.

- Use `--wait` when an immediate send result is needed.

- Use `describe` before composing unfamiliar operations.

- Never print API keys or webhook secrets in logs.

Maintained by the [primitive.dev team](/about) · [Trust & security](/trust)Last updated: May 17, 2026
