Duvo CLI
duvo is the official command-line interface for the Duvo
public API. It is published to npm as @duvoai/cli:
a single binary with resource-grouped subcommands (duvo agents …,
duvo runs …, duvo cases …, …) and a low-level duvo api <method> <path>
escape hatch for endpoints that don't yet have a dedicated command.
Use the CLI when the user wants to automate or script Duvo. The
web UI at https://app.duvo.ai is the right answer when they want to
click around interactively; duvo is the right answer the moment they
ask for a shell snippet, a cron job, a CI step, or "how do I do X
without opening the browser?". Both surfaces talk to the same public
API — there is no functional gap to bridge by reaching for curl.
Managed sessions and manual setup
In a managed session, the host runtime instructions govern transport, setup, reference lookup, and scope. Follow them before this standalone guide. When the host says the CLI is installed and configured, do not probe installation, log in, inspect credentials, change profiles, or switch transport. Read the references it names before commands. The installation, authentication, and profile-management steps below are for manual standalone setup only.
Install (manual setup)
npm install -g @duvoai/cli
duvo --version
Requires Node.js ≥ 22.22.0. npx @duvoai/cli <cmd> also works without
a global install.
Authentication (manual setup)
duvo keeps credentials as named profiles on disk. One profile per
(team, environment). The first profile added becomes the default; from
then on, every command uses the default unless overridden.
duvo login # OAuth flow — opens your browser
duvo login --name acme # name the profile up front
duvo login --api-key <key> # skip OAuth and store an API key directly
duvo whoami # confirm who's signed in
duvo login defaults to browser-based OAuth against the Duvo
production tenant. Pass --api-key <key> to store a long-lived API key
instead (grab one from https://app.duvo.ai/settings/api-keys).
Switching between profiles:
duvo profiles list # show all profiles; `▶` marks the default
duvo profiles use # interactively pick the default profile
duvo profiles use acme # set a named profile as the default
duvo --profile acme whoami # one-off override for a single command
Resolution precedence (the first match wins):
- Profile:
--profile <name>flag →DUVO_PROFILEenv →defaultProfilein config. - Credential:
DUVO_API_KEYenv (bypasses the profile's stored credential lookup) → the profile's stored credential. - Base URL:
DUVO_API_BASE_URLenv → the profile'sapiBaseUrl→https://api.duvo.ai. - Team:
--team <id>flag →DUVO_TEAM_IDenv → the profile'sdefaultTeamId→ the team derived from the active credential. Team-scoped API keys reject a different--team; user-scoped keys can select any team the user can access.
Reading the help
Read references/commands.md for command syntax. Every command also supports
--help; in managed sessions, use it only when the host runtime permits it.
For standalone use, these help commands describe the installed binary:
duvo --help # global help, lists every top-level group
duvo agents --help # subcommand group
duvo agents create --help # exact flags for one command
If the binary rejects a documented flag, its help describes the installed version. Do not guess flags or treat standalone help examples as instructions to probe a managed session.
Output modes
Each command picks a default output shape based on what it returns:
- Single resource (
duvo agents get <id>,duvo runs get <id>) → human-readable key/value text. - Collection (
duvo agents list,duvo runs list) → table with a fixed column set per resource. --jsonon either of the above → raw JSON to stdout. This is the stable contract for scripts — table and text formats can change between versions, JSON is safe to pipe intojqoryq.
duvo agents list --team <target-team-id> --json | jq '.agents[].id'
For scripting, pass --json wherever the command reference lists it and parse the response. Don't
parse the table output — column widths and truncation thresholds are
not part of the public contract. Envelope keys differ across
endpoints — agents list returns .agents[], queues list returns
.queues[], runs list returns .data[], agents create returns
.agent.id. Inspect the shape with a one-off --json call before
hard-coding a jq path.
The duvo api escape hatch
Any endpoint in the public API is reachable via duvo api <METHOD> <path>, modelled directly on gh api. Reach for it when:
- A new public endpoint shipped but doesn't have a dedicated
duvocommand yet. - You need a very narrow query-string or body shape that the high-level command doesn't expose.
- You're debugging —
duvo apishows exactly what the API returned, with no formatting in the way.
duvo api GET /v1/agents -F limit=20 -F offset=0
duvo api POST /v1/agents -f name="Ops bot" -F build[name]="v1"
duvo api POST /v1/agents --input body.json
cat body.json | duvo api POST /v1/agents --input -
-f sends the value as a string; -F parses it as a typed value
(boolean, number, JSON null, or @file to load JSON from disk). See
references/api-escape-hatch.md for the full flag table.
High-level commands like duvo agents create are sugar over duvo api — they share the same HTTP client, output pipeline, and exit
codes, so a script can mix the two freely.
Resource groups
See references/commands.md for the full command tree with flags.
The top-level groups are:
- Auth & profiles —
login,logout,whoami,profiles … - Agents —
agents …,agents delete,agents move,agents duplicate/clone,agents models,agents set-model,agents case-triggers …,agents schedules …,agents triggers …,agents slack-triggers …,agents memory …,agents eval-scores,agents eval-rubrics … - Suggestions —
suggestions …(Connection suggestions: list, consume, reject) - Agent folders —
agent-folders …(organize agents in a tree) - Revisions —
revisions …,revision-integrations …(versioned configs) - Runs —
runs …(start, get, message, stop, respond to HITL, evaluation) - Queues & cases —
queues …,queues eval-rubrics …,queue-labels …,cases … - Notifications —
notifications …(list, get, feed, get-batch, counts, unread-count, mark-read, mark-batch-read, mark-all-read, dismiss, delete-read, delete-all) - Files & sandboxes —
files …,sandboxes … - Connections & integrations —
integrations …,connections …,oauth … - Secrets & credentials —
secrets …(env-var secrets),credentials …(browser logins),revision-secrets …,revision-logins … - Clarity —
clarity …(process search, versions, captures, gaps, evidence, facets, export, generation, promotion, artifact imports, invite links, doctor, process landscape, process links, process tags, process summaries) - Pulse —
pulse …(create, get, list, send message, attach files, refresh, stop, rename, share, duplicate, move to another team, pdf/snapshot export, version history, restore, messages, answer HITL, connections, comment threads, delete Pulse dashboards) - Skills & plugins —
skills …,plugins … - Team —
team current,team get,team members,team set-role,team remove-member,team leave,team use,teams list,teams org,teams orgs,teams create-org-team,teams org-insights,teams org-metrics,teams org-usage - Invitations —
invite list,invite create,invite bulk,invite update,invite resend,invite delete,invite org-member,invite link get|create|delete - Bundled guides —
guide …(version-matched CLI guides for AI agents) - Self-update —
update(update the installed CLI to the latest version) - Low-level —
api <method> <path>
For end-to-end recipes (create an agent → start a run → respond to
HITL; manage a queue and its cases; upload files for a sandboxed run;
authorize a custom MCP server) see references/workflows.md.
Conventions you can rely on across commands
These hold for every command group, so call them out when explaining the CLI rather than restating per-command:
--profile <name>is a global flag that overrides the default profile for that single invocation.--team <id>is a global flag that overrides the resolved team for commands that use request-team scope. In managed sessions, always pass the target team explicitly for those commands, even when it matches the configured default. Follow the host instructions to choose the target. Resource-ID commands may ignore this flag; raw API paths are not rewritten. Command-local ownership flags (including landscapepropose-process --team) assign an owner and must not receive a default team mechanically. Organization commands use--orgor a positional organization ID as documented. OAuth and user-scoped API-key profiles can select an accessible team; team-scoped API-key profiles reject a different team.--jsonis available on nearly every command that hits the API and is the shape to use in scripts. Use it only when the command's help or command reference lists it; never invent an unsupported flag or parse table output.- Destructive operations (
duvo logout,duvo profiles remove,duvo runs stop,duvo agents delete,duvo agents move,duvo agent-folders delete,duvo cases delete,duvo cases clear,duvo cases bulk-delete,duvo cases bulk-reprocess,duvo cases bulk-update-status,duvo cases bulk-update-priority,duvo skills delete,duvo skills revisions delete,duvo queues delete,duvo secrets delete,duvo credentials delete,duvo revision-secrets detach,duvo revision-logins detach,duvo revision-integrations remove,duvo revision-integrations connections unpin,duvo agents schedules delete,duvo agents case-triggers delete,duvo agents triggers delete,duvo agents slack-triggers delete,duvo agents eval-rubrics remove,duvo agents eval-rubrics replace,duvo queues eval-rubrics remove,duvo queues eval-rubrics replace,duvo connections delete,duvo queue-labels delete,duvo integrations custom delete,duvo clarity process-labels delete,duvo suggestions reject,duvo files delete,duvo pulse delete,duvo pulse move,duvo notifications delete-read,duvo notifications delete-all,duvo team remove-member,duvo team leave, …) prompt for confirmation in a TTY and refuse on a non-TTY stdin. Pass-y/--yesto skip the prompt — never pipeyesinto the CLI to bypass the prompt; it explicitly refuses inferred consent from piped input. - Exit codes:
0success,1generic error,2auth error (missing or invalid key, unknown profile),3not found. Useful for CI scripts that want to branch on the failure mode. - IDs are printed bare (no quotes) so they copy cleanly into shell
pipelines and
$()substitutions:agent=$(duvo agents create --team <target-team-id> --name "Ops bot" --input "What to do" --json | jq -r .agent.id) duvo runs start --agent "$agent" - Deprecation warnings print to stderr (so they don't corrupt
--jsonstdout) and can't be silenced. If a user reports an unexpected warning, check whether their@duvoai/cliversion is behind.
Pitfalls and gotchas
- Profile vs credential.
--profile foochanges which profile is read;DUVO_API_KEY=…overrides the credential but still uses the selected profile'sapiBaseUrl. To target a totally different environment, set bothDUVO_API_KEYandDUVO_API_BASE_URL. profiles usewith no argument opens an interactive picker that only works in a TTY. In CI, always pass a name explicitly.agents createis interactive by default. When--nameand--inputare omitted and stdin is a TTY, the CLI prompts. In CI, pass both flags (and--no-buildif you don't want an initial build) so it never blocks waiting for input.cases create --from-file -reads JSON from stdin. The file (or stdin) is a single case object or an array of up to 100 cases. Each case is{ "title": "…", "data": "…", "labels": [{ "key": "…", "value": "…" }] }. Labels with nokeyare tag-only labels.- Sandbox files vs team files.
duvo files …manages persistent team files (visible in the Files surface in the UI);duvo sandboxes …stages files for a single run (duvo runs start --sandbox-id <id>). Don't mix them. - Connections vs integrations.
duvo integrations listshows the team's catalog of integration types;duvo connections listshows the user's actual connected accounts (one per OAuth/credential flow). OAuth-based connections (Gmail, Slack, …) are started byduvo oauth native start <provider>, not byduvo connections create— the latter is only for user-provided MCP servers. - Attached ≠ connected.
revision-integrations attachonly creates the integration slot on the revision. For OAuth and user-provided integrations (HubSpot, Gong, Slack, custom MCP, …) the run can only use the slot once one of the user's connections is pinned to it — an attached slot with no pinned connection fails at runtime with "not connected", and nothing warns you at attach time. Find the connection withduvo connections list --team <target-team-id> --type <slug>, pin it withduvo revision-integrations connections pin, and verify withduvo revision-integrations connections list(expect ≥ 1 entry per slot). Default integrations (browser, Exa, human-in-the-loop,case-queue-producer/case-queue-consumer, …) need no pin — but case-queue slots need a queue mapped instead, verified withduvo revision-integrations case-queue-setup. See workflow 7 and the setup checklist in workflow 4 ofreferences/workflows.md. - Secrets vs connections vs credentials. Three separate stores:
duvo secretsholds env-var key/value pairs injected into runs at runtime;duvo credentialsholds browser logins (domain + password- optional TOTP) used by the browsing agent;
duvo connectionsholds OAuth/API-key connections to external services (Gmail, Slack, custom MCP, …). They don’t overlap — attach secrets withrevision-secrets, logins withrevision-logins, and connection slots withrevision-integrations connections pin.
- optional TOTP) used by the browsing agent;
- Multi-team OAuth and user-scoped API-key profiles. An OAuth login,
or an API key not pinned to a single team by the server (a user-scoped
key), can act on several teams. Use
duvo teams listto see all teams, then pass--team <id>on request-scoped commands. In manual setup,duvo team use <id>can set the profile default — both work for these profiles. A team-scoped API key is the one exception: the server already pins it to one team, so it cannot target a different team via--team. - Reconnecting an expired OAuth connection. Don't create a new
connection for a stale one — pass
--reconnect-instance-id <id>toduvo oauth native startorduvo oauth mcp authorizewith the existing connection's ID (fromduvo connections list) to re-authorize it in place instead of creating a duplicate. - Clarity has both read and explicit write commands. Start with
duvo clarity overview <process-id>, then useversions,current,proposal,compare,gaps,evidence,readiness, orfacetsto understand the process. Use the write commands only when the user actually wants to mutate Clarity state: generation, promotion, revert, postprocessing, automation build, extra-capture agent, invite links, or Miro artifact imports. Those v2-only commands require a Clarity v2 process; legacy v1 processes support onlyoverview,status,captures,capture, andexport. Default output is compact; transcripts and media URLs are included only when a JSON command explicitly passes--include-transcripts. - Notifications: batches vs individuals.
duvo notifications feedreturns a mix of individual notifications and notification batches grouped by Agent or Queue;get-batchandmark-batch-readonly accept a batch ID (fromfeedor a notification'sbatchId), not an individual notification ID. Onnotifications list,--sort importancerequires--batch— the CLI rejects the combination locally if--batchis omitted. - Clarity artifact imports use a two-phase API under the hood. Use
duvo clarity import-artifact <process-id> <file>for local Miro SVG, XML, PNG, or JPEG exports. It creates the signed URL, uploads bytes, and completes the import. For custom upload clients or artifact-chat workflows, useduvo apiagainst the public route directly. - Slack channel triggers need a connected workspace first.
agents slack-triggers createfails unless the Slack workspace is already bound to the agent — check withagents slack-triggers workspaces <agent-id>before creating, and pass--workspacewhen the team has more than one installed workspace. - Team member management has per-command role floors.
team set-roleneeds Manager and above (only an Owner can grant or remove the Owner role);team remove-memberneeds Superadmin and above;team leaveworks for any member. All three refuse to act on the last remaining Owner. - Two ways to attach a file to Pulse.
duvo pulse send-message <id> --message <text> --attach-file <path>uploads and references a file in one step — use it when you already know the instruction.duvo pulse attach <id> <file>only stages the file and prints its attachment ID, for when the instruction is composed or sent separately (e.g. from a script building the message body). Both share the same 5-file, 25MB-each limit.
When the CLI is the wrong tool
Steer users to a different surface in these cases:
- They want to read a stream of run events as they happen. The
CLI's
runs get/runs messagesare point-in-time reads. Use--webhook-urlonruns startto receive events asynchronously, or open the run in the web UI. - They want to edit an AOP or agent configuration interactively.
revisions createandrevisions updateaccept a config file, but composing the config by hand is painful. Direct them to the Agent editor in the web UI for anything beyond a small targeted patch. - They want to run an agent in their own process rather than on Duvo. That's not what the public API exposes; the CLI is a client to the hosted Duvo platform.
In-skill references
references/commands.md— full command tree with flags, grouped by resource. Use this when you need the exact flag a command expects.references/workflows.md— end-to-end recipes (create an agent and start a run; queue + cases lifecycle; sandboxed runs with uploaded files; authorize a custom MCP server).references/api-escape-hatch.md—duvo apiflag reference, with worked examples of-fvs-F,@filetyped fields, and--inputfor raw JSON bodies.
Read the relevant command reference before acting; managed sessions follow the host runtime instructions for any help fallback.
See also
aop-writer— author or rewrite the AOP that ships in a Build (duvo revisions create/duvo revisions update).run-debugger— diagnose a failed Run; pairs withduvo runs get,duvo runs messages, andduvo revisions getfor API-mode reads.workflow-debugger— audit an Agent or workflow across many Runs; pairs withduvo runs list,duvo queues agents, andduvo revisions get.
Resources
- Duvo — product website
- Duvo documentation — concepts, building Agents, Connections
- Duvo API reference — every endpoint the CLI wraps
@duvoai/clion npm — versions, install instructions, changelog- Web app — interactive surface for everything the CLI scripts
- API keys — issue and revoke API keys for
duvo login --api-key - Public skill repository — the MIT-licensed community release of this skill, packaged for installation in third-party Claude Code setups