dj-atlassian-axi
v0.1.0
Published
Jira and Confluence over the shell - AXI-standard agent-facing CLI for the Atlassian Cloud REST API.
Maintainers
Readme
dj-atlassian-axi
Jira work items and Confluence pages over the shell, shaped for agents.
dj-atlassian-axi is an AXI: an agent-ergonomic CLI that talks to the Atlassian Cloud REST API and turns it into something an agent can read without spending its context window on it.
The REST API is built for applications. It answers with avatar URLs in four sizes, self-links on every nested object, and descriptions in Atlassian Document Format: a deeply nested node tree that an agent has to walk before it can read a sentence.
| Operation | Raw REST JSON | dj-atlassian-axi | Reduction |
| --- | --- | --- | --- |
| View one work item | 8,726 bytes | 1,547 bytes | 82.3% |
| Search, 10 results | 21,257 bytes | 1,119 bytes | 94.7% |
| Read a Confluence page | 6,253 bytes | 1,466 bytes | 76.6% |
Measured against a real Jira Cloud site with identical field sets.
Install
npm install -g dj-atlassian-axiAuthentication comes from the Atlassian CLI's existing login, so on a machine that already has one there is nothing to configure:
brew install atlassian/homebrew-acli/acli
acli auth loginacli is only read from, never invoked.
It writes its site and account to plain YAML under ~/.config/acli and its API token to the system keychain, and dj-atlassian-axi reads both directly.
To skip it entirely - on Linux, in CI, or against a second site - supply the same three facts yourself:
export ATLASSIAN_AXI_SITE=your-site.atlassian.net
export [email protected]
export ATLASSIAN_AXI_TOKEN=... # id.atlassian.com/manage-profile/security/api-tokensEach is resolved independently, so setting one overrides only that one.
dj-atlassian-axi stores no credentials of its own and never writes a token anywhere.
Use
Running it with no arguments shows live content rather than a usage manual:
$ dj-atlassian-axi
bin: ~/.local/bin/dj-atlassian-axi
description: Jira work items and Confluence pages over the shell
site: your-site.atlassian.net
count: 10 of 15 total
project: DAP
workitems[10]{key,type,status,summary}:
DAP-2315,Bug,In Progress,"[Checkout] Add New Address keyboard navigation is not accessible"
DAP-2389,Story Bug,In Progress,"[Checkout] Shipping address suggestion selection does not work"
DAP-2163,Task,PR Review,Spike - best way to share AI skills
help[3]:
Run `dj-atlassian-axi --full` to see all 15
Run `dj-atlassian-axi view DAP-2315` for the description and comments
Run `dj-atlassian-axi search --jql '<query>'` for any other query| Command | Purpose |
| --- | --- |
| dj-atlassian-axi | work items assigned to you that are still open |
| dj-atlassian-axi search --jql "..." | find work items with JQL |
| dj-atlassian-axi view <KEY> | one work item, with description and comments |
| dj-atlassian-axi transition <KEY> --to "<status>" | move a work item |
| dj-atlassian-axi comment <KEY> --body "<text>" | add a comment |
| dj-atlassian-axi assign <KEY> --to me | change the assignee |
| dj-atlassian-axi page <ID> | read a Confluence page |
| dj-atlassian-axi auth | show the active site and account |
| dj-atlassian-axi setup hooks | install the agent session-start hooks |
Every subcommand has its own --help with flags, defaults, and examples.
Design
dj-atlassian-axi implements the ten AXI principles.
The ones that do the most work here:
Flattened Atlassian Document Format.
This is the single largest saving.
A description arrives as a nested tree of doc, paragraph, taskList, orderedList, mediaSingle and mark nodes; it leaves as plain text with light Markdown.
Checkboxes stay checkboxes, code stays code, links keep their targets, and unknown future node types still surface their text rather than vanishing.
Truncation with an escape hatch. Long descriptions and comments are cut on a line boundary, and the total length is always reported, so nothing is ever silently lost:
... (truncated, 4211 chars total)
help[1]:
Run `dj-atlassian-axi view DAP-2389 --full` for the complete description (4211 chars)Pre-computed aggregates.
Lists report the true total, not just the page size, so an agent never paginates to find out how many matches exist.
The extra count query only runs when the page came back full, since otherwise the page already is the total.
Comment blocks report comments[5 of 23] for the same reason.
Hoisted constant columns. When every row shares a project or status, it is stated once as a scalar and dropped from the table instead of repeating on every line.
Definitive empty states. An empty result is a sentence, not silence:
workitems: 0 - no work items match that queryIdempotent mutations. Transitioning a work item to the status it already has is reported as a no-op and exits 0, rather than failing:
$ dj-atlassian-axi transition DAP-2389 --to "In Progress"
workitem: DAP-2389 is already In Progress (no-op)Structured errors on stdout. Errors are written to stdout in the same shape as normal output, translated to a single phrase, and paired with a next step. ANSI colour codes and REST payloads never reach the agent:
$ dj-atlassian-axi view DAP-99999999
error: no such item
help[1]:
Check the key, or run `dj-atlassian-axi search --jql '<query>'` to find itJira deliberately conflates "does not exist" and "you lack permission" into one message so it cannot leak the existence of restricted issues.
dj-atlassian-axi reports that honestly as no such item rather than guessing at which it was.
Fail loud on unknown input. An unrecognised flag exits 2 and lists the valid flags for that subcommand, so a wrong guess never returns plausible-looking output the agent believes was filtered:
$ dj-atlassian-axi search --query "project = DAP"
error: unknown flag --query for `search`
help[2]:
--query is not a flag here; use --jql instead
Run `dj-atlassian-axi search --help` for the full referenceFlags are validated against the subcommand actually in play, not a merged global list.
No interactive prompts. Every operation completes with flags alone, and nothing this tool runs can ask a question. Reading the keychain is the one subprocess it ever starts, and it is given a hard deadline precisely because macOS may raise a permission dialog: a missing token falls back to the environment rather than blocking an agent's session on a dialog nobody is watching.
An empty answer has to be a true answer.
Jira replies to a malformed JQL query with 200 and an empty page rather than an error, so "nothing matched" and "that query was nonsense" are indistinguishable at the transport.
An agent believes a definitive empty state, so a search that returns nothing is checked against Jira's own JQL parser before it is reported as empty:
$ dj-atlassian-axi search --jql "project = NOPE"
error: The value 'NOPE' does not exist for the field 'project'.That costs a request only when there were no results, and the parser names the offending field far more precisely than any local rule could.
Latency is a token cost too. An agent waiting on a command is an agent not doing work, and the session-start hook pays whatever this costs on every session in every harness.
| | via acli | direct REST |
| --- | --- | --- |
| dj-atlassian-axi | 3.19s | 0.82s |
| dj-atlassian-axi --hook | 3.18s | 0.84s |
| dj-atlassian-axi view <KEY> --comments | 2.75s | 0.80s |
Medians of interleaved runs against a live site, so network drift falls on both.
The gap is almost entirely process startup: acli --version, which does no work at all, costs around a second on its own, and every fact a command needs used to cost another one.
Over HTTP independent lookups simply overlap, so the page, the total and the credential all resolve together.
Exit codes
| Code | Meaning | | --- | --- | | 0 | success, including no-ops and empty results | | 1 | the operation could not be completed | | 2 | usage error: unknown command, unknown flag, bad or missing value |
Ambient context
dj-atlassian-axi setup hooks registers a SessionStart hook for Claude Code, Codex, GitHub Copilot CLI, and opencode, so each new agent session opens already knowing what is assigned to you.
dj-atlassian-axi setup hooksInstalls are idempotent, and re-running after moving the binary repairs the recorded path.
The injected view is deliberately tighter than the interactive one: 5 rows instead of 10, and none of the self-identifying preamble or discovery suggestions, because it is paid for on every session in every harness. That is 676 bytes rather than 1,322.
An installable skill is also shipped in skills/dj-atlassian-axi, for agents whose harness has no hook support or where the per-session cost is not worth paying:
npx skills add atz-dsampath/dj-atlassian-axi --skill dj-atlassian-axiThe hook and the skill achieve the same discovery; you only need one. The hook adds live state, the skill costs nothing until it is invoked.
Development
npm test # 45 unit tests, no network requiredThe TOON encoder, the ADF codec, the profile parser, the argument parser, and the error translator are all pure functions and fully covered.
Anything that touches the network lives behind src/http.mjs.
| File | Responsibility |
| --- | --- |
| src/toon.mjs | TOON encoding, applied only at the output boundary |
| src/adf.mjs | Atlassian Document Format to plain text, and back |
| src/config.mjs | reading the Atlassian CLI's profile files |
| src/auth.mjs | credential resolution, environment then keychain |
| src/http.mjs | the only module that reaches the network |
| src/errors.mjs | raw failures to one phrase plus a next step |
| src/commands.mjs | command implementations |
| src/cli.mjs | parsing, per-subcommand help, dispatch |
Zero runtime dependencies.
License
MIT.
