CLI
@erdoai/cli wraps the same /v1 API the MCP server exposes, so
anything an AI assistant can do over MCP you can do (and script) from a shell.
Install
Requires Node.js 18 or later.Update
npm install -g @erdoai/cli@latest.
When a newer version is published, commands print one line telling you so:
ERDO_NO_UPDATE_NOTIFIER=1 to
silence it.
The notice matters more than it looks: an old build’s --help is accurate about
itself and wrong about the product, so a command added since your install simply
isn’t listed — and nothing else tells you it exists.
Auth & orgs
Accounts are stored at~/.config/erdo/config.json, one active at a time.
ERDO_API_KEY, ERDO_ORG, ERDO_API_URL, ERDO_ACCOUNT.
Pin the org in automation
The active org set byerdo org use lives in machine-global config, so it is
shared across every concurrent session — another shell (or another job) running
org use switches the org for all of them. A command that only reads is
harmless, but a mutation that lands in the wrong org is not, so any command that
writes prints the org it is about to act in on stderr before it fires:
erdo --org <id|slug> <command> or by setting ERDO_ORG, so the command acts in
the org you intended regardless of what any concurrent session did. Runs that
build real artifacts enforce this: erdo eval run refuses an artifact-building
suite unless the org is pinned (see Evals).
API tokens
An API token is an account-level credential — it acts as you in any org you belong to, not just one. The org stored on a token is only its default (used when a request names no org);erdo --org <x> <command> or erdo org use <x>
steers any command to another of your orgs, and the backend re-checks your
membership on every request.
ERDO_API_KEY, or authenticate an interactive session with
erdo login --key <token>. There is deliberately no way for an AI assistant
(MCP) to mint tokens — creation lives only on the CLI/REST surface a human drives.
Manager accounts
A manager account operates many client (“managed”) orgs with one credential — the pattern a portal uses to provision and run an org per customer without a pasted key per tenant. Your active org is the manager (you must be an admin/owner of it);erdo org managed create provisions a client org, and erdo org managed key mints
a single manager key that acts inside any managed org via --org <slug>.
erdo --org <slug> (or the X-Organization-ID header). Running
erdo org managed key again rotates it. See Manager accounts
for the full portal flow and the REST/MCP surface.
Project context
Use the global--project <uuid> flag when a command should run inside an Erdo
project. Pair it with --org whenever the token can operate more than one
organization:
ERDO_PROJECT is the environment-variable equivalent for CI.
Agents
Running an agent is sending it a message; the artifact-builder produces pages this way.--context when an application or script knows state that should guide one
turn but should not masquerade as the operator’s words in the transcript. The
agent receives it as application context; the thread still shows the exact
message argument as the user message.
ask and send start the run, print its thread id, and poll until it finishes.
Agent runs routinely take minutes — building a landing page, screening variants —
and a single HTTP request held open that long is cut off by the edge proxy, so
polling is the default. The thread id is printed before the wait begins: if you
interrupt the CLI, or the run pauses for approval, the work carries on server-side
and you pick it back up by thread.
erdo approvals decide <id> --approve;
erdo agent wait <thread> then picks the wait back up and prints the answer when
the run completes.
Pass --sync to hold one request open instead. It returns faster on quick
questions, and it will time out on anything long.
Pages & artifacts
list shows your pages newest first (id, created-at, visibility, title) and filters by title substring (--query) or a created-at window (--created-after / --created-before, RFC3339). Pass --type <type> to list any artifact type (charts, tables) instead of just pages. delete is a soft delete — the page’s public link stops working and it drops out of list, but restore brings it back (private, since deleting revoked its public grant).
--html/--js/--css accept @path to read a file.
update edits an existing page in place (the URL and id stay the same) and merges the fields you pass, so you only send what’s changing. It takes the same content flags as deploy — --title, --html, --js, --css (plus the --datasets / --writable-datasets / --kv / --writable-kv grants below) — but all are optional: pass just --js to swap the script while keeping the existing HTML, CSS, and title. --public / --private change visibility. (Runtime is fixed at create time, so there’s no --runtime on update.)
Datasets and KV stores are wired with read/write grants. --datasets / --kv grant read (for window.erdo.queryDataset / erdo.kv.get); --writable-datasets / --writable-kv grant write (for erdo.insertRows / erdo.kv.set):
erdo.submitEvent) instead — see Build Apps.
Agent runs
Inspect what agents have done (the runs behind ask/send/evals).Approvals
Some agent actions pause for a human decision. List them and approve/reject so the paused run can continue. See Approvals.Decisions
What your organization committed to, whether the change actually happened, and what the evidence said afterwards. See Decisions.Review queue
The knowledge agents propose, the investigations they open, and the failure signals they keep counting — the queue of things awaiting a human decision. See the review queue.Datasets
list shows the newest 20 datasets by default; when more exist it says so on
stderr. Use --limit (max 100) and --offset to page through the rest.
upload accepts CSV, TSV, Excel, JSON, JSONL, PDF, DOCX, TXT, Markdown, and
more — the extension drives type detection. The schema is extracted before the
command returns, so the printed slug is immediately usable. Larger files (over
20 MB) go through the web app’s resumable upload.
Reading a dataset
There are two reads, and picking the right one matters. Before writing SQL, see what columns are actually there:schema reads the stored table itself (a DuckDB DESCRIBE), so it shows the
physical columns your SQL can reference — including ones added by recent writes
that a declared schema may not list yet. --json prints the raw result.
fetch is the deterministic read. You write the SQL, so the same command
returns the same rows every time — use it for anything mechanical, scripted, or
run by an agent. It answers with columns, rows, and row_count.
data — for file datasets, and
for anything an event pipeline writes, that is its name regardless of the
dataset’s slug. Database and warehouse datasets are queried through their real
table names, which come from the dataset’s schema. A dataset’s default filters
apply to every read; --filter <name> adds a saved filter on top and narrows
further, never bypassing a default. erdo datasets filter list <slug> shows the
names a dataset offers.
query is the natural-language read. Erdo writes and runs the SQL for you
and answers with that SQL alongside the values, so reach for it when you don’t
yet know the shape of the data. It runs an agent, so it is slower, and two
identical questions can produce two different queries.
fetch — the same SQL you would run against the live table.
revisions prints each version’s id, when it was created, when it was
superseded (blank for the live one, and for a stored file that was never live),
and the stored file’s name and type; --json prints the raw result.
Dataset revisions covers what does and does not create
one. The history is read-only — nothing here rolls a
dataset back. To restore, fetch the rows out of the old revision and write them
in again through the normal write path.
Integrations
Connect third-party apps and data sources from the terminal. Which flow you get depends on whether you hold the credential, not on whether the app is one of Erdo’s native integrations or one of the thousands in the SaaS catalog — see Connecting integrations for the full picture. Anything authenticated by a secret you already have — a database password, an API key, a service-account JSON — connects in one command with-c key=value
(repeat it per field). That covers native integrations and catalog apps whose
auth type is keys. OAuth apps are the exception: the provider mints their
credentials during the authorization itself, so there is nothing to pass. They
reject -c with an explanation and, connected without it, print a
connect_url for the browser; status then confirms the result.
organization_name / organization_slug and are printed above
the authorize URL, so an OAuth connection can still be abandoned at that point.
erdo integrations connect-links create says the same thing about the
connection its recipient will make.
A native credential integration is verified against the provider before the
command returns, so active means Erdo has genuinely talked to it. A catalog
keys app is only stored — the connector platform saves what it is given
without calling the vendor, and the printed next_step says so; the first action
you run is what confirms the key.
status on an app you have never connected answers normally — connected: false
with an empty list. It is a fact about your account, not a failure, so don’t read
it as one.
Once a database is connected, make it queryable as a dataset — queries run
live against the source, nothing is copied. Pass the schemas to include (some
integrations allow only one); tables lists the selectable ones. Per-table
column listing is available for SQL databases (Postgres, MySQL, and
compatible); warehouses list schemas only.
Knowledge
Knowledge is your agents’ shared brain — definitions, skills, and learnings.workspace (organization-internal) by default; public opts an
entry into anonymous external surfaces such as the
website voice widget — a draft is approved in the same step
and goes live immediately.
See Knowledge visibility.
KV (collections)
Named KV stores (collections) are Erdo’s shared key/value store — the canonical config and values (pricing, targets, brand tokens) that pages read, Knowledge bodies reference as{{slug.key}}, and agents resolve. One store, consistent everywhere.
Automations
Automations run on a schedule — either an agent that reasons each tick, or a zero-LLM script that runs a deterministic check. See Automations.update changes only the fields you pass. Edit an agent automation’s prompt with --instructions, or a scripted automation’s body with --script-js / --script-file — sending the wrong one for the automation’s kind is rejected rather than silently ignored. list shows each automation’s kind (agent or script).

