An agent-first CLI for Monday.com. Pull tasks, file backlog items, transition statuses, and post comments from the terminal — designed for AI coding agents (Claude Code, Codex, Aider) with humans as a welcome second audience.
AI coding agents need to operate on real tickets. Monday.com has a
GraphQL API, but each agent learning that schema from scratch is
wasteful — and the API is sharp-edged (40+ column types, idiosyncratic
mutation shapes, complex pagination). monday-cli is the abstraction:
one stable contract (universal envelope, 26 stable error codes,
JSON Schema introspection) that every agent can target.
- Agent-first ergonomics.
--jsoneverywhere, stableerror.code, deterministicmeta, no interactive prompts. monday board describeemits paste-ready--set <token>=<value>examples for every writable column — agents discover board structure without reading external docs.monday schema --jsondumps every command's input flags and output shape as JSON Schema 2020-12 — no--helpscraping.--dry-runon every mutation;confirmation_requiredfor destructive bulk ops (no surprise deletes).- Two-layer token redaction scrubs the API token from every emitted byte (logs, error messages, stack traces). Hardened against an adversarial fixture suite.
npm install -g monday-cliRequires Node.js ≥ 22.
# 1. Set your Monday API token (admin or member; guests can't mint one).
# Get one at https://<your-org>.monday.com/admin/integrations/api
export MONDAY_API_TOKEN="<your-token>"
# 2. Smoke test
monday account whoami --json
# 3. List a board's items (replace 12345 with your board ID)
monday item list --board 12345 --json
# 4. Move a ticket forward
monday item set 67890 status=Done --json
# 5. Comment on it
monday update create 67890 --body "Shipped in PR #1234" --jsonThe CLI follows a monday <noun> <verb> shape:
# Discovery
monday account whoami
monday board list
monday board describe <board-id> # full board schema with column types
# Reading items
monday item list --board <board-id>
monday item list --board <board-id> --where status=Backlog --where owner=me
monday item list --board <board-id> --all --output ndjson | jq '...'
monday item get <item-id>
monday item find "Refactor login" --board <board-id>
monday item search --board <board-id> --where status=Done
monday item subitems <item-id>
# Updating items
monday item set <item-id> status=Done
monday item update <item-id> --set status=Done --set 'Due date'=+1w
monday item clear <item-id> status
# Comments (Monday "updates")
monday update list <item-id>
monday update create <item-id> --body "Shipped in PR #1234"
# Schemas (the agent's discovery hammer)
monday schema # full registry as JSON Schema 2020-12
monday schema item.set # one command's schema (dotted name)
# Diagnostics + escape hatch
monday board doctor <board-id> # flag duplicate titles, non-writable
# column types, broken board_relations
monday raw '{ me { id name email } }' # GraphQL escape hatch
monday raw 'mutation { ... }' --allow-mutation --dry-runFor worked agent walkthroughs (pick up a backlog item → mark
in-progress → leave a comment → mark done), filter DSL syntax,
dry-run shapes, and error handling, see
docs/examples.md.
- TTY (you in a terminal): human-friendly tables, truncated to fit the terminal width.
- Pipe / redirect: JSON, no flags needed —
monday item list | jqworks. - Agent in a pseudo-TTY: pass
--json(alias for--output json) to force JSON regardless of terminal detection. JSON output is never truncated.
Every JSON response uses the same universal envelope:
{
"ok": true,
"data": ...,
"meta": {
"schema_version": "1",
"api_version": "2026-01",
"cli_version": "0.1.0",
"request_id": "0e6f1a7b-...",
"source": "live",
"cache_age_seconds": null,
"retrieved_at": "2026-05-01T10:00:00Z",
"complexity": null
},
"warnings": []
}Errors carry a stable error.code — agents key off the code,
never the English message:
{
"ok": false,
"error": {
"code": "rate_limited",
"message": "...",
"retryable": true,
"retry_after_seconds": 30,
"details": { "...": "..." }
},
"meta": { "..." }
}The full envelope and error-code contract live in
docs/cli-design.md §6 (binding) and
docs/output-shapes.md (per-command
reference).
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Usage error (bad args, confirmation_required) |
| 2 | API or network error |
| 3 | Config error (missing token, etc.) |
| 130 | SIGINT (Ctrl-C) |
If you're an AI coding agent driving this CLI:
- Always pass
--json. Pseudo-TTY detection isn't reliable inside an agent harness.--jsonis an alias for--output jsonand forces JSON on every command. JSON is never truncated; tables are. - Branch on
error.code, noterror.message. The 26 stable codes (not_found,confirmation_required,column_archived,unsupported_column_type,rate_limited,stale_cursor, …) are part of the contract. Messages are not. - Read
meta.sourceto know whether the data is"live"/"cache"/"mixed"/"none"."mixed"means board metadata came from cache while the rest hit live — non-trivial for writes because Monday's column state may have drifted.cache_age_secondstells you how stale the cached portion is. - Discover commands via
monday schema --json. Every command's input flags + outputdatashape are introspectable as JSON Schema 2020-12 — no--helpscraping. - Discover board structure via
monday board describe <board-id> --json. Each writable column carriesexample_set, paste-ready--set <token>=<value>strings the agent can use without external Monday docs. - Use
--dry-runon any mutation to preview the change as aplanned_changes[]envelope before committing. Bulk ops without--yesreturnconfirmation_required(exit 1) by default. - Per-command output reference lives in
docs/output-shapes.md— whatdatalooks like for every shipped command. Worked agent sessions indocs/examples.md.
The CLI reads configuration from environment variables. Source priority (first match wins):
MONDAY_API_TOKENinprocess.env(current shell).MONDAY_API_TOKEN=...in a.envfile in the working directory.
--token <value> is not a supported flag — tokens passed on the
command line leak via ps, shell history, and crash dumps. If you
must pass one inline, prefer MONDAY_API_TOKEN=... monday ... so
the token stays in the process env only.
The CLI sends Authorization: <token> (no Bearer prefix).
Monday's API rejects the Bearer form.
See .env.example for all supported variables
(API URL override, API-Version pin, request timeout, etc.).
v0.1.0 (published) ships: read-only core (account, workspace,
board, user, update, item) + safe mutations (item set /
item clear / item update single + bulk, update create) +
diagnostics (board doctor) + GraphQL escape hatch (raw) +
filter DSL (--where + --filter-json) + cursor pagination with
stale-cursor fail-fast + NDJSON streaming + local cache.
v0.2 in development on main (not yet published as a
tarball — package.json still pinned to 0.1.0):
- M8 added the
--set-raw <col>=<json>escape hatch (bypasses the friendly translator; gated against read-only-forever and files-shaped types) and thelink/email/phonefirm-row friendly translators. - M9 added
monday item create— top-level + classic-only subitem creation with single round-trip semantics, optional positional placement (--position before|after --relative-to <iid>), and the same--set/--set-rawsurface asitem update. - M10 closed the item-lifecycle cluster —
monday item archive/delete/duplicate. The two destructive verbs share the--yesconfirmation gate (--dry-runexempts) and read the source item for the dry-run preview;archiveis wire-level idempotent,deletenon-idempotent (re-running after an interimcreatewould target the new item).duplicateis creative (no--yes), runs two-leg live (board lookup + mutation — Monday requiresboard_id), takes--with-updatesto copy the source's comments, and extends the live envelope'sdatawithduplicated_from_idso an agent has the source-ID echo handy. - M11 closed the four-verb lifecycle set with
monday item move— same-board (--to-group <gid>) viamove_item_to_groupor cross-board (--to-group <gid> --to-board <bid>) viamove_item_to_board. Cross-board moves use--columns-mapping '{<src>: <target>}'to bridge columns whose IDs differ between source and target; the strict default rejects unmatched columns pre-mutation withdetails.unmatched+details.example_mapping(agents copy-paste the seed into their retry) rather than letting Monday silently drop them.--columns-mapping {}is the explicit "drop everything (Monday's permissive default)" opt-in.--to-groupis required for both forms because Monday'smove_item_to_board(group_id: ID!)is mandatory. Value-overrides on cross-board mappings deferred to v0.3 (Monday'sColumnMappingInputcarries no value slot — agents firemonday item setpost-move when they need overrides). - M12 ships the idempotency cluster —
monday item upsert- bulk
monday item clear --where. Upsert takes--match-by <col>[,<col>...]plus--name/--setand routes 0 / 1 / 2+ matches tocreate_item/update_item/ambiguous_match(the 28th stable error code). Sequential- retry idempotent — re-running with the same args from the same agent is safe; concurrent agents are NOT a uniqueness guarantee (agents should pick a stable hidden key column for--match-byso race-induced duplicates surface asambiguous_matchon the next call). The match-by safe-list is intentionally narrow in v0.2:name/text/long_text/numbers/ external_id-shaped hidden text round-trip verbatim;status/dropdownround-trip via label-text;peopleis restricted tome;date/link/email/phoneare NOT v0.2-safe (the lookup-leg vs mutation-leg grammars don't reconverge at the wire — see cli-design §5.8 for the per-kind breakdown). Bulkclear --whereextends M5b's per-item clear with the same cursor walk +--yesgate + per-item failure decoration as bulkupdate --where.
- bulk
Writer allowlist (other types return unsupported_column_type
with per-category guidance):
status, text, long_text, numbers, dropdown, date,
people, plus M8 firm row link, email, phone.
Remaining v0.2 milestones (M13–M18) on main: full update
mutation surface (reply / edit / delete / like / pin /
clear-all), workspace + board lifecycle, NDJSON streaming,
0.2.0 release prep.
Deferred to v0.3+: tags / board_relation / dependency
friendly translators (still tentative; usable today via
--set-raw), monday dev workflow shortcuts, multi-level subitem
creation. v0.4: monday item watch, --concurrency, asset
uploads. See docs/cli-design.md §13 for
the full roadmap and docs/v0.2-plan.md
for the active milestone plan.
See CHANGELOG.md for the per-release contract.
docs/cli-design.md— canonical CLI contract. Start here if you want to understand the full surface, the JSON envelope, error codes, or the v0.1 vs v0.2 split.docs/output-shapes.md— per-command output reference with concrete examples.docs/examples.md— worked agent sessions.docs/architecture.md— module boundaries (commands → api → SDK).docs/api-reference.md— Monday concepts cheat sheet.docs/development.md— local dev workflow, adding a new command.CLAUDE.md— agent-facing project context and conventions.
git clone https://github.com/Firer/monday-cli.git
cd monday-cli
npm install # `prepare` hook auto-builds dist/
npm run dev -- account whoami --json # tsx-based dev runner
# Quality gates (all must pass before merge):
npm run typecheck
npm run lint
npm testThe full dev workflow + how to add a new command is in
docs/development.md. Conventions:
- Strictest TypeScript (
exactOptionalPropertyTypes,noUncheckedIndexedAccess,verbatimModuleSyntax). - No
any(lint-enforced). - Parse at every boundary with zod.
- Mock at the network boundary, not internal modules.
- Branch coverage 94%+ floor.
- Atomic commits, Conventional Commits.
PRs welcome. Read docs/cli-design.md for
the contract before writing code — anything that changes the
output envelope or error codes is a major-version bump and
requires explicit doc revision.
MIT © Nick Webster