Create or update an issue
save_issueCreate an issue (omit identifier) or update one (pass identifier, e.g. XEN-12). Only title is required to create. Setting status to canceled requires cancelReason, and MOVING AN ISSUE INTO review requires handoff unless it already carries a checkpoint — a finished-work claim has to say where the work is. labels replaces the issue's labels. CREATE requires FOUR declarations: (1) a dependency declaration — blockedBy (ids this depends on) OR noDependency (a one-line reason there are none); and (2) work — true if this is a unit an agent executes, false if it's a tracking container; and (3) changeType — which of the Conventional Commits types this change is, which is what the Cost page splits spend by; and (4) reviewedSimilar — the open look-alikes you have read, demanded only when there ARE any. A create missing any of them is rejected. The fourth CANNOT be filled in blind: it is a list of issue ids only the server produces. So if nothing looks like this work you never send it, and if something does the create is refused with DUPLICATE_CHECK_REQUIRED naming the candidates and you re-call with them — or you searched first with list_issues, name them yourself, and pass in ONE call. Read them before you name them: the gate proves you were shown them, not that you judged them right, and the cheapest issue to file is the one you don't file twice. If this call is refused for billing (BILLING_INACTIVE or MONTHLY_CAP_REACHED), the response carries tellHuman, a ready-to-relay sentence: PASS IT TO YOUR HUMAN. You cannot fix it yourself — only an owner can — so do NOT absorb the refusal and continue with read-only work as if the session were healthy; every value-bearing write will keep failing until they act.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | Markdown spec: context, acceptance criteria, repro. | |
| work | No | REQUIRED on create — you decide once. true = a unit an agent FINISHES by changing something: editing code/config/files, infrastructure (deploys, provisioning, env, DB/schema, CI/CD, DNS, services), writing/updating docs, running commands/migrations/scripts, fixing a bug, building a feature, refactoring, or a spike that ends in a concrete deliverable. false = it only ORGANIZES or TRACKS other issues and is never executed: epic, milestone, plan, roadmap, grouping — 'done' only when its child work issues are. Test: to finish this, does an agent change files or systems? → true; just a container done when its children are? → false. work:false issues are readable but NEVER claimed by next_issue/next_batch/claim_issue. | |
| dueAt | No | Precise deadline as epoch milliseconds. SET IT WHENEVER THE PERSON ASKING NAMED A TIME — "by Friday", "before the demo", "end of the month" — converted to the instant they meant in their own timezone; a date said out loud and not recorded is a date the queue cannot act on. If the work is plainly time-bound and nobody said when, ASK, once, while you are filing it: a deadline added days later is a deadline that never dispatched. Omit only when there is genuinely no commitment — most work has none, and a guessed date is worse than none. It is not a label: dispatch derives an effective-priority FLOOR from it (RTSC-187) — past 75% of the window an issue sorts at least High, past 90% at least Urgent, past due above Urgent — and that floor inherits up the `blocks` chain, so a dated issue pulls its blockers up with it. Every read echoes the derived `slaState`, and the Dash cannot set a date anywhere: yours is the only hand that puts one on. Distinct from the day-granular import-only `dueDate` and from the claim lease TTL. | |
| title | No | Required when creating. | |
| labels | No | Replaces all labels on the issue. | |
| status | No | `review` (RTSC-257) = work finished, pending human acceptance: it still BLOCKS dependents (unlike done) and releases your lease so a reviewer can claim it. `assignee` is REQUIRED on every write that LEAVES the issue in `review` (RTSC-347 + RTSC-400) — name the reviewer's human lane, an ACTIVE member who is a DIFFERENT principal than whoever submitted it (author ≠ reviewer). It is a property of the STATE, not of the transition: it applies when you move an issue to review, when you CREATE one with `status:"review"`, and to any later write that changes a live review's assignee — including a write that names no `status` at all. So `assignee:""` can't clear a live review's reviewer, and it can't be re-pointed at the submitter, at a suspended/retired member, or at a member nobody has ever signed in as (an unclaimed placeholder left behind by an import or a restore — RTSC-408): a review parked on a lane nobody can claim strands, non-terminal, blocking its dependents. To unassign, send it back first (`status:"todo"`). The reviewer's agent then promotes it (`status:done`, unblocks dependents) or sends it back (`status:todo` + a comment). Whether to use review is your team's convention; that it must be assigned is not. Entering `review` also requires `handoff` (RTSC-741) unless the issue already carries a checkpoint — see that field. | |
| handoff | No | The author's handoff, REQUIRED on the write that MOVES an issue into `review` (RTSC-741) and on a CREATE with status:"review" — unless the issue already carries a checkpoint, which IS the handoff and satisfies it. Say what you built and where it lives: branch, PR, commit. It is stored as the issue's checkpoint, so the next agent to claim it resumes from it instead of being handed your spec with no sign the work exists and building it a second time (which is what happened on 2026-08-25, twice in 25 minutes). Not validated for content — nothing here reads your branch or your CI; the requirement is only that the claim carries its evidence, exactly as `canceled` carries a cancelReason. Valid ONLY on that entry: passing it on any other write (including a re-save of an issue ALREADY in review) is rejected, not ignored, because a live review's checkpoint is protected by the claim. To revise the note on a review already submitted, use the `checkpoint` tool (it needs the claim_token), or send the issue back with status:"todo" and re-submit with a corrected handoff. | |
| assignee | No | Responsible human (routing lane, distinct from claiming): a human member name, 'me', or '' to unassign. Optional for most statuses — unassigned issues stay in the global pull pool — but REQUIRED whenever the write leaves the issue in `review` (RTSC-347 + RTSC-400), including a CREATE with `status:"review"` (which records YOU as the submitter, so the assignee must be a different active principal). While an issue sits in `review`, '' does NOT unassign: clearing it, or naming the submitter's own principal, a suspended/retired member, or a placeholder nobody has signed in as (left by an import or a restore), is rejected even on a write that never mentions `status`. Send it back with `status:"todo"` first if you want it unassigned. | |
| priority | No | 0=None,1=Urgent,2=High,3=Medium,4=Low. | |
| blockedBy | No | On create: issue ids this new one DEPENDS ON (e.g. ['RTSC-12']). Creates blocked_by links so the dependency graph drives dispatch. | |
| changeType | No | REQUIRED on create — what KIND of change this is, in Conventional Commits' vocabulary: feat (new capability a user can reach) · fix (a defect repaired) · docs (documentation only) · style (formatting, no behaviour change) · refactor (restructuring, no behaviour change) · perf (measurably faster or cheaper) · test (tests only) · build (build system, deps, packaging) · ci (pipelines and automation) · chore (maintenance that ships no behaviour) · revert (undoes an earlier change). ONE per issue, never a list — the Cost page splits spend by it and a multi-valued dimension cannot sum to a total. Pick what the change IS, not what area it touches: that is what `labels` are for, and they are unaffected. Correctable later with the same call if the work turns out to be something else. | |
| identifier | No | Existing issue ID to update; omit to create. | |
| cancelReason | No | Required when status=canceled. | |
| noDependency | No | On create: a one-line reason this issue depends on nothing open. Use INSTEAD of blockedBy when independent — a positive 'I considered it' assertion. | |
| reviewedSimilar | No | On create: the ids of the open look-alike issues you have READ (e.g. ['RTSC-959']). Send it only when there are any — a create with no look-alikes needs no acknowledgement and an empty list is never wrong. Retasc refuses a create while any open issue looks like the same or adjacent work — `DUPLICATE_CHECK_REQUIRED`, which names them — because duplicate work is the most expensive failure a fleet has, and it is the one thing the other three declarations never caught. Unlike `noDependency` this cannot be pre-filled blind: only the server produces these ids. Two ways through, both fine: file, read the refusal, re-call with the ids it named; or search with `list_issues` FIRST and name them yourself, which passes in one call. Unknown ids are ignored, the second call recomputes rather than trusting your list (so a look-alike filed in between is surfaced again), and this is valid ONLY on a create — passing it on an update is rejected. What to do with what you read: if one of them IS this work, do not create — comment on it or claim it; if one is adjacent, create and link it with `add_relation` after. A declared `blockedBy` also counts as having read that issue, but declare one only where the dependency is real — a blocks edge invented to clear this gate leaves the new issue undispatchable until the other one closes. |