Metadata-Version: 2.4
Name: ktr-cli
Version: 0.3.0
Summary: Unofficial command-line client for the Kantree API.
Author: Sebastien De Reviere
License-Expression: Apache-2.0
Requires-Dist: click>=8.3,<9
Requires-Dist: requests>=2.33,<3
Requires-Python: >=3.11
Description-Content-Type: text/markdown

# ktr-cli

Unofficial command-line client for the Kantree API.

This project is not affiliated with, endorsed by, or maintained by Kantree.

`ktr-cli` provides two command names:

* `kantree`: canonical command
* `ktr`: short alias

Commands cover authentication, discovery (`org`, `team`, `workspace`, `view`),
cards, search, import/export, webhooks, automations, and raw API requests.

## Install

Requirements:

* Python `3.11+`
* A Kantree API key (`X-Api-Key`)
* Your Kantree API base URL

Install from PyPI:

```bash
uv tool install ktr-cli
kantree --help
ktr --help
```

## Auth Setup

Start with the local guide:

```bash
kantree auth guide
```

For an on-prem Kantree environment:

```bash
kantree auth set \
  --profile work \
  --base-url https://kantree.example.com/api/1.0
kantree auth key set
kantree auth show
kantree auth test
kantree me
```

Profiles store connection metadata such as the API base URL. `kantree auth key
set` stores the key in a separate local `api-keys.toml` file with `0600`
permissions. Use `kantree auth key edit` to replace it. `KANTREE_API_KEY` is
the only API-key environment variable, and it is only an ad-hoc fallback when
the profile is not explicitly selected with `--profile` or `KANTREE_PROFILE`.
On first run, `auth set` selects the target profile; pass `--no-use` when you
only want to create or edit a profile without making it active.

Use `kantree auth`, `kantree auth show`, `kantree auth status`, or
`kantree auth current` to inspect active profile metadata without printing
secrets. These setup/status commands print human-readable text by default; add
`--format json` when a script needs the stable JSON payload. Use
`kantree auth key show` to inspect whether a profile has a saved key without
printing it.

Local paths:

* `$XDG_CONFIG_HOME/kantree/config.toml` if `XDG_CONFIG_HOME` is set
* `~/.config/kantree/config.toml` otherwise
* `$XDG_CONFIG_HOME/kantree/api-keys.toml` or `~/.config/kantree/api-keys.toml`
  for saved profile API keys

`config.toml` is written as a private regular file with `0600` permissions.
Symlinks and non-regular files at that path are refused.

You can also pass connection settings per command:

```bash
kantree --base-url https://kantree.example.com/api/1.0 me
```

The API key can also come from environment variables:

```bash
export KANTREE_API_KEY="..."
kantree --base-url https://kantree.example.com/api/1.0 me
```

Resolution precedence:

1. Profile: root `--profile`, `KANTREE_PROFILE`, active profile, `default`
2. Base URL: root `--base-url`, `KANTREE_BASE_URL`, profile, internal default
3. API key value:
   * no config/default fallback: saved `default` key, then `KANTREE_API_KEY`
   * active profile: saved profile key, then `KANTREE_API_KEY`
   * explicit `--profile` or `KANTREE_PROFILE`: saved profile key only

When setup fails:

* Missing API key: run `kantree auth key set`, or export `KANTREE_API_KEY` for
  an ad-hoc command without explicit profile selection.
* Authentication failed (401): check that the key is current and matches the
  base URL, then run `kantree auth test`.
* Forbidden (403): the key may be valid, but the user may lack permission for
  the workspace, org, resource, or action.
* TLS/private CA: set `REQUESTS_CA_BUNDLE` or install the CA in system trust.
  For disposable test endpoints only, `--insecure-skip-tls-verify`,
  `KANTREE_INSECURE_SKIP_TLS_VERIFY=1`, or profile
  `insecure_skip_tls_verify = true` can disable certificate verification.

## Workspace Usage

Most commands need a workspace. Use one of:

```bash
kantree card list --workspace Ops
kantree card list --workspace-id 42
kantree --workspace Ops card list
KANTREE_WORKSPACE=Ops kantree card list
```

Resolution order:

1. Command-local `--workspace-id` / `--workspace`
2. Root `kantree --workspace-id` / `--workspace`
3. `KANTREE_WORKSPACE_ID` / `KANTREE_WORKSPACE`
4. Active profile `default_workspace`

`card batch --id` and `card batch --stdin-ids` use global card ids. They
reject active workspace selectors/defaults because those defaults do not scope
global id selection. For workspace-scoped batch selection, use `card batch`
with `--workspace-id` / `--workspace` and `--filter`.

Set defaults per profile:

```bash
kantree workspace use Ops
kantree workspace current
kantree workspace current --resolve-remote
```

`workspace delete` and `workspace move` are stricter and require explicit
selectors. They ignore env/profile default workspaces.

```bash
kantree workspace delete --workspace-id 42 --yes
kantree workspace move --workspace-id 42 --org DSI --dry-run
kantree workspace move --workspace-id 42 --org DSI --yes
```

Root `--org` sets the default organization context for org-scoped commands
such as `workspace list`, `team list`, `team show`, `team create`,
`team delete`, and `search cards`; command-local `--org` wins. Mutation target
options such as `workspace move --org` stay command-local.

## Output

Most commands default to JSON. Setup/status discovery commands such as
`auth show`, `auth key show`, `auth test`, `workspace current`, `api routes`,
and `api spec` print human-readable text by default; use `--format json` for
stable script output. List-style commands support:

* `table`
* `tsv`
* `ids`
* `ndjson`

Use:

```bash
kantree --format table workspace list
kantree --format tsv --fields id,title,state card list --workspace Ops
kantree --format ids card list --workspace Ops
```

Output controls are global root options. Put `--format`, `--fields`, and
`--verbose` before the command name. `--verbose` enables extra columns when
supported.

Discovery lists keep machine output bounded where useful. `org list` and
`team list --org ...` emit compact summary objects by default, including
JSON `count` and `truncated` metadata; pass command-local `--full` to include
the full remote objects in JSON or NDJSON output.

For `table` and `tsv`, terminal control characters in remote values are shown
as visible escapes such as `\x1b`, `\x07`, `\n`, `\r`, and `\t`. TSV cells are
escaped before printing so one item remains one row. `ids` output rejects
control-containing identifiers with a validation error instead of transforming
or emitting them. Except for summary-first discovery lists, JSON and NDJSON
preserve the response data model; JSON serialization keeps literal terminal
controls inert for scripts.

Successful first-class webhook, automation, workspace view, global view, and
workspace email-template output redacts secret-like response fields and
tokenized absolute URLs in place. Use `api request` in a private terminal when
you need exact successful API payloads for debugging.

## Common Commands

```bash
kantree org list
kantree workspace list --org DSI
kantree workspace card-types --workspace Ops
kantree team list --org DSI
kantree card list --workspace Ops --filter '@me'
kantree card create --workspace Ops "Fix LDAP sync"
kantree card edit 123 --state completed
kantree card move 123 --parent 456
kantree card move 123 --group "In Progress"
kantree workspace columns edit --workspace Ops "Done" --position 2
kantree search cards --filter '@me'
kantree search preset list
kantree view list
kantree webhook list --workspace Ops
kantree automation list --workspace Ops
kantree import discover ./cards.csv
kantree kql validate '@me and state!=completed'
kantree api request GET /me
```

Use `kantree --help` and command-level `--help` for current flags and
subcommand details.

Paginated commands stop if Kantree reports a repeated or decreasing
`X-Kantree-NextPage` value. `workspace export`, `card list --all`,
`card batch --filter`, and `search cards` fetch at most 1000 pages by default;
pass `--max-pages INTEGER` when an expected export, card list, batch filter
selection, or search needs more pages.

`workspace export-artifact --wait --output FILE` streams the finished artifact
to a private sibling temporary file, then atomically replaces `FILE` with a
`0600` regular file after the download completes. The default download ceiling
is 512 MiB; pass `--max-artifact-bytes INTEGER` for an expected larger
artifact. If the server reports an oversized `Content-Length`, the destination
is not created or changed. If a no-length or chunked download crosses the
limit, the partial temporary file is removed and any existing destination file
is left unchanged.

## Raw API Requests

Use `api` or `api routes` to see the configured base URL, derived spec URL,
official hosted API reference URL, and safe starting examples. For
self-hosted or Enterprise environments, keep the configured base URL on your
own Kantree API domain; `spec_url` is derived from that configured base URL.
The hosted API browser/reference is `https://kantree.io/help/api`.
These discovery commands print human-readable text by default; use
`--format json` for stable script output.

```bash
kantree api
kantree api routes
kantree api spec
```

`api request` is the escape hatch for endpoints without a first-class wrapper.
Paths must be relative to the configured base URL; absolute URLs are rejected.
Non-safe methods (`POST`, `PUT`, `PATCH`, and `DELETE`) require `--yes` unless
you use `--dry-run`.

```bash
kantree api request GET /projects/42/cards --query page=1 --include-headers
kantree api request POST /cards/7/comments \
  --body '{"message":"hello"}' \
  --header X-Trace-Id:manual-check \
  --yes
kantree api request POST /importers/spreadsheet/discover \
  --form delimiter=, \
  --file spreadsheet=cards.csv \
  --dry-run
kantree api request GET /me --output me.json
kantree api request GET /projects/42/export/json --max-response-bytes 20971520
kantree api request POST /integrations \
  --body '{"webhook_secret":"..."}' \
  --dry-run \
  --unsafe-verbatim-diagnostics
```

Successful raw requests emit a JSON envelope with `status` and `data` and keep
the API response payload verbatim when the captured response body stays under
`--max-response-bytes` (default: 10485760 bytes, 10 MiB). Oversized successful
responses fail with exit `7` and emit a bounded diagnostic envelope with status,
content metadata, `bytes_read`, `max_response_bytes`, `truncated: true`, and
rerun guidance instead of a partial `data` envelope. Oversized raw failures cap
body capture before text summarization and redaction; status-specific exits are
preserved where possible.
`--include-headers` adds selected response headers such as `Content-Type`,
`X-Kantree-NextPage`, request ids, and retry hints. Sensitive header names are
redacted or omitted. Dry-run previews, raw failure diagnostics, and request
error diagnostics redact secret-like JSON/form fields, reflected active
secrets, and selected response details by default, including diagnostics written
with `--output`. Raw failures also emit a JSON diagnostic envelope and exit
nonzero, preserving non-sensitive API body structure when it is JSON and
summarizing non-JSON HTML or proxy text.
Human stderr diagnostics render terminal control characters from external
values as visible escapes after redaction, while authored recovery guidance
keeps its intended line breaks.
Use `--unsafe-verbatim-diagnostics` only when you need exact raw API diagnostic
values in a private terminal; it can print or write secrets and is unsafe for
logs, CI, and support bundles. It can make raw dry-run and failure diagnostic
fields verbatim, but `planned_requests` remains redacted. It does not bypass
`--max-response-bytes`.
Authenticated `--output` files are written as private owner-only files (`0600`).
Existing regular files are overwritten and changed to `0600`; symlinks,
directories, FIFOs, devices, and other non-regular targets are refused. Omit
`--output` when you want stdout. On platforms that cannot safely protect
existing-path opens from symlink races, use a new output file path.
Credentialed raw API and artifact download requests do not follow redirects;
`3xx` diagnostics usually mean the configured base URL, reverse proxy, SSO/WAF
route, or artifact endpoint needs correction.

## Failure Recovery

* Missing API key or base URL: run `kantree auth guide`, then `kantree auth set`,
  `kantree auth key set`, and `kantree auth test`. On first run, `auth set`
  activates the profile.
* Wrong hosted/on-prem base URL: rerun with root `--base-url` or update the
  active profile.
* Private CA or certificate verification failure: install the CA chain or set
  `REQUESTS_CA_BUNDLE=/path/to/private-ca-chain.pem`. Use
  `--insecure-skip-tls-verify` only as a noisy last resort for disposable test
  endpoints; it disables certificate and hostname verification.
* `401` or `403`: verify the active profile, key, user permissions, and whether
  a proxy forwards `X-Api-Key`. Do not keep retrying mutating commands.
* `502`, `503`, or `504`: read-only requests are retried automatically; mutation
  requests are not. Check reverse proxy and upstream Kantree health.
* `3xx` redirects: credentialed Kantree requests are not followed because
  redirects can expose the API key. Fix the base URL, proxy, SSO/WAF route, or
  artifact endpoint so it serves the final API or artifact URL directly.
* Pagination stops with a validation error when `X-Kantree-NextPage` repeats,
  decreases, or would exceed `--max-pages`. Re-run with a larger explicit
  `--max-pages` only when the large result set is expected.
* Artifact download stops before writing output when `Content-Length` exceeds
  `--max-artifact-bytes`, and removes the private temporary file if a streamed
  no-length download crosses the limit. Re-run with a larger explicit
  `--max-artifact-bytes` only when the artifact size is expected.
* Raw `api request` stops before parsing or writing oversized responses when
  `Content-Length` exceeds `--max-response-bytes`, or after the first streamed
  chunk that crosses the limit when no length is known. Re-run with a larger
  explicit `--max-response-bytes` only when the response size is expected.
* `200 text/html` or login HTML in a raw `api request` response: suspect a proxy
  login page, missing `/api/1.0`, wrong base URL, or SSO/WAF rewrite.
* Output write failure: choose an existing writable parent directory and a
  regular file path. Authenticated `--output` writes refuse symlinks and
  non-regular targets, and may refuse existing files on platforms without safe
  no-follow open support.

## Safety And Help

* Keep API keys in `kantree auth key` storage, env vars, or a secret manager.
* `auth show` and `auth key show` redact key metadata; avoid command-line
  secrets (`--body`) in shared terminals and history.
* `api request --dry-run`, raw failure diagnostics, and request error
  diagnostics redact secret-like values by default. Do not use
  `--unsafe-verbatim-diagnostics` in shared logs or CI; it does not remove raw
  response byte limits, and `planned_requests` remains redacted.
* Guarded destructive commands, `import apply`, and every mutating `card batch`
  mode require explicit `--yes` or command-local `--dry-run`.
* Shared guarded dry-run previews for raw `api request`, first-class destructive
  commands, and `import apply` resolve the same selectors as execution, perform
  only needed reads, report whether confirmation would be required, and include
  `planned_requests` with method, endpoint, and redacted request body/file
  details. `card batch --dry-run` keeps its existing per-card action summary
  with `selection_mode`, `dry_run`, and `results`.
* `card create --parent` verifies that the parent card belongs to the selected
  workspace before resolving groups or fields and before creating the child.
* Workspace selectors/defaults do not scope global `card batch --id` or
  `card batch --stdin-ids` selections. Remove the selector/default or select
  cards with `--filter`.
* When no workspace selector/default is active, server-side `card batch` for
  explicit `--id` or `--stdin-ids` selections validates that selected cards
  belong to one workspace before posting the batch request. Split
  mixed-workspace batches and rerun per workspace.
* Server-side multi-operation `card batch` output includes an `operations`
  array. If an earlier operation was accepted or completed and a later one
  fails, per-card results use `partial-failure`, keep the successful `actions`,
  identify `failed_operation`, and exit with partial-failure status `9`.
* `workspace delete` and `workspace move` ignore default workspace fallbacks and
  require an explicit command-local or root `--workspace-id` / `--workspace`
  selector.
* Prefer `card archive` when you need a reversible action.
* Use `--dry-run` where available before mutating commands. Immediate-write
  convenience commands still execute directly unless their help lists
  `--dry-run`.
* Run `kantree auth guide` when credentials or the base URL are not configured.
