axon drives an Axon project from a terminal. axon-mcp hands the same operations to an AI agent as typed MCP tools. Both ship in one package and talk to the same v1 REST API.
bun add -g axonjira axon --help
bunx --package axonjira axon --help
The package installs two binaries: axon and axon-mcp. Node 20 or newer.
An API key authorises exactly one project, so a key and a project id always travel together. Create one in the app under Settings -> API Keys. Scopes are ranked rather than additive - read < write < admin - and every delete needs admin.
export AXON_API_KEY="axj_<keyId>.<secret>" export AXON_PROJECT_ID="<projectId>" export AXON_BASE_URL="https://axonjira.com" # optional
{
"defaultProject": "acme",
"projects": {
"acme": { "apiKey": "axj_...", "projectId": "..." }
}
}Resolution is per field, in the order flags, environment, file - so a key in the environment beside a project id in the file is a normal, working combination. axon config reports what resolved and where each field came from, and never prints the key itself.
Accepted by every command.
| Option | Description |
|---|---|
| --json | Print the result as JSON on stdout, and nothing else. |
| -y, --yes | Confirm a destructive command without being asked. |
| --no-color | Turn color off. $NO_COLOR does the same. |
| --profile <name> | Config-file profile to take credentials from. |
| --project <id> | Project id, overriding the configured one. |
| --base-url <url> | API origin or root to talk to. |
| --limit <n> | Items per page. The API caps it at 100. |
| --cursor <c> | Resume from the nextCursor of an earlier page. |
| --all | Walk every page instead of returning the first. |
| --timeout <ms> | Per-attempt timeout. 0 disables it. |
| --retries <n> | Retries per request on 429, 5xx and network failure. |
| --idempotency-key <key> | Re-running with the same key replays the first result instead of writing twice. |
| -h, --help | Show help for the CLI, a group, or a command. |
| -V, --version | Print the CLI version. |
50 commands across 12 groups. Every command also takes the global options above.
axon whoami
Show the project and scopes this key is bound to
Runs show when no command is named.
One request, to the only endpoint that is not scoped to a project id: it resolves the project from the key itself. The workflow statuses it prints are per project and are not an enum. Their ids are what `axon task move` and `axon task list --status` take, and this is the only place to read them.
Examples
axon whoami axon whoami --json
axon config
Show where this CLI takes its credentials and base URL from
Runs show when no command is named.
Reports what this process resolved, not what any one file says: a key from the environment and a project id from the config file is a normal mix, and the source beside each field is what makes that legible. Succeeds even when nothing resolves - that is the case it exists to diagnose - and says so through `configured`. The API key itself is never printed, in full or in part, only where it was found. Makes no requests.
Examples
axon config axon config --json
axon task
Create, find and change tasks
Filters combine as AND. Ids are printed raw: turning an assignee id into a name would cost a request per listing against a 120-a-minute ceiling. `axon member list` is the map.
Options
| --status <status> | Workflow status, by id or by name. `axon whoami` lists them. |
| --assignee <userId> | Assignee, as a member userId. |
| --sprint <sprintId> | Sprint id. |
| --epic <epicId> | Epic id. |
| --priority <priority> | Priority.one of: critical, high, medium, low |
| --type <type> | Task type.one of: epic, story, bug, task |
| --fix-version <versionId> | Version id. |
| --label <labelId> | Label document id from `axon label list`, not a label name. One per request. |
| --title-prefix <prefix> | Case-sensitive PREFIX match on the title alone, not a search: "auth" finds "auth token expiry" but neither "Auth token expiry" nor "fix auth token expiry", and a description is never looked at. Imposes a title-ascending sort. |
| --due-before <date> | Due before this ISO date. Tasks with no due date are excluded. |
| --due-after <date> | Due after this ISO date. Tasks with no due date are excluded. |
| --order-by <order-by> | Sort field. A due-date range forces dueDate.one of: createdAt, updatedAt, dueDate |
| --order <order> | Sort direction.one of: asc, desc |
Examples
axon task list --status in_progress --assignee u_123 axon task list --due-before 2026-10-01 --order asc
Arguments
| <ref> | Task key (AXO-42) or task document id. |
Examples
axon task view AXO-42
`--title` is the only required flag. The task is always created at the first status of the workflow; `axon task move` takes it from there.
Options
| --title <text> | Title. |
| --description <text> | Description. |
| --priority <priority> | Priority.one of: critical, high, medium, low |
| --type <type> | Task type.one of: epic, story, bug, task |
| --assignee <userId> | Assignee, as a member userId. Pass an empty value to unassign. |
| --sprint <sprintId> | Sprint id, from `axon sprint list`. An empty value means none. |
| --epic <epicId> | Epic id, from `axon epic list`. An empty value means none. |
| --fix-version <versionId> | Version id, from `axon version list`. An empty value means none. |
| --label <labelId> | Label id, from `axon label list`, not a label name. Repeatable and comma-separated. The ids replace the task's whole set; an empty value clears it. |
| --points <n> | Story points: 1, 2, 3, 5, 8, 13, 21. An empty value means unestimated. |
| --due <date> | Due date, ISO 8601. An empty value means none. |
Examples
axon task create --title "fix the build" --priority high --points 3
Only the flags you type are sent, so an untouched field keeps its value and an empty value on a nullable flag clears it. There is no --status here: a transition runs the project's workflow rules and can be refused, so `axon task move` owns it and the change is always explicit. --label takes label ids and replaces the whole set, so pass every id the task should end up with and --label "" to clear them. Names are not looked up: that would be a request you did not ask for, and `axon label list` is the map.
Arguments
| <ref> | Task key (AXO-42) or task document id. |
Options
| --title <text> | Title. |
| --description <text> | Description. |
| --priority <priority> | Priority.one of: critical, high, medium, low |
| --type <type> | Task type.one of: epic, story, bug, task |
| --assignee <userId> | Assignee, as a member userId. Pass an empty value to unassign. |
| --sprint <sprintId> | Sprint id, from `axon sprint list`. An empty value means none. |
| --epic <epicId> | Epic id, from `axon epic list`. An empty value means none. |
| --fix-version <versionId> | Version id, from `axon version list`. An empty value means none. |
| --label <labelId> | Label id, from `axon label list`, not a label name. Repeatable and comma-separated. The ids replace the task's whole set; an empty value clears it. |
| --points <n> | Story points: 1, 2, 3, 5, 8, 13, 21. An empty value means unestimated. |
| --due <date> | Due date, ISO 8601. An empty value means none. |
| --resolution <resolution> | Resolution. An empty value clears it.one of: done, wont_do, duplicate, cannot_reproduce |
Examples
axon task update AXO-42 --points 5 --assignee "" axon task update AXO-42 --label lbl_1,lbl_2
The status is matched against the project's own workflow, by id or by name. A transition the workflow forbids comes back as a 409 naming the rules that refused it, and some transitions require a comment: pass --comment for those.
Arguments
| <ref> | Task key (AXO-42) or task document id. |
| <status> | Target workflow status, by id or name. |
Options
| --comment <text> | Comment recorded against the transition. Required by some of them. |
Examples
axon task move AXO-42 "in review" --comment "ready for a look"
Takes a member userId, which `axon member list` prints.
Arguments
| <ref> | Task key (AXO-42) or task document id. |
| [userId] | Member userId to assign the task to. |
Options
| --unassign | Clear the assignee instead of setting one. |
Examples
axon task assign AXO-42 u_123 axon task assign AXO-42 --unassign
Sugar for `axon comment add`, which is the same call.
Arguments
| <ref> | Task key (AXO-42) or task document id. |
| <text...> | The comment body. Every remaining word is joined with spaces. |
Examples
axon task comment AXO-42 deployed to staging
Needs an `admin` key. Permanent, and nothing that references the task is cleaned up: comments, activity, and any task blocked by this one are all left pointing at an id that no longer resolves.
Arguments
| <ref> | Task key (AXO-42) or task document id. |
axon comment
Read and write the comments on a task
Oldest first. The ids printed here are what `comment edit` and `comment delete` take.
Arguments
| <taskRef> | Task key (AXO-42) or task document id. |
Posts as the key's own identity, with the author name `API`. Only comments posted this way can be edited or deleted through the API.
Arguments
| <taskRef> | Task key (AXO-42) or task document id. |
| <text...> | The comment body. Every remaining word is joined with spaces. |
Examples
axon comment add AXO-42 deployed to staging
The whole body is replaced; there is no partial edit. A key may only edit a comment it authored itself. Anyone else's is a 403, an `admin` key included.
Arguments
| <taskRef> | Task key (AXO-42) or task document id. |
| <commentId> | The comment id, from `axon comment list`. |
| <text...> | The comment body. Every remaining word is joined with spaces. |
A hard delete. Needs an `admin` key, and a key may only delete a comment it authored itself - anyone else's is a 403 however wide the key's scope.
Arguments
| <taskRef> | Task key (AXO-42) or task document id. |
| <commentId> | The comment id, from `axon comment list`. |
axon ticket
File and triage intake tickets
Newest first.
Options
| --status <status> | Ticket status.one of: open, in_progress, resolved, closed |
| --type <type> | Ticket type.one of: bug, feature, improvement, question |
Examples
axon ticket list --status open --type bug
Arguments
| <id> | The ticket document id, from `axon ticket list`. |
`--type`, `--title`, `--description` and `--priority` are all required; the description may be empty but must be given. The ticket is created open, unassigned and unlinked.
Options
| --type <type> | Ticket type.one of: bug, feature, improvement, question |
| --title <text> | Title. |
| --description <text> | Description. |
| --priority <priority> | Priority.one of: critical, high, medium, low |
| --steps <text> | Steps to reproduce. |
| --expected <text> | Expected result. |
| --actual <text> | Actual result. |
| --environment <text> | Environment: browser, build, device. |
| --page-url <url> | Where it happened. Must be an absolute http(s) URL. |
| --component <componentId> | Component id, from `axon component list`. |
| --needed-by <date> | When it is needed. Becomes the converted task's due date. |
| --notify | Notify the project members. Fixed at creation and not editable after. |
Examples
axon ticket create --type bug --title "login loops" --description "" --priority high
Only the flags you type are sent, so an untouched field keeps its value and an empty value on a nullable flag clears it. The status is not here: `axon ticket move` owns it, so a lifecycle change is always a deliberate one. --notify cannot be changed after creation.
Arguments
| <id> | The ticket document id, from `axon ticket list`. |
Options
| --type <type> | Ticket type.one of: bug, feature, improvement, question |
| --title <text> | Title. |
| --description <text> | Description. |
| --priority <priority> | Priority.one of: critical, high, medium, low |
| --assignee <userId> | Assignee, as a member userId. Pass an empty value to unassign. |
| --steps <text> | Steps to reproduce. |
| --expected <text> | Expected result. |
| --actual <text> | Actual result. |
| --environment <text> | Environment: browser, build, device. |
| --page-url <url> | Where it happened. Must be an absolute http(s) URL. |
| --component <componentId> | Component id, from `axon component list`. |
| --needed-by <date> | When it is needed. Becomes the converted task's due date. |
| --resolution-note <text> | Resolution note. Cleared by a move back to open or in_progress, whatever is sent. |
The four statuses are fixed: open, in_progress, resolved, closed. They are an enum of the API's own, not the project workflow a task moves through. Moving to resolved stamps who resolved it and when; moving back to open or in_progress clears those and the resolution note with them.
Arguments
| <id> | The ticket document id, from `axon ticket list`. |
| <status> | One of: open, in_progress, resolved, closed. |
Examples
axon ticket move 8f2c1a resolved
Takes a member userId, which `axon member list` prints.
Arguments
| <id> | The ticket document id, from `axon ticket list`. |
| [userId] | Member userId to assign the ticket to. |
Options
| --unassign | Clear the assignee instead of setting one. |
Creates the task, links the two and moves the ticket to in_progress. What comes back is the new TASK, not the ticket - that is what is printed and what --json carries. The ticket is named by the id you passed, since the response does not carry its key and looking it up would be a second request. A ticket already linked to a task is a 409.
Arguments
| <id> | The ticket document id, from `axon ticket list`. |
Options
| --type <type> | Task type, overriding the one derived from the ticket type (bug -> bug, feature -> story, anything else -> task).one of: epic, story, bug, task |
Examples
axon ticket convert 8f2c1a --type story
axon sprint
Plan, start and close sprints
Newest first.
Options
| --status <status> | Sprint status.one of: planning, active, completed |
Examples
axon sprint list --status active
Arguments
| <id> | The sprint document id, from `axon sprint list`. |
`--name`, `--start` and `--end` are required. The sprint is created at status planning; `axon sprint start` begins it.
Options
| --name <text> | Sprint name. |
| --start <date> | Start date, ISO 8601. |
| --end <date> | End date, ISO 8601. Must be after the start date. |
| --goal <text> | Sprint goal. |
| --capacity <points> | Capacity in story points. An empty value means none. |
Examples
axon sprint create --name "Sprint 14" --start 2026-10-01 --end 2026-10-15 --capacity 34
Only the flags you type are sent, so an untouched field keeps its value. A date is checked against the merged sprint, so moving one end alone cannot leave the sprint ending before it starts. The status belongs to `start` and `complete` and cannot be set here.
Arguments
| <id> | The sprint document id, from `axon sprint list`. |
Options
| --name <text> | Sprint name. |
| --goal <text> | Sprint goal. |
| --start <date> | Start date, ISO 8601. |
| --end <date> | End date, ISO 8601. Must be after the start date. |
| --capacity <points> | Capacity in story points. An empty value means none. |
Needs an `admin` key, and there is no way back through this API. Starting overwrites the sprint's start date with the current time and snapshots its tasks and points as the commitment the burndown is measured against - both are written once and never again. A sprint that is not in planning, or a project that already has an active sprint, is a 409.
Arguments
| <id> | The sprint document id, from `axon sprint list`. |
Needs an `admin` key, and there is no way back through this API. Every task in a done status is stamped as completed in this sprint, and everything else is moved out of it - an unfinished task loses its sprint and lands back in the backlog. A sprint that is not active is a 409.
Arguments
| <id> | The sprint document id, from `axon sprint list`. |
axon epic
Work with epics
Arguments
| <id> | The epic id. |
Creates an epic at the rollup status the API computes for an empty epic. There is deliberately no --status: an epic's status is derived from its tasks and sub-epics, and sending one is a 400.
Options
| --name <text> | Epic name. Required. |
| --description <text> | Description. |
| --color <hex> | Color as #rrggbb. The API picks one from its palette when omitted. |
| --start <date> | Start date, ISO 8601. |
| --target <date> | Target date, ISO 8601. |
| --parent <epicId> | Parent epic id. |
Examples
axon epic create --name "Checkout revamp" --target 2026-12-31
Sends only the flags you type, so a field you do not name keeps its value. A --parent that would make the epic its own ancestor is refused as a conflict; an id that is not an epic is a validation failure.
Arguments
| <id> | The epic id. |
Options
| --name <text> | Epic name. |
| --description <text> | Description. |
| --color <hex> | Color as #rrggbb. The API picks one from its palette when omitted. |
| --start <date> | Start date, ISO 8601. |
| --target <date> | Target date, ISO 8601. |
| --parent <epicId> | Parent epic id. Pass an empty value to re-root it. |
Examples
axon epic update epc_1 --parent ''
Needs a key with the `admin` scope. The epic is emptied before it is removed: its tasks are detached and its sub-epics re-rooted. On a large epic that cascade runs in batches, so a failure part-way can leave tasks already detached from an epic that still exists. Re-run it, and check the epic before assuming nothing changed.
Arguments
| <id> | The epic id. |
axon version
Work with versions
Arguments
| <id> | The version id. |
The version is always created `unreleased`. Use `axon version release` once it ships.
Options
| --name <text> | Version name. Required. |
| --description <text> | Description. |
| --start <date> | Start date, ISO 8601. |
| --release <date> | Release date, ISO 8601. |
Examples
axon version create --name 1.4.0 --start 2026-10-01
Sends only the flags you type, so a field you do not name keeps its value. Moving --status to released stamps the release date with the current time unless --release is given in the same command, which is how a release that already happened gets backdated.
Arguments
| <id> | The version id. |
Options
| --name <text> | Version name. |
| --description <text> | Description. |
| --status <status> | Version status.one of: unreleased, released, archived |
| --start <date> | Start date, ISO 8601. |
| --release <date> | Release date, ISO 8601. |
Examples
axon version update ver_1 --status released --release 2026-09-01
Shorthand for `axon version update <id> --status released`, and the same request. The release date is stamped with the current time; to backdate it, use `update` and pass --release.
Arguments
| <id> | The version id. |
Needs a key with the `admin` scope. Every task carrying this fix version is detached from it first, then the version is removed.
Arguments
| <id> | The version id. |
axon component
Work with components
Arguments
| <id> | The component id. |
Options
| --name <text> | Component name. Required. |
| --description <text> | Description. |
| --lead <userId> | Lead, as a member userId - the userId column of `axon member list`, not its id. |
Examples
axon component create --name Billing --lead uid_42
Sends only the flags you type, so a field you do not name keeps its value.
Arguments
| <id> | The component id. |
Options
| --name <text> | Component name. |
| --description <text> | Description. |
| --lead <userId> | Lead, as a member userId - the userId column of `axon member list`, not its id. Pass an empty value to clear it. |
Examples
axon component update cmp_1 --lead ''
Needs a key with the `admin` scope. The id is stripped from every task that carries it and cleared from every ticket that points at it first, then the component is removed.
Arguments
| <id> | The component id. |
axon label
Work with labels
Two things here differ from the app on purpose. Names are unique within the project, compared trimmed and case-insensitively, and creating or renaming onto a name already in use is a conflict rather than a silent hand-back of the existing label. The conflict carries that label's id as `labelId`, which is the id you were after. Deleting answers with a body rather than an empty 204: the id is stripped from every task carrying it first, and the count of tasks that changed is reported.
A label id from here is what every other --label takes - `axon task list` to filter by one, `axon task create` and `axon task update` to put them on a task. A label name is not: nothing resolves one for you.
Arguments
| <id> | The label id. |
Names are unique within the project, compared trimmed and case-insensitively. A name already in use is a conflict, not a quiet re-use of the existing label: the error carries that label's id as `labelId`, which is the id you wanted anyway. This command does not turn that into a find-or-create, because "Bug" and "bug " differ by a typo as often as by intent.
Options
| --name <text> | Label name. Required. |
| --color <hex> | Color as #rrggbb. Derived from the name when omitted, as the app derives it. |
Examples
axon label create --name regression --color "#c62828"
Sends only the flags you type, so a field you do not name keeps its value. Renaming onto another label's name is a conflict carrying that label's id.
Arguments
| <id> | The label id. |
Options
| --name <text> | Label name. |
| --color <hex> | Color as #rrggbb. Derived from the name when omitted, as the app derives it. |
Needs a key with the `admin` scope. The id is stripped from every task carrying it first, then the label is removed. The count of tasks that changed is reported, and is the only record of how far the strip reached - those tasks cannot be given the label back, because it no longer exists to be named.
Arguments
| <id> | The label id. |
axon member
Look up project members
A member carries two ids and they are not interchangeable. `userId` is what --assignee and --lead accept; `id` is the membership document and is accepted nowhere. The listing leads with `userId` for that reason. Membership is managed in the app; this API only reads it.
The USERID column is the value every other command wants: `axon task create --assignee`, `axon task list --assignee` and `axon component create --lead` all take a userId. The membership document also has its own `id`, visible under --json. It is not a userId and no command accepts it.
Examples
axon member list --all
axon event
Read the project activity log
Activity from the app and from this API alike. The default page is 50 events; --limit takes up to 100 and --all walks the whole log. An event without a TASK is project-level rather than about one task. The per-event `metadata` is under --json.
Examples
axon event list --limit 20
Distinct per error class, so a script can branch without reading the message.
| 0 | success |
| 1 | unexpected error |
| 2 | bad usage |
| 3 | missing or malformed configuration |
| 4 | not found |
| 5 | unauthorized or forbidden |
| 6 | conflict |
| 7 | validation failed |
| 8 | rate limited |
| 9 | network failure |
| 10 | webhook loop depth exceeded |
48 tools named axon_<resource>_<verb>, over the same API.
Point an MCP client at the built axon-mcp binary. For Claude Code, an .mcp.json beside your project:
{
"mcpServers": {
"axon": {
"command": "bunx",
"args": [
"--package",
"axonjira",
"axon-mcp"
],
"env": {
"AXON_API_KEY": "axj_<keyId>.<secret>",
"AXON_PROJECT_ID": "<projectId>"
}
}
}
}AXON_BASE_URL, AXON_PROFILE and AXON_LOOP_DEPTH are optional. Set AXON_LOOP_DEPTH when the server runs inside something reacting to an Axon webhook: it is passed through as x-axon-webhook-loop-depth, so a chain of agents reacting to each other is refused by the API rather than running forever. The server fails at startup, loudly, when credentials cannot be resolved.
Describe the key this server is using and the project it is bound to. CALL THIS FIRST when you do not already know the project: it returns the project id, code and name, the key's scopes, and the project's whole vocabulary - `workflow` as `id` + `label` pairs, plus task types, priorities, ticket statuses and ticket types. Workflow statuses are defined per project and are NOT a fixed enum, so this is the only way to learn the status ids `axon_task_move` takes and `axon_task_list` filters on; `isDone` on a status marks the ones that close work. The scopes say what the key may do at all: `read` to look, `write` to create and change, `admin` for every delete. A missing scope is a refusal no retry can fix. Takes no arguments and writes nothing.
One page of tasks. Filters combine as AND, and paging is explicit: follow `nextCursor` to read more. Ids come back raw - `axon_member_list` maps an assignee id to a person and `axon_sprint_list` a sprint id to a sprint. Not every filter combination is indexed; one that is not is refused with a 400 asking for fewer filters or the default sort, not a 500.
One task in full, by key or by document id. A key has an endpoint of its own, so either form is a single request. The task carries fields this API cannot write - subtasks, attachments, blockers, time tracking - because it is serialized straight from the stored document.
Creates a task. Only `title` is required. The task is always created at the workflow's first status; `axon_task_move` takes it from there. Counts against a limit of 30 task creations a minute per reporter.
Changes a task's fields. Only the fields you send are written; anything omitted keeps its value, and a nullable field set to null is cleared. There is deliberately no `status` here. The API writes the other fields first and applies a transition afterwards, so one request carrying both can land the edits and still fail the move with a 409; `axon_task_move` owns the status instead, and nothing here can leave a half-applied update behind. `labelIds` is the field that puts labels on a task, and it is the one the app renders and `axon_task_list` filters by. The older `labels` is refused with a 400, so do not reach for it: they are different fields, not two spellings of one.
Moves a task to another workflow status, running the project's own transition rules. This is the only way to change a task's status. A rule that refuses the move is a 409 whose `details.errors` names every validator that failed - read it and fix the cause (assign the task, close the blocker, add the comment) rather than retrying the same call. Some transitions require a comment and refuse the move without one. A resolution is not set here: use `axon_task_update`, which can write one before or after the move.
Assigns a task to a project member, or unassigns it. `assigneeId` is required rather than optional, so unassigning is an explicit `assigneeId: null` and can never happen by omission.
Deletes a task for good. Needs an `admin` key. Nothing that references the task is cleaned up: its comments, its activity and any task blocked by it are all left pointing at an id that no longer resolves. The endpoint is addressed by document id, so a key is resolved to one first - that costs an extra request.
One page of the comments on a task, oldest first. The `id` of each is what `axon_comment_update` and `axon_comment_delete` take, and `authorId` is what the API compares against this key's own identity when deciding whether a comment may be edited at all.
Adds a comment to a task. It posts as the key's own identity with the author name `API`, and only comments posted this way can be edited or deleted through this API afterwards.
Replaces the text of a comment. The whole body is replaced; there is no partial edit. A key may only edit a comment it authored itself - anyone else's is a 403, an `admin` key included, and retrying will not help.
Deletes a comment for good. Needs an `admin` key. A key may only delete a comment it authored itself - anyone else's is a 403 however wide the key's scope. Unlike the other deletes in this API this one answers with a record rather than an empty response, so the deleted id comes back.
One page of tickets, newest first. This is also how a ticket id is found: tickets are addressed by document id everywhere else in this API, and the `id` field here is that id.
One ticket in full, by document id.
Files a ticket. `ticketType`, `title`, `description` and `priority` are all required - the description may be an empty string, but it has to be sent. The ticket is created open, unassigned and unlinked. It is an intake record, not work: `axon_ticket_convert` turns it into a task when someone decides to do it.
Changes a ticket's fields. Only the fields you send are written; anything omitted keeps its value, and a nullable field set to null is cleared. The status is not here: `axon_ticket_move` owns it, so a lifecycle change is always deliberate. `notifyMembers` cannot be changed after creation.
Moves a ticket through its own lifecycle. The four statuses are a fixed enum of the API's, not the workflow statuses a task moves through, and no project rules are run. Moving to `resolved` stamps who resolved it and when; moving back to `open` or `in_progress` clears those and the resolution note with them.
Assigns a ticket to a project member, or unassigns it. `assigneeId` is required rather than optional, so unassigning is an explicit `assigneeId: null` and can never happen by omission. Assigning a ticket does not assign the task a conversion creates.
Turns a ticket into a task: creates the task, links the two, and moves the ticket to `in_progress`. WHAT COMES BACK IS THE NEW TASK, NOT THE TICKET. Read `data.task` for the task that was created - its key and id are what everything else in this API takes. The ticket itself is unchanged in the response because it is not in the response; read it back with `axon_ticket_get` if you need it. A ticket already linked to a task is a 409, and the new task counts against the limit of 30 task creations a minute per reporter.
One page of sprints, newest first. This is where a sprint id comes from - the `sprintId` every task tool takes is the `id` field here.
One sprint in full, by document id. `committedTaskIds` and `committedStoryPoints` are absent until the sprint is started: they are the snapshot a burndown is measured against, written once by `axon_sprint_start`.
Creates a sprint. `name`, `startDate` and `endDate` are required. The sprint is created at status `planning` and holds no tasks: put tasks in it with `axon_task_update` (`sprintId`), then begin it with `axon_sprint_start`, which is a separate and irreversible call.
Changes a sprint's fields. Only the fields you send are written. A date is validated against the merged sprint, so moving one end alone cannot leave the sprint ending before it starts. There is no `status` field: the API rejects one outright. A sprint's status is changed only by `axon_sprint_start` and `axon_sprint_complete`.
Starts a sprint. Needs an `admin` key, and there is no way back through this API. Starting OVERWRITES the sprint's start date with the current time, and snapshots the tasks in it and their points as the commitment every burndown is measured against - both are written once and never again, so a sprint started before its scope is ready has the wrong commitment for good. A sprint that is not in `planning`, or a project that already has an active sprint, is a 409.
Completes a sprint. Needs an `admin` key, and there is no way back through this API. Every task in a done status is stamped as completed in this sprint; EVERYTHING ELSE IS MOVED OUT OF THE SPRINT - an unfinished task loses its sprint and lands back in the backlog. Check what is still open with `axon_task_list` before calling this. A sprint that is not `active` is a 409.
List the project's epics, newest first, one page at a time. An epic id from here is what a task's `epicId` takes, and `parentEpicId` is null on a top-level epic. An epic's `status` is a read-only rollup recomputed from its tasks and sub-epics, not a field anything can set.
Read one epic by id. An epic's `status` is a read-only rollup recomputed from its tasks and sub-epics, not a field anything can set.
Create an epic. There is deliberately no `status` argument: an epic's status is derived from its tasks and sub-epics, and sending one is rejected. Creating an epic attaches nothing to it - point a task at it afterwards with `axon_task_update`.
Change an epic. Only the fields you send are written, so anything you omit keeps its value. There is no `status` argument here either, for the same reason as on create.
Delete an epic. Needs a key with the `admin` scope, and there is no undo. The epic is emptied before it goes: its tasks are detached and its sub-epics re-rooted to the top level. On a large epic that cascade runs in several batches and is NOT transactional, so a failure part-way can leave tasks already detached from an epic that still exists. If this fails, re-read the epic and its tasks rather than assuming nothing changed.
List the project's versions, newest first, one page at a time. A version id from here is what a task's `versionId` (its fix version) takes.
Read one version by id, including its status and release date.
Create a version. It is always created `unreleased`, whatever dates you give it; ship it later with `axon_version_release`.
Change a version. Only the fields you send are written, so anything you omit keeps its value. This is also the way to release one: send `status: "released"`, with a `releaseDate` if the release already happened and should be backdated.
Mark a version released. Exactly the request `axon_version_update` makes with `status: "released"` and nothing else, so the release date is stamped with the current time; to record a release that already happened, use `axon_version_update` and pass `releaseDate` as well. Releasing a version that is already released leaves its release date alone.
Delete a version. Needs a key with the `admin` scope, and there is no undo. Every task carrying this fix version is detached from it first, then the version goes - so tasks survive, but their `versionId` is cleared and there is no record of which ones it was.
List the project's components, newest first, one page at a time. A component id from here is what a task's `componentIds` and a ticket's `componentId` hold; `leadId` is a member `userId`.
Read one component by id. Its `leadId` is a member `userId`; resolve it to a person with `axon_member_list`.
Create a component. Creating one attaches nothing to it; tasks and tickets point at a component of their own accord.
Change a component. Only the fields you send are written, so anything you omit keeps its value.
Delete a component. Needs a key with the `admin` scope, and there is no undo. The id is stripped from every task that carries it and cleared from every ticket that points at it first, then the component goes - so the work survives, but which items belonged to the component is not recorded anywhere afterwards.
List the project's labels, newest first, one page at a time. A label's `id`, not its `name`, is what `axon_task_list` filters on, so resolving a name to an id starts here. Putting a label on a task happens elsewhere: send the id in the `labelIds` of `axon_task_create` or `axon_task_update`, which replaces that task's whole set.
Read one label by id. `nameNormalised` is the trimmed, lowercased form the uniqueness check compares, which is why "Bug" and "bug " collide.
Create a label. Names are unique within the project, compared trimmed and case-insensitively. A name already in use is a CONFLICT rather than a quiet hand-back of the existing label, and the conflict carries that label's id in `details.labelId` - which is the id you were after, so a conflict here is recoverable rather than fatal: read the id out of the error and use it instead of retrying. This is deliberately not a find-or-create, because "Bug" and "bug " differ by a typo as often as by intent. Putting a label on a task happens elsewhere: send the id in the `labelIds` of `axon_task_create` or `axon_task_update`, which replaces that task's whole set.
Change a label. Only the fields you send are written, so anything you omit keeps its value. Renaming onto another label's name is a conflict carrying that label's id in `details.labelId`; the two labels are not merged.
Delete a label. Needs a key with the `admin` scope, and there is no undo. The id is stripped from every task's `labelIds` first, then the label goes. Unlike the other deletes this answers with a body rather than nothing: `{ id, deleted, tasksUpdated }`, where `tasksUpdated` counts the tasks that lost the label and is the only record of how far the strip reached. Putting a label on a task happens elsewhere: send the id in the `labelIds` of `axon_task_create` or `axon_task_update`, which replaces that task's whole set. Those tasks cannot be given it back afterwards: the label is gone, and `labelIds` refuses an id the project no longer has.
List the project's members, most recently joined first, one page at a time. Use it to turn a name or an email into the id other tools want. Each member carries TWO ids and they are not interchangeable: `userId` is the value `assigneeId` on a task and `leadId` on a component take, while `id` is the membership document and is accepted nowhere. Membership is managed in the Axon app; this API only reads it, so there is no tool here to add, change or remove a member.
Read the project's activity log, newest first, one page at a time. It covers what people do in the Axon app as well as what API keys do, so it is the way to see whether a change came from a teammate or from an agent: `actorName` is the literal `API` for anything this API recorded and a person's name otherwise. An event with no `taskId` is project-level rather than about one task, and the per-event `metadata` carries whatever that event type records.
Everything on this page is generated from the CLI's own command and tool declarations, so it cannot drift from what axon --help prints.