Skip to content
digiogithubPublic

About

A terminal cli for ai agents working in markdown

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jira-cli

Terminal CLI for Jira issues and Confluence knowledge bases, compatible with Bun and Node.js. It lists and fetches issues and pages, exports them to Markdown with YAML frontmatter, applies edited Markdown back to create or update them, and downloads whole Jira projects or Confluence spaces (issues, comments, changelog, pages, labels and attachments) through a resumable, rate-limited job queue.

It is the Atlassian sibling of youtrack-cli and follows the same principles: plain ESM JavaScript, zero runtime dependencies, and Markdown as the editable transport format.

Requirements

  • Bun or Node.js 18.17 or later (Node 22.5+ or Bun enable the SQLite queue backend; older runtimes use a JSONL journal).
  • An Atlassian Cloud site (https://<site>.atlassian.net) and an API token.

Installation

From a local checkout:

bun install      # or: npm install

The install script links the jira-cli and jr binaries globally for your user when you work from a local checkout (it is skipped for global installs). To relink manually:

bun link         # or: npm link

Install directly from the repository:

bun install -g github:digiogithub/jira-cli
# or
npm install -g git+https://github.com/digiogithub/jira-cli.git

Verify:

jr --help

Configuration

jr setup --url https://acme.atlassian.net --email you@example.com --token <api-token>
jr config      # shows the resolved configuration (never prints the token)
jr whoami      # checks the credentials

Confluence is assumed to live at <url>/wiki; override it with --confluence-url.

The configuration is saved (with 0600 permissions) at:

  • Linux/macOS: ~/.config/jira-cli/config.yaml or $XDG_CONFIG_HOME/jira-cli/config.yaml
  • Windows: %APPDATA%\jira-cli\config.yaml
  • or the path in JIRA_CONFIG

Environment variables override the file:

JIRA_URL=https://acme.atlassian.net JIRA_EMAIL=you@example.com JIRA_TOKEN=... jr issues list
Variable Meaning
JIRA_URL Site URL.
JIRA_EMAIL Account email. With it, requests use Basic auth (Cloud API token).
JIRA_TOKEN API token. Without an email it is sent as a Bearer personal access token.
CONFLUENCE_URL Confluence base URL, defaults to <JIRA_URL>/wiki.
JIRA_CONFIG Alternative config file path.

Jira issues

jr projects --query web
jr issues list                                   # assigned to you, most recently updated first
jr issues list --project PRJ --limit 50
jr issues list --jql "project = PRJ AND status = 'In Progress'" --json
jr issues get PRJ-123 --comments
jr issues export PRJ-123 --dependencies --comments --out ./issues
jr issues apply ./issues/PRJ-123.md
jr issues apply ./new-bug.md --dry-run
jr issues comment PRJ-123 --text "Deployed in **v1.2**"
jr issues transition PRJ-123                     # list available transitions
jr issues transition PRJ-123 "In Review"

issues export --dependencies also exports linked issues, sub-tasks and the parent.

Issue Markdown

---
kind: issue
id: "10123"
key: PRJ-123
summary: Login fails with SSO
project:
  key: PRJ
  name: Platform
issuetype: Bug
status: In Progress
priority: High
assignee:
  accountId: 5b10ac8d82e05b22cc7d4ef5
  displayName: Ana
labels:
  - auth
components:
  - web
fields:
  customfield_10016: 5
---

# PRJ-123 Login fails with SSO

Description in **Markdown**.

jr issues apply:

  • creates the issue when there is no key (needs project and issuetype) and writes the new key/id back into the file;
  • updates the issue otherwise, sending only the fields that changed compared to the live issue;
  • changes the workflow status through the matching transition when status differs;
  • sends the fields map verbatim, which gives access to any custom field (customfield_*), and assignee: null unassigns;
  • ignores read-only metadata (reporter, created, links, customFields, ...) and the comments section rendered by --comments.

Confluence knowledge base

jr kb spaces
jr kb list --space ENG                           # pages of a space
jr kb list --query "onboarding" --space ENG      # full-text search (CQL)
jr kb list --cql "label = howto ORDER BY created DESC"
jr kb get 123456
jr kb export 123456 --children --out ./kb        # page and all its descendants
jr kb apply ./kb/123456-Onboarding.md --message "Update steps"

Page Markdown

---
kind: page
id: "123456"
title: Onboarding
spaceKey: ENG
spaceId: "98765"
parentId: "123000"
status: current
version: 7
labels:
  - howto
---

# Onboarding

Page body in **Markdown**.

jr kb apply creates the page when there is no id (needs spaceId, spaceKey or --space; parentId is optional) and updates it otherwise using version + 1. If the page changed remotely after the export (remote version greater than the file's version), the update is refused unless --force is given. After a successful apply the new id/version are written back into the file, so it can be edited and applied again.

Rich text: ADF <-> Markdown

Jira Cloud (REST v3) and Confluence Cloud (REST v2) store rich text as Atlassian Document Format (ADF). jira-cli converts it to and from Markdown:

ADF Markdown
headings, paragraphs, bold, italic, strike, inline code, links CommonMark
bullet/ordered lists, code blocks, quotes, rules, hard breaks CommonMark
simple tables (header row, one paragraph per cell) GFM tables
task lists - [ ] / - [x]
info/note/warning/success/error panels > [!INFO] alert blockquotes
expand sections <details><summary>Title</summary> ... </details>
external images ![alt](url)
underline <u>text</u>
user mentions [@Name](mention:<accountId>)
smart links (inline cards) <https://...>
anything else (uploaded media, status lozenges, dates, macros, colored text, merged cells, ...) preserved losslessly as <!--adf:{...}--> comments

Keep the <!--adf:...--> comments in place when editing and those elements survive the round trip.

Bulk export

jr project export PRJ                            # Jira project into ./PRJ
jr project export PRJ --space ENG --out ./dump   # project plus a Confluence space
jr space export ENG --out ./ENG                  # only the Confluence space
jr project status --out ./dump                   # inspect progress (safe while running)

Output layout

<out>/
  export.json                    manifest: options, counts, queue stats, timestamps
  .jr-export/
    queue.db | queue.jsonl       persistent job queue
    queue.lock                   single-coordinator lock
    run.json                     current run number
  issues/
    PRJ-123/
      issue.md                   Markdown export (with comments)
      issue.json                 raw API payload (all fields + field names)
      comments.json
      changelog.json             full field history
      assets/<attachmentId>__<filename>
  pages/
    123456/
      page.md                    Markdown export
      page.json                  raw API payload plus labels
      comments.json              footer comments
      assets/<attachmentId>__<title>

Queue and resume behaviour

Every remote call is scheduled through an embedded, file-backed job queue in <out>/.jr-export (SQLite when the runtime provides bun:sqlite or node:sqlite, a JSONL journal otherwise).

  • Interrupting an export (Ctrl-C) and rerunning it with the same --out resumes it; finished jobs are not repeated.
  • Rerunning a completed export starts a new run that re-indexes the project/space and picks up new and updated content; attachments already on disk with the expected size are skipped.
  • Only one process may coordinate a directory. A lock left by a dead process is taken over automatically; --force breaks a lock on purpose and --fresh discards the queue and starts over.
  • Failed jobs are retried with exponential backoff; remaining failures are printed and the command exits with status 1.
  • Jira's /search/jql paging has known reports of tokens looping back to the first page; the indexer detects it and stops.

Flags

Flag Default Meaning
--out <dir> ./<key> Output directory.
--space <key> none (project export) Also export this Confluence space.
--jql <jql> none (project export) Extra JQL filter, e.g. type = Bug.
--since <date> none Only issues updated since this date (2024-01-31).
--limit <n> none Stop after indexing this many issues.
--rate <req/s> 5 Maximum requests per second (fractions allowed).
--concurrency <n> 4 In-process workers consuming the queue.
--no-attachments off Skip binary attachments.
--no-comments off Skip issue and page comments.
--no-changelog off Skip the issue changelog.
--fresh off Discard the previous queue state.
--force off Take over an existing coordinator lock.
--json off Print only the JSON summary on stdout.

Requests from the Jira and Confluence clients share one token bucket and are retried on 429 and 5xx, honouring Retry-After.

APIs used

  • Jira Cloud platform REST API v3: /rest/api/3/search/jql, /issue, /issue/{key}/comment, /issue/{key}/changelog, /issue/{key}/transitions, /project/search, /myself, /attachment/content/{id}.
  • Confluence Cloud REST API v2: /wiki/api/v2/spaces, /spaces/{id}/pages, /pages/{id} (body-format=atlas_doc_format), /pages/{id}/children, /labels, /attachments, /footer-comments; CQL search through v1 /wiki/rest/api/search.

See docs/implementation-plan.md for the research notes and design decisions. Jira/Confluence Data Center support is planned but not implemented yet.

Development

npm run check    # syntax check of every source file + offline test suite
bun test         # the same suite under Bun

See AGENTS.md for the repository conventions.

License

MIT

About

A terminal cli for ai agents working in markdown

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages