Skip to content

Firer/monday-cli

Repository files navigation

monday-cli

npm version CI Node License: MIT

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.


Why

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, 29 stable error codes, JSON Schema introspection) that every agent can target.

  • Agent-first ergonomics. --json everywhere, stable error.code, deterministic meta, no interactive prompts.
  • monday board describe emits paste-ready --set <token>=<value> examples for every writable column — agents discover board structure without reading external docs.
  • monday schema --json dumps every command's input flags and output shape as JSON Schema 2020-12 — no --help scraping.
  • --dry-run on every mutation; confirmation_required for 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.

Install

npm install -g monday-cli

Requires Node.js ≥ 22.

Quick start

# 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
#    (`monday auth login` is registered but the OAuth flow is not yet
#    available — authenticate via the env var.)
export MONDAY_API_TOKEN="<your-token>"

# 2. Smoke test — confirm the token works.
monday account whoami --json

# 3. Install shell completion (bash / zsh / fish). The default mode
#    emits raw script bytes on stdout (so the redirect works); `--json`
#    opts into the envelope.
monday completion bash >> ~/.bashrc        # or .zshrc / config.fish

# 4. Is everything wired up?
monday status --json                       # DNS / TCP / TLS / auth / cache probe matrix
monday usage --json                        # remaining daily Monday API operations

# 5. Discover a board's shape (columns / groups / views).
monday board describe 12345 --json         # full schema + example_set per writable column
monday board views 12345 --json            # views only (Kanban / Gantt / Calendar / Table / …)

# 6. List a board's items.
monday item list --board 12345 --json

# 7. File a new task.
monday item create --board 12345 --name "Refactor login" \
  --set status=Backlog --set 'Due date'=+1w --json

# 8. Long-poll for activity on an item (NDJSON stream).
#    Per-event NDJSON record + a `{"_meta": {...}}` trailer carrying
#    the session counters. Use `--once` to drain backlog without
#    polling further; SIGINT (Ctrl-C) drains gracefully and exits 130.
monday item watch 67890 --once             # or --max-events 50 --max-duration 1h

# 9. Upload a file to a column or to an update (comment).
#    Both surface `--dry-run` for an envelope preview without the
#    multipart round-trip.
monday item upload 67890 --column 'Attachments' ./screenshot.png --json
monday update upload <update-id> ./diagram.png --json

# 10. Parallel partial-success bulk updates. `--concurrency <N>` (1..32)
#     opts into parallel dispatch; envelope is byte-equivalent to the
#     sequential `--concurrency 1` default, input order is preserved in
#     `data.results[]` regardless of completion order.
monday item update --where status=Backlog --set status='Working on it' \
  --board 12345 --yes --continue-on-error --concurrency 4 --json

# 11. Browse the workdocs surface.
monday doc list --workspace 5 --order-by used_at --limit 10 --json
monday doc get 88001 --json                # full Document with blocks

# 12. Workdocs CRUD. Doc-level: create / rename / delete / duplicate.
monday doc create-in-workspace --workspace 5 --name "Design notes" --json
monday doc rename 88001 --name "Design notes (v2)" --json
monday doc duplicate 88001 --with-updates --json
monday doc delete 88001 --yes --json
#     Per-block: block-create / block-update / block-delete.
monday doc block-create 88001 --type normal_text --content '{"text":"hi"}' --json
#     Bulk import from HTML / markdown — no per-block round-trips.
monday doc import-html --workspace 5 --html ./page.html --title "Imported" --json
monday doc append-markdown 88001 --markdown ./notes.md --json

# 13. Team writers.
monday user team-list --json
monday user team-create --name "Platform" --users 7,9 --json
monday user team-add-members <tid> --users 11,13 --json

# 14. File-column friendly `--set` writes — every shape reaching
#     Monday's file-upload wire. `--dry-run` emits `planned_changes` on
#     any of these without the multipart round-trip.
monday item set 67890 'Attachments'=./screenshot.png --json
monday item update 67890 --set 'Attachments'=./diagram.png --json
monday item update --board 12345 --where status=Backlog \
  --set 'Attachments'=./report.pdf --yes --continue-on-error \
  --concurrency 4 --json                   # bulk file dispatch
monday item create --board 12345 --name "Field report" \
  --set 'Attachments'=./report.pdf --set 'Spec'=./spec.pdf \
  --set status='Working on it' --json      # multi-file at create-time
cat report.pdf | monday item set 67890 'Attachments'=- \
  --filename report.pdf --json             # stdin file source

# 15. Find-or-create with idempotent matching. Re-running with the
#     same args is safe — 0 / 1 / 2+ matches route to create / update
#     / `ambiguous_match` (a stable error code agents can key off).
monday item upsert --board 12345 --name "Refactor login" \
  --match-by name --set status='Working on it' --json

# 16. Move a ticket forward, then comment on it.
monday item set 67890 status=Done --json
monday update create 67890 --body "Shipped in PR #1234" --json

# 17. Monday Dev convention layer (sprint / epic / release / task).
#     First-time setup auto-detects boards by Monday's stock template
#     names.
monday dev discover --apply --json         # writes ~/.monday-cli/config.toml
monday dev sprint current --json           # the active sprint
monday dev task list --mine --json         # my open tasks

# 18. Outbound writes — webhooks + notifications.
monday webhook list 12345 --json
monday notification send --user 7 --target 67890 \
  --target-type item --text "PTAL" --json

Usage

The 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-run

For 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.

Output format

  • TTY (you in a terminal): human-friendly tables, truncated to fit the terminal width.
  • Pipe / redirect: JSON, no flags needed — monday item list | jq works.
  • 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.8.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).

Exit codes

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)

Agent quickstart

If you're an AI coding agent driving this CLI:

  1. Always pass --json. Pseudo-TTY detection isn't reliable inside an agent harness. --json is an alias for --output json and forces JSON on every command. JSON is never truncated; tables are.
  2. Branch on error.code, not error.message. The 29 stable codes (not_found, confirmation_required, column_archived, unsupported_column_type, rate_limited, stale_cursor, ambiguous_match, tag_not_found, oauth_failed, …) are part of the contract. Messages are not.
  3. Read meta.source to 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_seconds tells you how stale the cached portion is.
  4. Discover commands via monday schema --json. Every command's input flags + output data shape are introspectable as JSON Schema 2020-12 — no --help scraping.
  5. Discover board structure via monday board describe <board-id> --json. Each writable column carries example_set, paste-ready --set <token>=<value> strings the agent can use without external Monday docs.
  6. Use --dry-run on any mutation to preview the change as a planned_changes[] envelope before committing. Bulk ops without --yes return confirmation_required (exit 1) by default.
  7. Per-command output reference lives in docs/output-shapes.md — what data looks like for every shipped command. Worked agent sessions in docs/examples.md.

Configuration

The CLI reads configuration from environment variables. Source priority (first match wins):

  1. MONDAY_API_TOKEN in process.env (current shell).
  2. MONDAY_API_TOKEN=... in a .env file 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.).

Scope

v0.11.0 (current). Adds monday item get-description for reading item description doc-block content. A narrow new verb that surfaces Monday's Item.description payload (a list of doc blocks) without bloating every item read with heavy/nested content. 119 commands across boards, items (single + bulk via --where), columns, groups, workspaces, teams, workdocs, updates, files, and the monday dev workflow namespace. No breaking changes vs v0.10.0.

What's next. Roadmap headlines (see docs/cli-design.md §13 for the full roadmap):

  • Profile-scoped argument defaults via ~/.monday-cli/config.toml
  • Cross-board monday item move with column-value overrides
  • Resumable cross-board search cursor

A user-entity contract migration plus Monday API version pin bumps (to 2026-04, then 2026-07) defer pending upstream Monday SDK releases.

See CHANGELOG.md for the full per-release history.

Documentation

Development

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 test

The 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 95.45% floor for branches; 95% floor for statements / functions / lines (v0.3-M22 ratcheted branches from 94% via an OAuth coverage-push session — see vitest.config.ts).
  • Atomic commits, Conventional Commits.

Contributing

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.

License

MIT © Nick Webster

About

A CLI tool for interracting with Monday.com - in particular for building AI agentic workflows that need access to read, add, update, re-structure etc anything that is in a Monday.com or Monday Dev board

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors