# Formant CLI (`formant`)

**The official command-line interface for [Formant](https://formant.io) — a cloud platform for monitoring, operating, and analyzing robot fleets at scale.**

Formant helps robotics teams observe, troubleshoot, and control their robots in production. With `formant`, you can manage your entire fleet from the terminal: query telemetry, trigger AI-powered investigations, delegate tasks to AI personas, send remote commands, manage users and permissions, and automate workflows.

## What is Formant?

[Formant](https://formant.io) is a cloud observability and operations platform designed specifically for robotics. It provides:

- **Real-time monitoring** — Live telemetry streams (battery, sensors, cameras, logs) from all your robots
- **Event tracking** — Automatic detection and alerting of critical issues (crashes, errors, anomalies)
- **AI-powered investigations** — Intelligent root cause analysis that diagnoses problems automatically
- **AI personas** — Configurable AI agents with tools for async task delegation
- **Remote operations** — Send commands, trigger actions, and control robots from anywhere
- **Fleet management** — Organize devices by location, type, or purpose; manage user permissions
- **Analytics & reporting** — Query historical data with SQL to understand performance trends

## Features

This CLI provides programmatic access to all Formant capabilities:

### Device Management
- List, create, rename, and delete robots/sensors
- Add tags for organization (environment, location, customer)
- View real-time device status and configuration
- List available telemetry streams with per-stream data presence (datapoint counts, last seen, freshness)
- Data-based last seen timestamps and datapoint counts on device listings
- Filter to devices that have ingested data (`--with-data`)
- Search by name across **all** devices (online and offline) with `--name`; repeat the flag for multiple names

### Telemetry Queries
- Query historical sensor data (battery, temperature, position, custom metrics)
- Retrieve latest values with `--latest-values-only`
- Auto-discover all streams with `--all-streams`
- Filter by time range, device, and stream type
- Export data as JSON for analysis

### Telemetry Ingestion
- Send numeric, text, JSON, image, video, bitset, and health data to devices
- Add tags and custom timestamps to telemetry points
- Batch upload multiple data points in a single request
- Programmatically populate device streams from scripts and automation

### Event Monitoring
- View events filtered by severity (info, warning, critical, error)
- Track device online/offline status
- Investigate alert history for troubleshooting
- Filter events by device, time range, or type

### AI Personas
- List available AI personas and their configurations
- View persona details including integrations and available tools
- Delegate async tasks to personas (fire-and-forget)
- Check task status and results

### AI Investigations
- List available investigation workflows
- Trigger investigations manually with custom input
- View investigation runs, execution logs, and results
- Get investigation statistics and success rates
- Trace investigations back to their triggering signals

### Signal Management & Ground Truth
- Create manual signals for testing and evaluation
- List and query signals (investigation triggers)
- Assign ground truth (expected outcomes) to signals for evaluation
- View signals with their ground truth annotations
- Count signals by type
- Trace the workflow: Signal -> Investigation -> Run -> Result

### Remote Commands
- List available command templates for your fleet
- Send commands to individual devices with parameters
- View command execution history
- Check command delivery status

### Event Triggers (Automation)
- View configured trigger rules
- Understand what conditions create events and signals
- See trigger configuration (thresholds, exit conditions, device scope)

### User & Organization Management
- View organization details (plan, retention, support tier)
- Update organization name and description
- List all users and their roles
- Inspect user permissions and account status

### Fleet & Group Management
- Create logical groups of devices (by location, project, customer)
- List all fleets and their member devices
- Organize your fleet for easier management

### Scheduled Tasks
- View scheduled investigations and commands
- Understand recurring workflows and automation

### Analytics & SQL
- Execute custom SQL queries against your analytics database
- List available tables and schemas
- Analyze fleet performance, uptime, and trends

### Schema Introspection
- Export machine-readable command schemas from the CLI itself
- Filter by topic or command for agent/tool integration
- Validate args/flags/options/exclusivity before execution

### Snowflake Data Loading
- Define named external stages pointing to S3 buckets
- Create tables directly from CSV files (local or S3-staged) using `INFER_SCHEMA` with relaxed types
- Load CSV files into Snowflake tables from local paths or S3 stages via COPY INTO
- List load history for any table using native COPY_HISTORY
- Check status of a load by query ID
- Cancel in-progress queries

### Key-Value Metadata Store
- Store custom metadata per device
- Retrieve configuration values
- Update device-specific settings

## Installation

### npm

```bash
npm install -g @formant/formant-cli
```

### Yarn

```bash
yarn global add @formant/formant-cli
```

### pnpm

```bash
pnpm add -g @formant/formant-cli
```

After installation, verify it works:

```bash
formant --help
```

## Tool Integration Setup (Cowork, Claude, Codex, Gemini)

This repository's primary distribution goal is:
- Formant CLI commands (`formant`)
- packaged skills/plugins for Cowork, Claude, Codex, and Gemini

### 1) Build all integration artifacts

From repo root:

```bash
npm run agents:package
```

This generates:
- `dist/formant-admin.plugin`
- `dist/agent-integrations/claude-skill-pack`
- `dist/agent-integrations/codex-skill-pack`
- `dist/agent-integrations/gemini-workspace-pack`
- `dist/agent-integrations/gemini-extension-formant-admin`

Note: `npm run smoke:ci` runs a fresh build (`npm run build`) and clears `dist/`.  
Run packaging (`agents:package` / `plugin:package`) after smoke checks.

### 2) Cowork / Claude plugin import

- Artifact: `dist/formant-admin.plugin`
- Import this file into Cowork plugin manager / Claude plugin tooling.

Plugin source:
- `cowork/formant-admin/`

### 3) Claude standalone workspace setup (skills + /check command)

Copy the Claude bundle into your target workspace root:

```bash
cp -R dist/agent-integrations/claude-skill-pack/. /path/to/workspace/
```

This installs:
- `.claude/skills/*`
- `.claude/commands/check.md`
- `CLAUDE.md`

### 4) Codex Desktop workspace setup

Copy the Codex bundle into your target workspace root:

```bash
cp -R dist/agent-integrations/codex-skill-pack/. /path/to/workspace/
```

This installs:
- `.codex/skills/*`
- `AGENTS.md`

If your Codex runtime expects `.agents/skills` instead, copy skill folders there and keep `AGENTS.md` at workspace root.

### 5) Gemini workspace setup

Copy the Gemini workspace bundle into your target workspace root:

```bash
cp -R dist/agent-integrations/gemini-workspace-pack/. /path/to/workspace/
```

This installs:
- `.gemini/skills/*`
- `.gemini/commands/formant/check.toml`
- `GEMINI.md`

### 6) Gemini extension install

```bash
gemini extensions install dist/agent-integrations/gemini-extension-formant-admin
```

### 7) Post-install validation (all runtimes)

Run these in the target workspace:

```bash
formant --help
formant auth status --json
formant org get --json
formant schema commands --json
```

Detailed packaging/distribution notes:
- `docs/agent-integration-distribution.md`
- `cowork/formant-admin/README.md`

## Authentication

Formant CLI uses **service account credentials** for authentication. You'll need to create a service account in your Formant organization first.

### Creating a Service Account

1. Log in to [Formant](https://app.formant.io)
2. Go to **Settings** -> **Users**
3. Click **Create Service Account**
4. Copy the generated email and password

### Setting Credentials

Formant CLI supports two credential sources:

1. **Stored defaults (recommended for npm/homebrew installs)**  
   Save credentials once and reuse them from any directory:

```bash
formant auth login --user "your-service-account@org.iam.formant.io" --password "your-password"
formant auth status
```

Stored credentials are saved at:
- macOS/Linux: `~/.config/formant/credentials.json`
- Windows: `%APPDATA%\\formant\\credentials.json`

2. **Environment variables**  
   Use for local/session-level credentials or one-off overrides:

```bash
export FORMANT_USER="your-service-account@org.iam.formant.io"
export FORMANT_PASSWORD="your-password"
```

Or create a `.env` file in your project:

```env
FORMANT_USER=your-service-account@org.iam.formant.io
FORMANT_PASSWORD=your-password
```

The CLI will automatically load credentials from your `.env` file.

### Credential Precedence

1. `FORMANT_USER` + `FORMANT_PASSWORD` (environment / `.env`)
2. Stored defaults from `formant auth login`

For commands that accept explicit credential flags (`--user`, `--password`), inline flag values override environment values.

This means you can keep defaults on the machine, then override per request:

```bash
FORMANT_USER="override@org.iam.formant.io" FORMANT_PASSWORD="override-password" formant org get --json
```

## Quick Start

```bash
# View your organization (singleton; no "org list")
# JSON/TOON are minimal by default; add --full for complete payloads
formant org

# List devices with data
formant device list --with-data --dev

# Look up a device by name (searches all devices, online + offline)
formant device list --name "mech-0" --dev --toon
formant device list --name "mech-0" --name "mech-1" --dev --toon

# Get device details
formant device get <device-id> --dev

# Query battery telemetry over the last day
formant query --device <device-id> --stream battery_level \
  --start 2026-02-17 --end 2026-02-18 --dev

# View recent critical events
formant event list --severity critical --limit 20 --dev

# List AI personas and delegate a task
formant persona list --dev
formant persona delegate-task <persona-id> "Analyze recent device failures" --dev
formant persona task-status <task-id> --dev

# List all investigations
formant investigation list --dev

# Send a command to a robot
formant command send <device-id> <template-id> --param speed=5 --dev
```

## Command Reference

### Organization

View your Formant account settings. This is a singleton resource.

```bash
formant org                                       # Shorthand: view organization details
formant org get                                   # Explicit equivalent
```

### Device

Create, list, and manage robots/sensors in your fleet.

```bash
# Listing and filtering
formant device list                               # Online devices (default)
formant device list --include-offline             # Include offline devices
formant device list --with-data                   # Only devices with ingested data
formant device list --with-data --days 90         # Widen the search window (default: 30d)
formant device list --tag location=warehouse      # Filter by tag
formant device list --name "mech-0"               # Search all devices by name (online + offline)
formant device list --name "mech-0" --name "mech-1"  # Multiple names (parallel queries, merged)

# Device details
formant device get <device-id>                    # Get full device details
formant device config <device-id>                 # Get device configuration

# Stream discovery with data presence
formant device streams <device-id>                # List streams with datapoint counts,
                                               # last seen (ISO), and freshness
formant device streams <device-id> --days 30      # Adjust presence lookback (default: 7d)

# Device management
formant device create "robot-001"                 # Create a new device
formant device rename <device-id> "new-name"      # Rename a device
formant device disable <device-id>                # Disable a device

# Tagging
formant device tag <device-id> --tag env=prod            # Add/update tag
formant device untag <device-id> --key env               # Remove tag
```

### Event

View and filter important events emitted by your devices.

```bash
formant event list                                # List all recent events
formant event list --device <device-id>           # Events for one device
formant event list --severity critical            # Filter by severity
formant event list --limit 50                     # Limit results
formant event list --start 2026-01-01             # Filter by date range
formant event get <event-id>                      # Get event details
```

**Severity levels:** `info`, `warning`, `error`, `critical`

### Query

Retrieve historical telemetry and sensor data. `--start` and `--end` are always required.

```bash
# Historical data
formant query --device <device-id> --stream battery_level \
  --start 2026-01-01 --end 2026-01-02

# Multiple streams in one query
formant query --device <device-id> --stream heat.current --stream power.available \
  --start 2026-02-01 --end 2026-02-20

# Multiple devices in one query
formant query --device <id1> --device <id2> --stream battery_level \
  --start 2026-02-01 --end 2026-02-20

# Aggregated data (downsample to hourly)
formant query --device <device-id> --stream temperature \
  --start 2026-01-01 --end 2026-02-01 --aggregate hour

# Latest value per stream (within the time range)
formant query --device <device-id> --stream battery_level \
  --start 2026-01-01 --end 2026-02-01 --latest-values-only

# Auto-discover and query all streams on a device
formant query --device <device-id> --all-streams \
  --start 2026-01-01 --end 2026-02-01 --latest-values-only

# Common streams: battery_level, temperature, cpu_usage, memory_usage, location
```

### Ingest

Send telemetry data to devices via the Formant ingestion API.

```bash
# Numeric data
formant ingest numeric 42.5 --device <device-id> --stream battery_level
formant ingest numeric 23.8 --device <device-id> --stream temperature --tag location=warehouse

# Text data
formant ingest text "System operational" --device <device-id> --stream status
formant ingest text "Low battery warning" --device <device-id> --stream alerts --tag severity=warning

# JSON data
formant ingest json '{"x":10,"y":20}' --device <device-id> --stream position

# Image data
formant ingest image https://example.com/camera.jpg --device <device-id> --stream camera_front

# Video data
formant ingest video https://example.com/recording.mp4 --device <device-id> --stream camera_feed --duration 30000

# Bitset data (multiple boolean key-value pairs)
formant ingest bitset --device <device-id> --stream sensors \
  --keys motor_on,door_open,battery_charging \
  --values true,false,true

# Health status
formant ingest health --device <device-id> --stream health_status --status operational

# Batch ingestion (multiple items from JSON file or stdin)
formant ingest batch --file payload.json
cat batch.json | formant ingest batch --stdin
```

**Common flags for all ingest commands:**
- `--device <id>` - Target device ID (required)
- `--stream <name>` - Stream name (required)
- `--tag key=value` - Add tags as string key-value pairs (repeatable)
- `--timestamp <ms>` - Unix timestamp in milliseconds (defaults to current time)

**Health status values:** `unknown`, `operational`, `offline`, `error`

### Persona

Manage AI personas and delegate async tasks.

```bash
# Listing and details
formant persona list                              # List all personas
formant persona get <persona-id>                  # View persona details and tools

# Async task delegation
formant persona delegate-task <persona-id> "Analyze recent device failures"
formant persona delegate-task <persona-id> "Generate a daily report" --name "Daily Report"
formant persona task-status <task-id>             # Check task status and results

# Conversational chat threads
formant persona chat start <persona-id> --name "Ops triage"
formant persona chat send <thread-id> "Summarize current fleet issues"
formant persona chat send <thread-id> "Continue with remediation plan" --async
formant persona chat poll <thread-id> --wait --after 2026-01-01T00:00:00Z
formant persona chat history <thread-id> --limit 20
formant persona chat switch-persona <thread-id> <persona-id>
```

The `delegate-task` command creates a task, assigns it to the persona, and queues it for
async execution. It returns immediately with a task ID. Use `task-status` to check progress.

### Investigation

Trigger and monitor AI-powered analysis workflows that diagnose device issues.

```bash
# Listing
formant investigation list                        # List all investigations
formant investigation get <investigation-id>      # Get investigation details

# Definition lifecycle
formant investigation create --file investigation.json
formant investigation update <investigation-id> --file update.json
formant investigation delete <investigation-id>

# Version lifecycle
formant investigation version-list <investigation-id>
formant investigation version-get <investigation-id> <version-number>
formant investigation version-create <investigation-id> --label "baseline"
formant investigation version-restore <investigation-id> <version-number>
formant investigation version-delete <investigation-id> <version-number>

# Triggering
formant investigation trigger <id> --input "Robot stopped responding"

# Runs
formant investigation runs <investigation-id>     # List all runs
formant investigation run <inv-id> <run-id>       # Get run details & logs

# Analytics
formant investigation stats --start 2026-01-01    # Get metrics
formant investigation analytics <investigation-id> # Get investigation analytics
```

### Signal

Signals are points of interest (from events, schedules, or manual triggers) that start investigations.
You can create signals manually and assign ground truth (expected outcomes) for evaluation.

```bash
# Listing and querying
formant signal list                               # List all signals
formant signal list --investigation <inv-id>      # List with ground truth annotations
formant signal query --start 2026-01-01 --end 2026-02-01 # Query by time
formant signal count                              # Count signals by type
formant signal get <signal-id>                    # Get signal details

# Creating signals
formant signal create "Motor overheated on device X"
formant signal create "Sensor fault" --device <device-id>
formant signal create "Test scenario" --investigation <inv-id> \
  --ground-truth "Should detect thermal issue"

# Ground truth (expected outcomes for evaluation)
formant signal set-ground-truth <signal-id> <investigation-id> "Expected outcome text"
```

### Command

Send remote commands to devices and view execution history.

```bash
formant command list                              # List all command templates
formant command get <command-id>                  # Get template details
formant command for-device <device-id>            # Commands available for device
formant command send <device-id> <template-id> --param key=value # Send command
formant command history --device <device-id>      # View command history
```

### Event Trigger

View automated trigger rules that generate events and signals based on device conditions.

```bash
formant event-trigger list                        # List all trigger rules
formant event-trigger get <trigger-id>            # Get trigger configuration
```

### User

Manage users in your organization.

```bash
formant user list                                 # List all users
formant user get <user-id>                        # Get user details
```

### Fleet

Organize devices into logical groups (by location, type, project, customer).

```bash
formant fleet list                                # List all fleets
formant fleet get <fleet-id>                      # Get fleet details
```

### Schedule

View recurring tasks and one-time scheduled jobs.

```bash
formant schedule list                             # List all schedules
formant schedule get <schedule-id>                # Get schedule details
```

### Analytics

Execute custom SQL queries against your Formant analytics database.

```bash
formant analytics tables                          # List available tables
formant analytics query --sql "SELECT * FROM events WHERE severity='critical' LIMIT 10"
```

### Schema

Inspect machine-readable CLI command schemas for tooling and agents.

```bash
formant schema commands --json                           # All command schemas
formant schema commands --topic device --json            # Filter by topic
formant schema commands --command "device list" --json   # One command
formant schema commands --command "device list" --json | jq '.commands[0].output'
formant schema operations --json                         # Backend operation contracts
formant schema operation admin.channels.create --json    # One backend operation contract
```

### Key-Value Store

Store and retrieve custom metadata for devices.

```bash
formant kv list                                   # List all keys
formant kv get <key>                              # Get value
formant kv set <key> <json-value>                 # Set value
formant kv delete <key>                           # Delete key
```

### Snowflake

Load CSV files into Snowflake tables and manage load history. Commands connect
directly to Snowflake using credentials from environment variables (or `.env`).
The `--dev` / `--stage` environment flags do not apply to Snowflake commands —
connection targets are controlled entirely by environment variables.

#### Authentication

Three authentication methods are supported (in priority order):

**Programmatic Access Token (PAT)** — recommended when MFA is enabled:
```env
SNOWFLAKE_ACCOUNT=myorg-myaccount          # identifier only — no .snowflakecomputing.com
SNOWFLAKE_USER=your-snowflake-user
SNOWFLAKE_TOKEN=your-pat-token
```

**Key-pair / JWT**:
```env
SNOWFLAKE_ACCOUNT=myorg-myaccount
SNOWFLAKE_USER=your-snowflake-user
SNOWFLAKE_PRIVATE_KEY_PATH=/path/to/rsa_key.p8
SNOWFLAKE_PRIVATE_KEY_PASS=optional-passphrase
```

**Username / password** (not compatible with MFA):
```env
SNOWFLAKE_ACCOUNT=myorg-myaccount
SNOWFLAKE_USER=your-snowflake-user
SNOWFLAKE_PASSWORD=your-snowflake-password
```

Optional session defaults (all can be overridden per-command with `--warehouse`
or inferred from `--table`):
```env
SNOWFLAKE_WAREHOUSE=COMPUTE_WH
SNOWFLAKE_DATABASE=MY_DATABASE
SNOWFLAKE_SCHEMA=PUBLIC
```

#### Commands

```bash
# Define a named external stage pointing to S3
# Use --aws-key/--aws-secret, or AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY env vars,
# or --storage-integration for a pre-configured Snowflake storage integration
formant snowflake create-stage my_stage --url s3://my-bucket/data/ \
  --aws-key AKIA... --aws-secret ...
formant snowflake create-stage my_stage --url s3://my-bucket/data/ \
  --storage-integration MY_S3_INT --replace

# Infer schema and create a table — from a local file or an S3 stage
# Use --dry-run to preview the DDL without executing
formant snowflake create-table data.csv --table mydb.public.orders --dry-run
formant snowflake create-table data.csv --table mydb.public.orders
formant snowflake create-table data.csv --table mydb.public.orders --if-not-exists
formant snowflake create-table @my_stage/data.csv --table mydb.public.orders

# Load a CSV — from a local file or an S3 stage
# Local file is PUT to an internal stage first; S3 stage references skip the upload
formant snowflake load data.csv --table mydb.public.orders
formant snowflake load data.csv --table mydb.public.orders --field-delimiter "\t"
formant snowflake load @my_stage/2026/orders.csv --table mydb.public.orders
formant snowflake load @my_stage/ --table mydb.public.orders --pattern ".*\\.csv"

# List recent load history for a table (last 7 days, 20 records)
formant snowflake list --table mydb.public.orders
formant snowflake list --table mydb.public.orders --limit 50 --since 30

# Get details for a specific query/load by query ID
formant snowflake status 01b234cd-0000-abcd-0001-000000000001

# Cancel a running query
formant snowflake cancel 01b234cd-0000-abcd-0001-000000000001
```

Add `--verbose` to any snowflake command to print each SQL statement to stderr
as it is executed — useful for debugging connection and permission issues:

```bash
formant snowflake list --table mydb.public.orders --verbose
# [snowflake] USE WAREHOUSE "COMPUTE_WH"
# [snowflake] USE DATABASE "MYDB"
# [snowflake] USE SCHEMA "PUBLIC"
# [snowflake] SELECT FILE_NAME, STATUS ...
```

The `create-stage` command defines a named external stage that `load` and
`create-table` can reference directly using `@stage_name/path` syntax — no local
file upload needed. AWS credentials are read from `--aws-key`/`--aws-secret` flags
or `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` env vars.

The `create-table` command relaxes the strict types that `INFER_SCHEMA` produces:

| Inferred type     | Created as                      |
|-------------------|---------------------------------|
| `TIMESTAMP*`      | `TIMESTAMP_NTZ`                 |
| `TEXT` (timestamp column name) | `TIMESTAMP_NTZ`    |
| `NUMBER(n,0)`     | `/* NUMBER(n,0) */ INTEGER`     |
| `NUMBER(n,1–3)`   | `/* NUMBER(n,1) */ FLOAT`       |
| `NUMBER(n,4+)`    | `/* NUMBER(n,4) */ DOUBLE`      |

The original inferred type is kept as a SQL comment for reference.

The `load` command prints the query ID on completion — pass it to `status` to
inspect results or `cancel` to abort an in-progress operation.

All commands support `--json` and `--toon` output:

```bash
formant snowflake load data.csv --table mydb.public.orders --json
formant snowflake list --table mydb.public.orders --json
```

## Global Flags

These flags work with any command:

- `--dev` — Target the dev environment (for testing; not applicable to `snowflake` commands)
- `--stage` — Target the stage environment (for staging; not applicable to `snowflake` commands)
- `--json` — Output minimal machine-readable JSON (projected fields)
- `--toon` — Output minimal machine-readable TOON (projected fields)
- `--field <path>` — Include additional field path(s) in JSON/TOON output (repeatable)
- `--full` — Disable projection and return full API payloads in JSON/TOON output
- `-h, --help` — Show help for any command

**Default environment:** Production (unless `--dev` or `--stage` is specified)

## Output Formats

### Table (default)

Human-readable tables optimized for terminal viewing:

```bash
$ formant device list --with-data --dev

Devices — with data (dev):

NAME                    ID                                      ONLINE  TYPE      LAST SEEN (30D)             DATAPOINTS (30D)
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
carter.1                a8840212-a0a4-4d0b-8a47-098563894748    false   default   2026-02-19T19:05:37.536Z    720156
DJI Matrice 4E          10f78fd5-c00d-42d9-94c4-b310646f59be    false   default   2026-02-18T01:17:41.167Z    917051
```

```bash
$ formant device streams <device-id> --dev

Device Streams (dev):

  Device: Walt (020e59a1-...)
  Configured: 10  |  Discovered from data: 34
  Presence (last 7d): 0 active, 32 recent, 0 stale, 0 dormant, 12 no data

NAME                              TYPE          SOURCE  DATAPOINTS  LAST SEEN                 FRESHNESS
spot.robot_state.battery          numeric       data    20195       2026-02-19T23:37:01.281Z  recent
spot.localization                 text          data    16962       2026-02-19T23:37:01.271Z  recent
spot.hand.image                   custom        config  —           —                         —
```

```bash
$ formant query --device <device-id> --stream heat.current --stream power.available \
    --start 2026-02-01 --end 2026-02-20 --dev

Telemetry Data (dev environment):

  Stream: heat.current (numeric)  Device: 01397354-d17a-4b53-ac27-61753de7918c
  Points: 1

TIME                        VALUE
──────────────────────────────────────────────────────────────────────────────
2026-02-18T21:15:38.491Z    47

  Stream: power.available (numeric)  Device: 01397354-d17a-4b53-ac27-61753de7918c
  Points: 1

TIME                        VALUE
──────────────────────────────────────────────────────────────────────────────
2026-02-18T21:15:38.520Z    72
```

### JSON

Machine-readable JSON for scripting and automation. By default, JSON output is
minimal and command-specific (optimized for direct operations and agent use).

```bash
$ formant device list --with-data --dev --json
{
  "items": [
    {
      "id": "a8840212-...",
      "name": "carter.1",
      "online": false,
      "last_seen": "2026-02-19T19:05:37.536Z",
      "datapoints": 720156
    }
  ]
}
```

Request additional fields as needed:

```bash
formant org get --json --field flags --field billingInfo
formant device get <device-id> --json --field state.ros.topics
```

Return the full backend payload when needed:

```bash
formant device list --include-offline --json --full
```

Use with `jq` for advanced processing:

```bash
formant device list --json | jq '.items[] | select(.online==true) | .name'
```

### TOON

**`--toon` is the recommended output format when working with AI tools, LLM prompts, or any context where token efficiency matters.**

TOON (Token-Oriented Object Notation) is a compact, schema-aware encoding of
structured data that is both human-readable and significantly more token-efficient
than JSON. Like `--json`, TOON output is projected to minimal fields by default.

```bash
$ formant org get --toon
name: Acme Robotics
id: 6380a48c-0847-4543-a67f-9b7ccc41ec21
plan: paid
daysDataRetained: 600
enabled: true
updatedAt: 2026-02-23T20:17:06.225Z
```

```bash
$ formant user list --toon
items[2]{id,email,firstName,lastName,enabled}:
  4f79f32b-...,alice@acme.io,Alice,Smith,true
  9a1c22de-...,bob@acme.io,Bob,Jones,true
```

Key properties of TOON output:

- **Arrays are schema-compressed** — `items[N]{field1,field2,...}:` header followed by rows, rather than repeating field names for every object
- **Scalars are unquoted** — only strings with special characters are quoted
- **Nested objects are indented** — structure is preserved but without JSON's punctuation overhead
- **Null and boolean values are compact** — `null`, `true`, `false` without quotes

**When to use `--toon` vs `--json`:**

| Use case | Recommended flag |
|---|---|
| Pasting into an LLM prompt | `--toon` |
| AI agent / agentic scripting | `--toon` |
| Shell scripting with `jq` | `--json` |
| Saving to a file for later processing | `--json` |
| Quick human inspection | (default) |

```bash
# Pipe directly into an LLM context or agent prompt
formant device list --toon
formant event list --severity critical --toon
formant investigation runs <id> --toon
formant org get --toon
```

## Examples

### Monitor fleet health

```bash
# Find devices that have data
formant device list --with-data

# Find devices with data, wider search window
formant device list --with-data --days 90

# Check which devices are offline
formant device list --include-offline --json | jq '.items[] | select(.online==false) | .name'

# View recent critical events across the fleet
formant event list --severity critical --limit 50

# Discover what streams a device has and their data freshness
formant device streams <device-id>
```

### Delegate a task to an AI persona

```bash
# List available personas
formant persona list

# Delegate an async task
formant persona delegate-task <persona-id> "Check all offline devices and summarize issues"

# Check the result
formant persona task-status <task-id>
```

### Investigate a device issue

```bash
# 1. View recent events for the device
formant event list --device <device-id> --limit 20

# 2. Trigger an investigation
formant investigation trigger <investigation-id> --input "Device stopped responding"

# 3. Check investigation runs
formant investigation runs <investigation-id>

# 4. Query relevant telemetry (multiple streams and/or devices at once)
formant query --device <device-id> --stream temperature --stream battery_level \
  --start 2026-02-17T10:00:00Z --end 2026-02-17T12:00:00Z
```

### Automate fleet operations

```bash
# Tag all production devices
for device in $(formant device list --json | jq -r '.items[].id'); do
  formant device tag $device --key environment --value production
done

# Send command to all devices in a fleet
for device in $(formant fleet get <fleet-id> --json | jq -r '.devices[].id'); do
  formant command send $device <template-id> --param mode=standby
done
```

### Export data for analysis

```bash
# Export all critical events to JSON
formant event list --severity critical --limit 1000 --json > critical_events.json

# Export device list with tags
formant device list --json | jq '.items[] | {name, id, tags}' > devices.json

# Query analytics and save results
formant analytics query --sql "SELECT * FROM events WHERE created_at > '2026-01-01'" \
  --json > analytics_export.json
```

### Use with AI tools and LLMs

`--toon` produces compact, token-efficient output that is well-suited for LLM
prompts and agentic workflows. Use `--field` to expand specific paths, or `--full`
when you need full payloads.

```bash
# Summarize your fleet for an LLM
formant device list --with-data --toon

# Get org context in compact form
formant org get --toon

# Pipe investigation results into an AI workflow
formant investigation runs <investigation-id> --toon

# Combine with other tools for agentic scripting
formant event list --severity critical --limit 20 --toon | your-ai-tool analyze

# Check recent events and device state together
{
  echo "=== Critical Events ==="
  formant event list --severity critical --limit 10 --toon
  echo "=== Fleet Status ==="
  formant device list --include-offline --toon
} | your-ai-tool "Summarize what's wrong with my fleet"
```

## Development

### Build from source

```bash
git clone https://github.com/FormantIO/formant-cli.git
cd formant-cli
npm install
npm run build
```

### Run in development mode

```bash
npm run dev -- device list --dev
```

### Run directly

```bash
./bin/run.js --help
```

### Capability Validation Matrix

```bash
# Read-only capability sweep
npm run capability:test:readonly

# Read-only capability sweep against built CLI (bin/run.js)
npm run capability:test:readonly:built

# Read-only + safe-write checks (currently KV set/get/delete smoke)
npm run capability:test:safe-write

# Safe-write checks against built CLI
npm run capability:test:safe-write:built

# Mutating operation checks (create/update/delete, operational triggers)
npm run capability:test:mutate

# Mutating checks against built CLI
npm run capability:test:mutate:built

# Optional: fail mutate run if any skip is not in the known expected skip set
npm run capability:test:mutate:strict

# Regenerate docs/capability-validation-matrix.md from latest results
npm run capability:matrix

# Run both sweeps and regenerate the matrix doc
npm run capability:refresh

# Run readonly + safe-write + mutate in dev and built runtimes + matrix
npm run capability:refresh:full

# Pre-release validation: repo checks + strict contracts + non-destructive capability sweep
npm run validate:release
```

Result files are written to `tmp/capability-results/`.
Mutation result JSON includes `residue` (artifacts we could not fully clean up) and `skipAudit` (expected vs unexpected skips).

`validate:release` requires working Formant credentials and performs one temporary KV set/get/delete smoke check. It does not run the broader mutate suite.
Manifest-dependent validation scripts now self-generate `oclif.manifest.json` when needed, so local validation no longer depends on manually leaving that ignored file around after packaging.

Manual checks for descriptions/help/README/skills are documented in:
- `docs/manual-cli-content-review.md`

## Requirements

- **Node.js** >= 18.0.0
- A **Formant account** with service account credentials
- Appropriate **permissions** for the operations you want to perform

## Support & Resources

- **Documentation:** [https://formant.io/docs](https://formant.io/docs)
- **Support Email:** [support@formant.io](mailto:support@formant.io)
- **GitHub Issues:** [https://github.com/FormantIO/formant-cli/issues](https://github.com/FormantIO/formant-cli/issues)
- **Formant Platform:** [https://app.formant.io](https://app.formant.io)

## License

MIT

See [LICENSE](./LICENSE) for details.

---

Made with care by [Formant](https://formant.io)
