# CLI (met)

`met` is Meteor's terminal: it runs a Met, follows the run history, opens a
chat and — most useful while you integrate — **listens to your workspace's events and
forwards them to your local server**.

```bash
npm i -g @meteor.ia/cli
```

Node ≥ 20. It uses the same `met_` API key as the SDK.

## Configure

```bash
met config set --key met_live_xxx --workspace 7
met config show    # the key comes out masked
```

It is stored in `~/.config/met/config.json`. It also reads `MET_API_KEY`, `MET_WORKSPACE` and
`MET_BASE_URL` from the environment, and every command accepts `--key` / `--workspace` for
one-off use. In CI, use the environment variables.

While developing, use a **test** key (`met_test_`): runs cost nothing and
external side effects are blocked.

## Run a Met

```bash
met run "Summarize today's leads"
```

In an interactive terminal it streams by default. For a pipeline or a cron job:

```bash
met run "Hello" --json --no-stream
```

`--json` prints the whole object on one line, ready for `jq`. `--met <name>`
picks which Met runs if you don't want the workspace's default.

```bash
met runs list --status failed --limit 20
```

## Run a task

A task is a procedure with steps that your Met runs. From the terminal:

```bash
met tasks list
met tasks run tsk_123
```

`run` fires the execution and returns right away, because the steps run in the
background. For a cron job or a pipeline that isn't enough — the command would say "ok"
for having been able to fire it, not for it having worked — so use `--wait`:

```bash
met tasks run tsk_123 --wait
```

With `--wait` the command waits for the final state and **the exit code reflects the
result**: `0` if it finished completed, `1` if it failed or was cancelled. The default
ceiling is 300 seconds; raise it with `--timeout 900`.

```bash
met tasks show tsk_123          # the task and its latest executions
met tasks executions tsk_123 --json
```

## Chat

```bash
met chat --met sales
```

A REPL over the same run stream. Good for trying out a prompt without writing
code.

## Listen to events, and forward them to your machine

This is the command that makes installing the CLI worth it:

```bash
met listen --forward http://localhost:3000/webhooks
```

It takes the workspace's events live and **POSTs them to your local server**, so you
develop the webhook handler without exposing your machine to the internet or setting up
a tunnel. Filter for what you care about:

```bash
met listen --types run.completed,run.failed
```

Without `--forward` it prints them, which is enough to see what is going on. The event
catalog is in [Webhooks](webhooks.html#event-catalog).

## Collections and items

Collections are the workspace's no-code databases, and they are the step before
everything else: without a collection's id you can't list or create anything inside it.

```bash
met collections list
met collections show 12        # the field schema
```

`show` prints the fields with their type because those keys are exactly the ones you
then use to write:

```bash
met items list --collection 12 --limit 20
met items create --collection 12 --set title="House up north" --set price=250000
met items update 9812 --collection 12 --set status=sold
```

`--set` is repeatable and is written without escaping anything, which is what you want in a
terminal. It splits on the **first** `=`, so a URL with a query string goes through whole.

Watch out for types: everything arrives from the shell as text, and `--set` only converts what
is unambiguous. `true`, `false`, `null` and numbers go through; `007`, `1.50` and `1e3`
stay as text because they don't survive the round trip. What it **cannot** tell apart
is a phone number `3001234567` from a quantity — for those cases, pass JSON and set the
type yourself:

```bash
met items create --collection 12 --data '{"phone":"3001234567"}'
```

`--data` wins over `--set` if you pass both.

## Contacts

```bash
met contacts list --limit 50
met contacts show 42                          # the contact and their latest messages
met contacts send 42 "The visit is booked"
```

`send` sends as a **human operator**, not as a Met: it is the equivalent of writing from
the inbox, and the message is attributed to a person in the history. If what you
want is for a Met to answer, that is `met run`.

## Which Mets are there

`met run --met <name>` needs the name of a Met. To see them:

```bash
met agents list
met agents show 3        # its tools
```

`show` prints the tools because it answers the next question — *"why doesn't the Met
do X?"*, which is almost always that it doesn't have the tool, not that the prompt is wrong.

## How much you are spending

```bash
met billing resumen --from 2026-07-01 --to 2026-07-31
met billing ejecuciones      # the detail, sorted by cost
met billing saldo
```

`resumen` is the period's aggregate and `ejecuciones` the detail. **When the invoice doesn't
add up, the answer is in the detail**: it walks every execution and sorts them by
cost, and at the top there is almost always a Met calling itself in a loop.

`saldo` warns you if automatic recharging is off. It matters more than it looks in an
unattended integration: running out of Energy **stops executions**, and on the customer's
side that looks like "the API stopped responding".

## Debug webhooks

It is the counterpart of `met listen`: that one brings the events to your machine, and this
answers the other half — *"the webhook is configured, why isn't my server receiving anything?"*.

```bash
met webhooks list
met webhooks events 12       # delivery history, with the HTTP code
met webhooks sample 12       # fires a test event
```

If `events` comes back empty, you already have your answer: the webhook **never fired**, so the
problem is in the trigger and not in your endpoint.

It is read-and-test only, on purpose: creating a webhook or rotating its secret is done from the
panel. A secret left in your shell history is exactly what you don't want.

## Provision a workspace from a script

A template (Snapshot) sets up a whole vertical in the workspace: collections,
Mets, flows and content. From the terminal you can do it without opening the panel, which is
what you need when you onboard a new customer from your own signup flow or
from CI.

```bash
met snapshots list --vertical inmobiliaria
met snapshots show inmobiliaria-basica     # what it includes and which variables it asks for
```

`show` prints the variables with a `*` on the required ones. They are the business
data the template uses to personalize prompts and content, and they are passed at
install time:

```bash
met snapshots claim 3f1e…                  # free templates only
met snapshots install 3f1e… --set negocio="Muebles del Norte" --set ciudad=Medellín
```

`install` requires the workspace to already have access to the template: `claim` grants it for
the free ones, and paid ones are bought from the panel. Here `--set` **does not convert
types**: a phone number or a tax id stays text, which is what they are. If a variable
really isn't text, pass it as JSON with `--vars '{"cupo":10}'`.

The install is additive and idempotent, and **everything arrives switched off**: `install`
prints the id on stdout and the state on stderr, so in a pipeline you can store
the id and review before turning anything on.

## When something doesn't work

```bash
met whoami
```

It tells apart the three cases that look identical from the outside: the key is wrong (**401**),
the key is valid and missing the operation's scope (**403**), or everything is fine. The
second is the one that wastes the most time, because it authenticates without trouble and the
operation still fails — and the first suspicion always falls on the key. It also tells you which
host and which workspace you are hitting, which is the other silent mistake.

## If you are a partner

Your partner business is also queried from the terminal, with the same key:

```bash
met partner leads --status won
met partner clients
met partner commissions --status approved --json
met partner payouts --period 2026-07
```

The resources are `clients`, `leads`, `projects`, `commissions` and `payouts`. They are
**read-only**: creating an opportunity or moving a stage is done over the
[SDK](../../partners.html) or from the panel — not something you want to fire off in one
go from a terminal.

The exception is support, which does write:

```bash
met partner tickets list
met partner tickets show 84                     # the whole thread
met partner tickets reply 84 "Fixed — give it another try"
```

`show` prints the messages and not just the header, because the next thing you are going to
write is `reply`. Opening a ticket and closing it are done from the panel or over the SDK.

A partner key has no workspace, and these commands don't need one. The Partners API
host is a different one, so if you point at another environment it is configured
separately:

```bash
met config set --partner-base-url https://api.partners.meteor.com.co
```

## Every command

| command | what it does |
|---|---|
| `met run <input>` | runs a Met and shows the output |
| `met runs list` | run history (`--status`, `--limit`, `--json`) |
| `met tasks list` | the workspace's tasks |
| `met tasks run <id>` | fires a task (`--wait`, `--timeout`) |
| `met tasks show <id>` | the task and its latest executions |
| `met tasks executions <id>` | execution history |
| `met agents list\|show` | the workspace's Mets and their tools |
| `met billing resumen\|ejecuciones\|saldo` | Energy usage; `ejecuciones` is the detail by cost |
| `met webhooks list\|show\|events\|sample` | debug webhook deliveries |
| `met collections list\|show` | the workspace's collections and their field schema |
| `met items list\|show\|create\|update` | rows of a collection (`--collection`, `--set`, `--data`) |
| `met contacts list\|show\|send` | CRM and sending as an operator |
| `met partner <resource>` | your partner business (read-only) |
| `met partner tickets list\|show\|reply` | support: a ticket's thread and your reply |
| `met snapshots list\|show\|claim\|install` | templates: catalog, details and install (`--set`, `--vars`) |
| `met chat` | interactive REPL |
| `met listen` | live events (`--types`, `--forward`) |
| `met config set\|show` | stores or shows the configuration |
| `met whoami` | checks the active key: authentication, scope and host |
| `met help` | the full help |

## Common options

| option | what for |
|---|---|
| `--met <name>` | which Met to run (by default, the workspace's) |
| `--workspace <id>` | target workspace (or `MET_WORKSPACE`) |
| `--key <met_…>` | API key (or `MET_API_KEY`, or the stored one) |
| `--base-url <url>` | API host (or `MET_BASE_URL`), to point at another environment |
| `--partner-base-url <url>` | Partners API host (or `MET_PARTNER_BASE_URL`) |
| `--json` | JSON output, for pipes and CI |
| `--no-stream` | waits for the complete result instead of streaming |

## What it doesn't do yet

The CLI covers **runs**, **Mets**, **tasks**, **collections**, **items**, **contacts**,
**flows**, **webhooks**, **billing**, **events**, **templates** and the partner
business (read, plus support tickets). The ones left out — skills,
channels, automations, integrations, functions — are operated over the
[SDK](../index.html#quickstart) or REST, where they are complete.

It is not a gap to be filled for symmetry: a CLI is for what you do one command at a
time, in a cron job or while trying something out. Configuring a webhook or activating a skill is
done once, and from the panel.

**API keys are created from the panel** (Settings → Developers), not from the
terminal: issuing credentials from a CLI is the kind of thing that ends up in a
shell history. To check the one you are using, `met whoami`.
