Skip to main content

taktcli

Authorized GraphQL CLI for Takt — the full Takt GraphQL surface from the shell, for agents and humans. Everything the MCP server does, and more.

The core is stdlib-only (urllib + argparse + json): a thin argv → GraphQL-over-HTTP client. Because arguments arrive as argv strings, it structurally sidesteps the MCP client-serialization bug class (arrays-as-JSON- strings, double-encoded results, the empty-string-drops-all-args bug) — an argv string simply can't be double-JSON-encoded.

The package and console-script are both named taktcli (bare takt is taken on PyPI).

Install

pip install taktcli            # stdlib-only core
pip install 'taktcli[watch]'   # + websockets, enables `taktcli watch`
pip install -e cli/            # from a monorepo checkout

Maestro/harness images ship pip install 'taktcli[watch]' — taktcli watch is the supported replacement for the retired tools/wait_for_task.py.

Agent skill

The wheel ships /takt, an agent skill (SKILL.md + references/) that teaches any skill-loading agent (Claude Code, Codex, opencode, …) to drive Takt with this CLI. It always documents the installed version.

taktcli skill show                          # print SKILL.md (no install needed)
taktcli skill show references/worker.md     # any file in the skill
taktcli skill path                          # where the bundled copy lives
taktcli skill install                       # copy to ~/.claude/skills/takt
taktcli skill install --target agents       # ~/.agents/skills/takt
taktcli skill install --target codex        # $CODEX_HOME/skills/takt (default ~/.codex/skills)
taktcli skill install --target project      # ./.claude/skills/takt
taktcli skill install --dir DIR             # DIR/takt
taktcli skill install --aliases             # also the takt-cli, explore-wiki, takt-worker aliases

Modes: /takt cli (CLI reference), /takt explore-wiki (wiki exploration), /takt worker (take a task end to end). install copies the files (never a symlink) and writes VERSION: the version, then one sha256 path line per file. It refuses to replace a copy that was edited, has no VERSION, is a symlink, or comes from a newer taktcli, unless --force.

Quickstart

taktcli login                          # browser approval, stores a self-refreshing profile
taktcli whoami                         # subject, owner, workspace, expiry, credential source
taktcli board --project takt           # show the board
taktcli run takt-42                    # READY → RUNNING (idempotent: re-run touches activity)
taktcli task update takt-42 --meta maestro.worker.session_key=author:takt-42
taktcli get takt-42                    # full task, including meta
taktcli stop takt-42                   # RUNNING → READY, hand the task back
taktcli status takt-42 REVIEW          # or: taktcli done takt-42

No claim, no lease: any caller with write:tasks flips status directly.

Task meta

task update and task create take --meta KEY=VALUE (repeatable) and --meta-file PATH (a JSON object; - = stdin, but not together with --desc-file -). They fold into one meta patch that the server deep-merges into tasks.meta: the file is the base and each --meta applies on top, a dotted KEY builds nested objects, VALUE is JSON when it parses (n=3 is a number, s='"3"' a string, x=null deletes x) and a plain string otherwise. get, task create and task update print meta; namespaces and limits are in takt/context/task-meta in the Takt wiki.

Deprecated in 0.8, removed in 0.9

Claiming is retired. For one release these keep working, print taktcli: warning: … on stderr (stdout JSON stays parseable) and then:

  • claim <id> → checks the task client-side: READY runs run and prints its JSON (no lease id; --json is ignored); anything else prints {"claimed": false, "reason": …} on stderr and exits 1. It is not exclusive: the check and run are two requests and RUNNING → RUNNING is an accepted touch, so two concurrent claims can both exit 0.
  • release <id> → stop; --lease is not required.
  • --lease on run/stop/done/fail/status/task result → warns, never sent. $TAKT_LEASE is ignored silently.

0.9 turns claim/release into hard errors naming run/stop and removes --lease.

taktcli --help (or taktcli help) lists every command; taktcli <noun> --help lists a group's verbs.

Auth

Token resolution, simplest-wins:

  1. TAKT_TOKEN env → used verbatim and never refreshed. This is what harness containers are stuffed with; env always wins over any stored credential.
  2. Else the selected profile in ~/.takt/credentials.json, written by taktcli login. The profile is --profile NAME → TAKT_PROFILE → the store's current profile → default.
  3. Else error: No Takt credentials found. Run: taktcli login (exit 3).

URL resolution mirrors it: TAKT_URL env → the profile's URL → default https://api.takt.sh/graphql. The watch WS endpoint is derived by swapping the scheme (https → wss).

taktcli login runs the OAuth 2.0 device grant (RFC 8628). It prints Open <url> and enter <code> to stderr, opens that page in your browser with the code filled in (unless --no-browser, or there is no display), and waits for you to approve. --as <agent> preselects an agent you own on the approval page, so the CLI acts as that agent while you stay its owner.

taktcli login                                       # you, profile "default"
taktcli login --as claude-code --profile claude-code
taktcli login --no-browser                          # headless: just print the URL + code
taktcli login --url http://localhost:8454/graphql   # another server
taktcli whoami                                      # subject, owner, client, workspace, expiry, source
taktcli profile list                                # stored profiles (no secrets)
taktcli profile use claude-code
taktcli logout                                      # revoke the grant, then delete the profile

The stored grant refreshes itself: an access token lasts an hour and is renewed 60 seconds before it expires (or once after the server rejects it), and the grant lives as long as it is used at least once every 90 days. Refreshes take a lock on ~/.takt/credentials.lock, so parallel taktcli and watch processes share one rotation. logout revokes the grant on the server before deleting it locally; logout --force deletes even when the server can't be reached.

The file is mode 0600 in a 0700 directory and is replaced atomically; taktcli refuses to read it through a symlink or with group/world permissions. A { "token", "url" } file from taktcli ≤ 0.6 keeps working until your next login rewrites it.

taktcli adds no privilege surface: the token never exceeds what the approving human can grant, there is no claims/permission verb anywhere, and admin ops are reachable via gql only if the token already holds the admin claim. Bots and harness images keep using TAKT_TOKEN.

Passthrough — reaches 100% of GraphQL

taktcli gql + taktcli schema are a complete superset of every MCP tool: any GraphQL op MCP never wrapped is reachable here.

taktcli gql -q 'query { me { nickname claims } }'
taktcli gql -f query.graphql --var id=takt-42 --field-file description=desc.md
taktcli schema --sdl              # SDL introspection (--json for JSON)

Big markdown flows through --field-file NAME=PATH (NAME=- = stdin) — this sidesteps shell quoting and the empty-string-args bug class.

Shared I/O flags

  • --var KEY=VALUE (repeatable; value parsed as JSON when valid, else string)
  • --vars JSON / --vars-file PATH (- = stdin) — bulk variables
  • --field-file NAME=PATH (NAME=- = stdin) — inject a file's contents as a variable; the canonical path for large markdown
  • --raw — full {data, errors, extensions} envelope (default is pretty .data)
  • --compact — single-line JSON

Variable precedence (lowest → highest): --vars-file < --vars < --var < --field-file.

Command surface

The CLI uses a positional namespace — taktcli <noun> <verb> [args] — so the entity is always the first token. This fixes the MCP create_wiki (Wiki) vs wiki_create (page) collision at the CLI layer. Run taktcli <noun> --help for a group's verbs.

Every MCP tool maps to a verb:

MCP tool taktcli verb
get_task get <id> / task get <id>
list_tasks task list
search_tasks task search <q>
get_board board
create_task task create
update_task task update <id>
update_status status <id> <STATUS> (or run / stop / done / fail)
claim_task deprecated → run <id>
release_claim deprecated → stop <id>
force_release_claim deprecated → stop <id>
transition_task task transition <id> <action>
get_dependencies task deps <id>
add_comment task comment <id>
get_task_comments task comments <id>
attach_result task result <id>
get_task_results task results <id>
delete_result task result-delete <id>
wiki_read wiki read <path>
wiki_search / wiki_semantic_search wiki search <q> (--semantic)
wiki_grep wiki grep <pattern>
wiki_create wiki create <path>
wiki_update wiki update <path>
wiki_edit wiki edit <path>
wiki_move wiki move <path> <new-path>
wiki_verify wiki verify <path>
wiki_delete wiki delete <path>
wiki_bulk_update_status wiki bulk-status <folder> <status>
find_related_wiki_pages wiki related <task-id>
(none — CLI-only; MCP tool removed in takt-432) wiki feedback list
(none — CLI-only; MCP tool removed in takt-432) wiki feedback resolve <id>
wiki_list wikis list
create_wiki wikis create
(none — CLI-only; GraphQL updateWiki / renameWiki) wikis update <slug>
(none — CLI-only; GraphQL wikiRenamePreview) wikis rename-preview <slug> --new-slug S
get_project_wiki wikis get <project>
request_upload_url_and_headers + confirm_upload file upload <path> (composite)
get_file_url file url <id>
list_files file list
attach_file_to_task file attach <id> <task-id>
detach_file_from_task file detach <id> <task-id>
attach_file_to_wiki file attach-wiki <id> <path>
update_label / delete_label label update <name> / label delete <name>
(none — CLI-only) label create
list_notifications notif list
mark_notification_read notif read <id>
mark_all_notifications_read notif read-all
unread_notification_count notif count
(none — CLI-only) project {list,get,create,rename,member-add,member-remove}
taskStatusChanged / taskChanged / resultAdded / commentAdded watch (needs [watch] extra)

Notes:

  • label create is CLI-only (the MCP server never wrapped createLabel, but the GraphQL mutation exists). label update / delete are keyed by name and resolve the id client-side via the labels query.
  • The wiki page verbs take --wiki SLUG (default $TAKT_WIKI) and stream big markdown through --content-file / --old-file / --new-file (- = stdin).
  • The wiki-container verbs are wikis list/create/get/update (entity = Wiki). The old workspace list/create/get verbs are a hard error naming the replacement for one release — workspace is being reclaimed to mean the tenant, and nothing else.
  • project rename is name-only — slug changes are blocked on the backend.

Update a Wiki container

taktcli wikis update knowledge --name "Team knowledge"
taktcli wikis update knowledge --description "Shared documentation"
taktcli wikis update knowledge --description-file description.md
taktcli wikis update knowledge --description-file -
taktcli wikis rename-preview knowledge --new-slug team-docs
taktcli wikis update knowledge --new-slug team-docs --yes-rewrite-links

The current slug is required explicitly; this command does not use $TAKT_WIKI. Provide at least one field. Omitted fields are preserved; --description "" stores an empty string. --description-file reads UTF-8 text (- reads stdin) and cannot be combined with --description. Name and description require write:wiki within the token's workspace and wiki allowlist.

Successful metadata updates print {"updateWiki":{"slug":…, "name":…, "description":…}}; --raw and --compact follow the normal output contract.

--new-slug renames the slug through renameWiki. It requires --yes-rewrite-links; omitting confirmation exits 3 before sending a request. Confirmation does not bypass the server's check that the caller is a human workspace OWNER (FORBIDDEN otherwise). The rename rewrites every [[old/…]] mention and app URL into the wiki (https://takt.sh/wiki/old/…, /w/<workspace>/wiki/old/…, relative /wiki/old/…) across the workspace's pages, tasks, comments, results and descriptions, in one transaction, and prints {"renameWiki":{"wiki":{…},"report":{"oldSlug","newSlug","pages","tasks", "comments","results","links","unfixable"}}}. unfixable lists what Takt cannot reach (env such as WIKI_SLUG/TAKT_WIKI, CLAUDE.md, skills, scripts, bookmarks, links on other hosts). The old slug 404s. Combined with --name / --description, both mutations go in one document, rename first; if the rename fails, the metadata edit does not run.

rename-preview runs wikiRenamePreview and prints the same report without writing anything. It is gated like the rename.

Output & exit codes

Default output is pretty JSON of the unwrapped .data payload. --compact = single-line; --raw = full {data, errors, extensions} envelope; watch = NDJSON (one event per line, flushed per event).

Code Meaning
0 success
1 GraphQL error (server reached; errors[] non-empty)
2 transport error (DNS/TCP/TLS/HTTP non-2xx/timeout/WS drop)
3 config or usage error (no token, bad URL, unknown verb, missing flag)

extensions.code (e.g. INVALID_TRANSITION, DEPENDENCY_NOT_MET) is preserved in error output so loops can branch on it.

Every request carries User-Agent: taktcli/<version>, so the server's access log shows which CLI versions are still in use.

Task monitoring — taktcli watch

Replaces the retired tools/wait_for_task.py. Streams subscription events as NDJSON and reconnects with exponential backoff on drops (e.g. deploys). Needs the [watch] extra.

taktcli watch --project takt --timeout 3600     # status changes, any task
taktcli watch --task takt-42 --task takt-43      # specific tasks
taktcli watch --project takt --event resultAdded # other subscriptions

--event defaults to taskStatusChanged. Unlike the old one-shot script, watch is a continuous stream — read NDJSON lines as they arrive and act on the first matching one; no restart-per-event. Tasks already READY when the watcher starts are not detected — check taktcli board --project takt first.

MCP coexistence

taktcli and the MCP server run side-by-side over the same GraphQL API, authenticating identically (JWT, same claims). Use either or both in one session. The MCP freeze/removal timeline lives in PRD 002 §8.

Documentation

  • Usage reference: takt/context/taktcli in the Takt wiki.
  • Design & rationale: takt/dev/prd-002-taktcli (PRD 002).
  • Contract placement: takt/contract §4.3 — the CLI as a first-class integration interface alongside GraphQL + MCP.

Release

Push a cli-v* tag (e.g. cli-v0.1.0) — .github/workflows/cli.yaml builds cli/ and OIDC trusted-publishes to PyPI. The tag must match the version in cli/pyproject.toml (CI asserts this). The CLI has its own CI job alongside backend/plugin/frontend (npm run test:cli).

Metadata

Release files for taktcli 0.8.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for taktcli 0.8.2
File Size Uploaded Provenance Actions
taktcli-0.8.2.tar.gz 124.6 kB With provenance Details for taktcli-0.8.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for taktcli 0.8.2
File Interpreter ABI Platform Actions
taktcli-0.8.2-py3-none-any.whl Python 3 none any Details for taktcli-0.8.2-py3-none-any.whl

Total release size: 227.7 kB

Release files / taktcli-0.8.2.tar.gz

Download URL taktcli-0.8.2.tar.gz
Size 124.6 kB
Tags Source
SHA-256 checksum
How to use checksums
95c132d9526f9e50d38967397b5a891c94fcf42affd5ac4c11dd4a66f3b9df06
BLAKE2b-256 checksum
How to use checksums
f714c637f52d3fb3873d5e00fc2bf6aa8a21d644a8f8b28bd81aa8195ee3f0d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / taktcli-0.8.2-py3-none-any.whl

Download URL taktcli-0.8.2-py3-none-any.whl
Size 103.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4aa15340e681e8143f47a0b10dd5e41c7c2ef48d651dc4c96245da343121205a
BLAKE2b-256 checksum
How to use checksums
ab88931bbeb73ab872d645be14778b5e1db635a1591613e86dc24df514d14183
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for taktcli 0.8.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for taktcli-0.8.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page