task command
Add, start, or complete selected local work through its owning store.
/ca:task$ca-task/ca-taskAvailability is read from each shipped host catalog. Preview-only commands are marked on the page.
What it does
Section titled “What it does”The only blessed way to mutate .codearbiter/open-tasks.md. It runs a thin writer over pure
board-transform logic, which keeps every entry schema-conformant and every transition dated —
start always stamps a started date so a task can never sit as a dateless in-progress item.
Board-only PRs filed just to flip a task’s state are the anti-pattern this command eliminates: a
task’s done-flip, start-flip, or new-task add is meant to ride the same commit as the work it
tracks.
/ca:task add "<desc>" | start <id|"title"> | done <id|"title"> | archive <id|"title">add appends a queued task (optionally minting a dotted ID with --id); its description must be
nonblank and single-line, and its optional origin and boundaries must also be single-line, and
--desc attaches a rationale sub-bullet. start flips a task to
in-progress and stamps today’s date (or mints an ID at pick-up with --as); done flips an
in-progress task to done and stamps the done date. A queued task must be started first; attempting
to complete it directly writes nothing and tells the caller to use start. Targeting by title is
best-effort — prefer the dotted ID once one exists.
archive moves one already-done task off the board into done-tasks.md, which is the permanent
record. It moves the task’s whole block — the bullet and any Desc/Boundaries sub-bullets
travel together, so nothing is orphaned onto a neighbouring task — and it writes done-tasks.md
before removing from open-tasks.md, so an interruption costs at most a duplicate the next run
absorbs rather than a lost record. It refuses an item with no (done YYYY-MM-DD) stamp unless you
pass --allow-undated, since an unstamped entry’s real age is unknown. /ca:standup offers the
same verb per-item as its archival sweep.
Example
Section titled “Example”> /ca:task done poc.docs.0001
Flipped poc.docs.0001 to done, dated 2026-07-02.open-tasks.md updated via taskwrite.py.When to reach for it
Section titled “When to reach for it”Any board write — adding, starting, or completing a task. To just read the board and its counts,
use /ca:status instead; it’s read-only.
| Gate | When | Effect |
|---|---|---|
| writer-only mutation | any add, start, or done invocation | the write goes through the taskwrite.py transforms only, never a free-hand edit — a malformed add field or target, an already-matching state, an out-of-order transition, an invalid GROUP.TYPE namespace, or a bad —date is reported and writes nothing |
Related
Section titled “Related”Route context
Section titled “Route context”Find this entry in the workflow atlas. Compare its related teaching maps, host spelling and context inputs. The exact procedure below remains the owner.
Source
Section titled “Source”Source — plugins/ca/commands/task.md (v3.7.0)
---description: Add, start, or complete selected local work through its owning store.argument-hint: "add \"<desc>\" | start <work-id|legacy-id|\"legacy title\"> | done <work-id|legacy-id|\"legacy title\">"---
# /ca:task — selected local work writer
# Owner selection
Check whether `${CLAUDE_PROJECT_DIR}/.codearbiter/open-tasks.md` exists. When it does,that board remains the work owner. Before a board write, resolve the installed`hooks/work.py` through the helper card below and run `work.py list --limit 1`from the project worktree. Continue with the legacy board procedure only whenthe result says `owner: legacy`; a refusal (including two owners) stops thewrite without changing either store.When it does not, use the installed `hooks/work.py` helper for native work.Do not create a board as a side effect of a native task command, and do notwrite both stores. If the selected helper reports two owners or an unsafestore, preserve the state and report its refusal.
For native `add`, use `work.py create --title=<description>--intent=<description> --type unknown --operation-id <stable-request-id>`.Pass title and intent as separate literal arguments so leading hyphens staydata. The request ID must be newly minted for a distinct action and reused unchanged after anuncertain result; retain it with the request until the result is known. If the task came froma durable source, also pass `--origin <source-key>` so later sessions canreconcile the same item. Record the returned `work_id` as the selection key.For native `start` and `done`, require that exact `work_id`. Read it once with`work.py get <work_id>`, then invoke `work.py start <work_id>` or `work.pycomplete <work_id>` with `--operation-id <stable-request-id>`,`--expected-revision <revision>` and `--expected-model-sha256 <model_sha256>`from that read. Retain all three values for an exact retry after an uncertainresult. A title or dotted board ID is not a safe native selector. A conflictreports the affected identity and must not overwrite a later update.Read the installed helper card described below for `hooks/work.py` too, andinvoke only the resolved installed copy with the selected Python interpreter.
## Legacy board procedure
The one blessed way to mutate `${CLAUDE_PROJECT_DIR}/.codearbiter/open-tasks.md`(resolves D-1). Hand-editing the board is no longer the only path; this command keepsevery entry schema-conformant and every transition dated. The board LOGIC lives in thepure `_taskboardlib` transforms; this command runs the thin writer`taskwrite.py` from the selected installed package.
Before an authorized board mutation, read the installed helper card:[helper-invocation.md](../includes/helper-invocation.md) relative to this loaded command.
Set its loaded-resource inputto the absolute path of this **loaded** command or skill, and select the literalrelative helper `hooks/taskwrite.py`. Resolve and check that helper exactly onceusing the card, then run its interpreter-selection block for the current shell.Run from the intended project worktree so the writer targetsthat project's board. Do not switch to the plugin directory, use a root tokenfrom a hook environment in an ordinary tool call, or search source/cache copies.
## Verbs
Always put `--` before user text (a desc or title) so a value beginning with `-` is notparsed as a flag. Use the validated Python 3 interpreter selected by the card;never retry a refused helper under another interpreter. Keep every option before `--` andpass user text as one literal argument.
- **add** — append a queued task. ID-less by default; pass `--id <group>.<type>` to mint a dotted ID now, `--from <origin>` for a harvest back-ref, `--boundaries a,b` for the security/trust boundaries it touches. The description must be nonblank and single-line; origin and boundary values must also stay on one line. - Invoke the resolved helper with `add [--id group.type] [--from origin] [--boundaries a,b] -- <desc>`.- **start** — flip a task to in-progress and **stamp the started date** (so it can never be a dateless `[~]`). On an ID-less item, pass `--as <group>.<type>` to mint its dotted ID at pick-up. `--date YYYY-MM-DD` overrides today. - Invoke the resolved helper with `start [--as group.type] [--date YYYY-MM-DD] -- <id|title>`.- **done** — flip an in-progress task to done and stamp the done date (`--date` overrides today). A queued task must be `start`ed first. - Invoke the resolved helper with `done [--date YYYY-MM-DD] -- <id|title>`.
The following are literal minimal `add` invocations after the installed helperand interpreter have been resolved. Bind the named text variable to the exactcaller-supplied description; do not paste that text into the command syntax.
### PowerShell add invocation```powershell& $caPython -B $caHelper add -- $caDescriptionif ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }```
### POSIX add invocation```sh"$ca_python" -B "$ca_helper" add -- "$ca_description"```
When `add` needs fields, bind each value separately and keep all options before`--`. Use the `--from=<value>` form if the origin begins with a hyphen. Theseexamples preserve quotes, metacharacters, and non-ASCII description text asone argument; neither shell evaluates the variable's contents as a command.
### PowerShell add with options```powershell$caAddArgs = @('add', '--id', $caId, "--from=$caOrigin", '--boundaries', $caBoundaries, '--', $caDescription)& $caPython -B $caHelper @caAddArgsif ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }```
### POSIX add with options```sh"$ca_python" -B "$ca_helper" add --id "$ca_id" "--from=$ca_origin" --boundaries "$ca_boundaries" -- "$ca_description"```
For `start` and `done`, replace only the verb and its literal option array,keeping the same resolved helper and `--` before the one title or ID argument.
A missing target, an already-matching state, an out-of-order transition, a malformedadd field or `--date`, or an invalid `GROUP.TYPE` namespace is reported and writesnothing (exit 1).A queued `done` identifies the task as queued and tells the caller to `start` it first.**Targeting by title is best-effort:**prefer the dotted ID, andnote that if two ID-less items share a title, `start`/`done` act on the first — give onean ID (`/ca:task start --as <group>.<type> -- "<title>"`) to disambiguate.
## When NOT to use
- Promoting workflow follow-ups in bulk → that is the harvest (`${CLAUDE_PLUGIN_ROOT}/includes/harvest.md`), which calls this writer for you.- Reading the board / counts → `/ca:status` (read-only).- Archiving long-settled done items → `/ca:standup` owns the sweep (D-2, resolved 2026-07-31). It proposes dated complete work strictly more than 14 calendar days old through the selected owner, then archives only the user's named subset in a fresh dedicated worktree. Native items use `work.py`; legacy rows stay with `taskwrite.py`, using an exact dotted ID or a uniquely verified title for an ID-less row. Undated done items are never proposed automatically; standup's explicit-request and `--allow-undated` rules apply. Declined items stay put.- Filing a separate `chore(board)` PR just to flip a task state → task-board transitions (`[x]` done-flip, `[~]` start-flip, new `[ ]` add) ride the **work commit** via commit-gate, co-located atomically with the code that completes, starts, or spawns the task (ADR-0008). A lagging board-only PR is the anti-pattern this design eliminates.
## Hard gate
- MUST write the board only through `taskwrite.py` (the pure transforms), never a free-hand Edit that can malform the schema.- `start` MUST stamp a started date — never leave a dateless `[~]`.- `done` MUST target an in-progress task — a queued task must go through `start` first.- MUST NOT delete a task to "complete" it — mark it `done` so the record survives.