Skip to content

Latest commit

 

History

History
654 lines (469 loc) · 22.4 KB

File metadata and controls

654 lines (469 loc) · 22.4 KB

jira-cli Implementation Plan

Date: 2026-05-26 Inputs reviewed:

  • docs/jira-cli-prd.md
  • Sibling Rust CLIs in ..: xero-cli, posthog-cli, slack-cli, keito-cli, reddit-cli, semrush-cli, otterai-cli, ms-teams-cli, todoist-agent-cli, wordpress-cli
  • Current Atlassian Jira Cloud REST v3 and GitHub Actions documentation

Executive Recommendation

Build jira-cli as a Rust 2021 single-crate application with a public library target, matching the xero-cli shape (src/api, src/auth, src/cli, src/config, src/output, src/rate_limit, src/models). Keep the module boundaries strict enough that a future workspace split is easy, but avoid a multi-crate workspace until the ADF codec, MCP server, or generated API layer justify it.

The first shippable milestone should be agent-safe issue reads and comments, not full Jira coverage. That means: profile config, API token auth, secure token storage, typed client, /rest/api/3/search/jql cursor pagination, issue view, issue list, issue body, comment add/list, stable JSON/JSONL output, deterministic errors, and no hidden stdin reads. OAuth, full ADF round-tripping, bulk operations, Agile APIs, cache, and MCP should follow in that order.

PRD Review Notes

The PRD is directionally strong. Its core differentiation remains valid: Jira Cloud v3-native, ADF-native, cursor pagination, profile-aware, and agent-friendly. The implementation should preserve those points, but adjust a few details before coding.

  1. OAuth 3LO base URLs need explicit handling. For OAuth access tokens, Atlassian requires calls through https://api.atlassian.com/ex/jira/{cloudid}/..., after resolving accessible resources. Direct site URLs such as https://example.atlassian.net/rest/api/3/... remain suitable for API-token/basic auth. Model this as an ApiBase enum, not string concatenation scattered through endpoint modules.

  2. Treat PKCE as an auth spike, not an assumption. The PRD says OAuth 3LO PKCE, but the current Atlassian 3LO docs still describe authorization-code exchange with a client secret. Confirm whether Atlassian supports public/native PKCE for this app type before committing the UX. If not, support either a product-owned distributable 3LO app or user-provided client_id/client_secret.

  3. Build the scope catalogue from endpoint metadata. The PRD mixes broad classic scopes (read:jira-work, write:jira-work) with current granular scopes. Store both, but make auth doctor endpoint-aware and able to explain the exact missing granular scope when Jira returns 401/403.

  4. Keep ADF lossless as a goal, but implement it in tiers. Start with a robust CommonMark/GFM subset plus raw ADF preservation for unknown nodes. Full bidirectional fidelity across Jira panels, statuses, mentions, media, tables, and custom macros should be gated by snapshot corpus quality.

  5. Defer a hand-written full JQL parser. Start with macro expansion (@me, @open, @current-sprint) plus server-side validation and helpful error mapping. Add a parser once the field catalogue/cache exists, otherwise the validator will drift.

  6. MCP should be a post-core feature. It should wrap proven CLI/API operations rather than drive the initial architecture. Design output schemas now so MCP can reuse them later.

Local Best-Practice Findings

xero-cli is the best architectural base: single binary plus lib, clap derive, reqwest with rustls, keyring, miette/thiserror, comfy-table, SQLite cache, rate-limit modules, and a simple dispatch layer. Reuse that shape, but improve the parts that matter for agents.

posthog-cli and slack-cli have better agent-output patterns: JSON/JSONL output, TTY-based auto format, response envelopes (ok, data, meta), field projection, deterministic JSON errors, and pagination helpers. Jira should standardize on an envelope for all machine-readable output.

keito-cli has the strongest CI/release posture: workflow concurrency, minimal permissions, pinned action SHAs, release smoke tests, generated manpage verification, a release gate before asset builds, semver tag validation, and explicit Homebrew/Scoop publishing. Use this as the new workflow baseline.

posthog-cli and reddit-cli show the cargo-dist route. Because the PRD requires multi-platform releases, checksums, installers, and Homebrew automation, use cargo-dist for release artifact planning, but wrap it with Keito-style gates and smoke tests.

Older sibling workflows using actions/checkout@v4, actions/cache@v4, actions/upload-artifact@v4, or taiki-e/upload-rust-binary-action are acceptable historical context, not the recommended baseline for a new repo in 2026.

Target Repository Shape

jira-cli/
|-- Cargo.toml
|-- Cargo.lock
|-- build.rs
|-- LICENSE
|-- README.md
|-- CHANGELOG.md
|-- SECURITY.md
|-- .github/
|   |-- dependabot.yml
|   `-- workflows/
|       |-- ci.yml
|       |-- release.yml
|       `-- release-version-guard.yml
|-- docs/
|   |-- jira-cli-prd.md
|   |-- jira-cli-implementation-plan.md
|   |-- auth.md
|   |-- adf-spec.md
|   |-- agent-integration.md
|   |-- jql-cookbook.md
|   |-- recipes.md
|   `-- schema/
|-- src/
|   |-- main.rs
|   |-- lib.rs
|   |-- error.rs
|   |-- cli/
|   |-- api/
|   |-- auth/
|   |-- config/
|   |-- output/
|   |-- adf/
|   |-- jql/
|   |-- cache/
|   |-- rate_limit/
|   |-- models/
|   `-- mcp/
`-- tests/
    |-- cli_smoke.rs
    |-- auth_flow.rs
    |-- issue_search.rs
    |-- pagination.rs
    |-- adf_roundtrip.rs
    `-- fixtures/

Core Architecture

CLI Layer

Use clap derive with a thin main.rs:

  • parse CLI
  • initialize logging based on global flags/env
  • convert top-level args into GlobalArgs
  • dispatch to command modules
  • map JiraCliError to exit codes and JSON/text diagnostics

Global flags should include --profile, --site, --output, --fields, --no-input, --no-color, --quiet, --verbose, --dry-run, --debug-curl, --config, --log, --log-format, --page-size, --max, and --all.

Use aliases sparingly but intentionally:

  • jira search as alias for jira issue list --jql
  • jira issue body KEY for markdown/plain body extraction
  • jira me issues for common agent use

Config Layer

Config files:

  • user config: platform-specific config dir, using dirs
  • local override: .jira.toml or .jira/config.toml, discovered upward from cwd
  • env overrides: JIRA_PROFILE, JIRA_SITE, JIRA_OUTPUT, JIRA_CONFIG, JIRA_TOKEN, JIRA_EMAIL

Profile model:

pub struct Profile {
    pub name: String,
    pub site: String,
    pub cloud_id: Option<String>,
    pub auth_method: AuthMethod,
    pub email: Option<String>,
    pub default_project: Option<String>,
    pub default_board: Option<u64>,
    pub default_fields: Option<Vec<String>>,
    pub scopes: Vec<String>,
}

Selection precedence:

  1. command flags
  2. environment
  3. local repo config
  4. user config active profile
  5. first configured profile

Auth Layer

Implement auth in this order:

  1. Environment token override, never persisted.
  2. Scoped API token with email, suitable for CI and initial agent workflows.
  3. Keyring-backed token storage per profile.
  4. Encrypted file fallback, if keyring is unavailable.
  5. OAuth 3LO after a spike confirms PKCE/client-secret constraints.
  6. Legacy unscoped token/basic auth with deprecation warnings.

Token storage must never place bearer tokens or API tokens in plain TOML. Config may reference token source metadata only.

OAuth profile data must include cloud_id, resolved through accessible-resources, and the API client must use the Atlassian gateway base URL for OAuth calls.

API Client

Centralize HTTP behavior in api::client::JiraClient:

  • reqwest::Client with rustls-tls, timeouts, gzip, multipart
  • auth injection by AuthContext
  • API base construction by auth mode
  • request redaction before logging
  • --debug-curl rendering with secrets redacted
  • Retry-After parsing as seconds or HTTP date
  • 429 and 5xx retry with jitter
  • Jira error body parsing into typed errors
  • response metadata capture for rate-limit headers

Endpoint modules should expose typed methods and models for known fields, but keep a serde_json::Value escape hatch for custom fields.

Search must use GET/POST /rest/api/3/search/jql, not deprecated /rest/api/3/search. For CLI consistency, prefer POST internally and support nextPageToken, isLast, maxResults, fields, expand, and reconcileIssues.

Output Layer

Make machine-readable output stable from day one:

{
  "ok": true,
  "data": {},
  "meta": {
    "schema_version": "1",
    "profile": "work",
    "site": "example.atlassian.net",
    "request_id": "...",
    "rate_limit": {}
  }
}

Formats:

  • auto: table on TTY, JSON on non-TTY
  • json: pretty unless --compact
  • jsonl: one envelope or data object per line for streaming lists
  • table
  • csv
  • tsv
  • yaml
  • plain
  • template=<expr>

Errors in JSON mode:

{
  "ok": false,
  "error": {
    "code": "auth_scope_missing",
    "message": "...",
    "hint": "Add scope read:issue-details:jira"
  }
}

ADF Layer

Initial ADF scope:

  • strongly typed AdfDocument, AdfNode, AdfMark
  • parse/render paragraphs, headings, lists, links, code spans, code blocks, blockquotes, rules, tables, status, mentions
  • preserve unknown nodes in a loss-tolerant representation
  • adf::to_plain for jira issue body --plain
  • adf::to_markdown for display/editor flows
  • adf::from_markdown for create/edit/comment input

Testing must drive this module. Add fixtures before broad endpoint work.

JQL Layer

Phase 1:

  • macro expansion
  • quote-safe builder for internally generated queries
  • server-side validation endpoint/error mapping
  • unbounded query warnings

Phase 2:

  • field-aware lexer/parser
  • typo suggestions from field cache
  • miette spans

Cache Layer

Use SQLite once core issue commands are stable:

  • fields and custom field schema
  • projects/components/versions
  • users
  • transition graphs
  • board/sprint metadata

Use cache for dynamic completions and for custom field name resolution. Provide jira cache info and jira cache clear.

Phase Plan

Phase 0: Repository Bootstrap

Tasks:

  • Add Cargo.toml, Cargo.lock, build.rs, src/main.rs, src/lib.rs.
  • Add modules with empty boundaries and smoke tests.
  • Add MIT LICENSE, README.md, CHANGELOG.md, SECURITY.md.
  • Add lints: forbid unsafe, warn clippy all, release profile with strip/LTO/codegen-units.
  • Add jira --version, help text, and completions.

Acceptance:

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo test --all-targets --all-features
  • jira --help, jira --version, and completions work.

Phase 1: CI and Release Foundation

Tasks:

  • Add .github/workflows/ci.yml with format, clippy, test matrix, audit, release-smoke.
  • Add concurrency and least-privilege permissions.
  • Pin actions by full commit SHA with version comments.
  • Add Dependabot or Renovate for Cargo and GitHub Actions updates.
  • Add release workflow skeleton with semver tag validation and pre-release gate.

Acceptance:

  • CI passes on Ubuntu, macOS, and Windows.
  • Release smoke builds the binary, runs --version, runs --help, and verifies generated manpages.
  • No release job has write permissions unless it publishes.

Phase 2: Config, Errors, Output

Tasks:

  • Implement JiraCliError with PRD exit codes.
  • Implement JSON error output and text/miette diagnostics.
  • Implement OutputFormat, TTY detection, JSON envelope, JSONL, table, CSV, TSV, YAML, plain.
  • Implement --fields projection with dotted paths.
  • Implement config load/merge precedence and profile commands.
  • Implement no-input behavior and tests that prove no stdin read occurs unless explicitly requested.

Acceptance:

  • Non-TTY defaults to JSON and no color.
  • TTY defaults to table.
  • --no-input is honored globally.
  • Every error type maps to the expected exit code.

Phase 3: API Token Auth and Token Store

Tasks:

  • Implement auth setup-token, auth status, auth list, auth logout, auth migrate.
  • Store tokens by profile in keyring.
  • Add encrypted file fallback if keyring fails.
  • Support JIRA_TOKEN, JIRA_TOKEN_<PROFILE>, JIRA_EMAIL, and --token-file.
  • Reject plain token fields in config with a migration hint.

Acceptance:

  • Token setup/status/logout work with temp config dirs.
  • Env tokens override stored tokens and are not persisted.
  • File fallback is permission-restricted and encrypted.
  • Secret redaction is covered by tests.

Phase 4: API Client and Search Pagination

Tasks:

  • Implement JiraClient with request methods and typed error mapping.
  • Implement rate limiter and retry middleware.
  • Implement api::pagination::SearchPager over nextPageToken and isLast.
  • Add --debug-curl with redacted auth.
  • Add wiremock fixtures for 200, 400, 401, 403, 404, 429, 5xx, and multi-page search.

Acceptance:

  • No code path calls deprecated /rest/api/3/search.
  • Multi-page search follows all nextPageToken values until isLast.
  • 429 honors Retry-After.
  • Failed Jira responses become structured CLI errors.

Phase 5: MVP Issue Reads

Tasks:

  • Implement issue view KEY.
  • Implement issue list --jql, search, --all, --max, --page-size.
  • Implement issue body KEY and --description.
  • Implement field projection and stable issue normalization.
  • Implement macros: @me, @open, @mine, @updated-today.

Acceptance:

  • Agents can fetch ticket context with one JSON command.
  • --all -o jsonl streams without loading all issues into memory.
  • issue body returns Markdown/plain without table chrome.
  • Snapshot tests cover table, JSON, JSONL, CSV, TSV, YAML, and plain output.

Phase 6: ADF Markdown Core

Tasks:

  • Add ADF data model.
  • Implement Markdown to ADF for common blocks and marks.
  • Implement ADF to Markdown/plain for descriptions and comments.
  • Add corpus fixtures from real Jira ADF samples.
  • Add editor temp-file flow with frontmatter.

Acceptance:

  • 100 fixture round-trips are snapshotted.
  • Unknown nodes are preserved or surfaced without data loss.
  • Editor flow aborts safely on parse errors and leaves recovery files.

Phase 7: Issue Mutations and Comments

Tasks:

  • Implement issue create, edit, delete.
  • Implement comment add/list/view/update/delete.
  • Implement comment visibility flags.
  • Implement transition listing and issue transition.
  • Implement assignment and issue links.

Acceptance:

  • All mutation commands support --dry-run.
  • Every command has JSON output and structured partial error details.
  • Wiremock tests cover validation errors and permission failures.

Phase 8: Worklogs, Attachments, Projects, Fields

Tasks:

  • Implement worklog CRUD.
  • Implement attachment upload/download/list/delete, including X-Atlassian-Token: no-check.
  • Implement project, version, component, user, group, and field reads.
  • Add custom-field schema helpers.

Acceptance:

  • Multipart attachment upload is tested.
  • Field cache can map human names to customfield_* IDs.
  • Project defaults are used by issue create.

Phase 9: Bulk Operations

Tasks:

  • Implement bulk transition/edit/assign/comment/link/delete.
  • Add concurrency limits and JSONL progress events.
  • Add dry-run affected-set preview.
  • Add partial failure summaries.

Acceptance:

  • Bulk commands continue on per-issue failures.
  • Exit code reflects max severity.
  • Non-TTY progress is machine-readable JSONL.

Phase 10: Agile API and Cache

Tasks:

  • Implement board, sprint, and epic commands.
  • Implement @current-sprint resolution through board/profile context.
  • Add SQLite cache for fields, projects, users, transitions, boards, sprints.
  • Add dynamic completions backed by cache.

Acceptance:

  • Sprint resolution is deterministic; if board is ambiguous, it errors with candidates.
  • Cache invalidation and clear/info commands are tested.

Phase 11: OAuth 3LO

Tasks:

  • Complete PKCE/client-secret spike.
  • Implement OAuth login, refresh, logout, status, and site selection.
  • Resolve and store cloud_id from accessible resources.
  • Use Atlassian gateway URLs for OAuth profiles.
  • Add auth doctor for scope/site mismatch.

Acceptance:

  • OAuth flow is wiremock-tested.
  • Refresh token rotation is handled.
  • Profile switching between token-auth and OAuth-auth sites works.

Phase 12: MCP Server

Tasks:

  • Implement jira mcp serve --stdio.
  • Expose curated tools: search, get issue, create issue, transition, comment, assign, worklog, link, current sprint.
  • Generate JSON schemas from shared request types.
  • Add MCP fixtures and protocol tests.

Acceptance:

  • MCP tools return the same normalized issue/comment objects as CLI JSON.
  • Failures use machine-readable error codes.

Phase 13: Distribution and Docs

Tasks:

  • Add cargo-dist metadata and release workflow.
  • Publish GitHub Releases with checksums.
  • Publish Homebrew formula to osodevops/homebrew-tap.
  • Publish to crates.io if package naming is available.
  • Add container image for CI usage.
  • Add docs: auth, ADF, recipes, JQL cookbook, agent integration, migration guide.

Acceptance:

  • Release artifacts exist for macOS arm64/x86_64, Linux gnu/musl where feasible, Windows x86_64.
  • brew install osodevops/tap/jira-cli works after release.
  • Docs include copy-pasteable Codex/Claude/Cursor integration examples.

GitHub Actions Plan

Use current local Keito-style security and current GitHub guidance:

  • permissions: contents: read for CI.
  • permissions: contents: write only in release jobs that create releases or tags.
  • permissions: packages: write only for GHCR publishing.
  • concurrency.group: ${{ github.workflow }}-${{ github.ref }} and cancel-in-progress: true for CI.
  • cancel-in-progress: false for release.
  • Pin actions by SHA with version comments.
  • Keep third-party action count low.
  • Never use pull_request_target.
  • Do not expose secrets to PR workflows.
  • Use unique artifact names per matrix target.

CI jobs:

  1. fmt: cargo fmt --all -- --check
  2. clippy: cargo clippy --all-targets --all-features -- -D warnings
  3. test: matrix ubuntu-latest, macos-latest, windows-latest
  4. release-smoke: cargo build --release, jira --version, jira --help, generated manpage checks
  5. audit: cargo audit
  6. ci-complete: verifies required jobs succeeded

Release jobs:

  1. pre-release-gate: semver tag validation, fmt, clippy, tests, audit, smoke.
  2. plan: cargo-dist plan.
  3. build-assets: target matrix, checksums, unique artifact names.
  4. create-release: create/update GitHub release.
  5. publish-crates: optional, after dry-run.
  6. publish-homebrew: update tap.
  7. publish-container: optional GHCR image.
  8. release-complete: verifies required release jobs.

Testing Strategy

Unit tests:

  • config precedence
  • output projection
  • error code mapping
  • JQL macro expansion
  • ADF node conversion
  • token redaction
  • retry delay parsing

Wiremock integration tests:

  • auth token setup/status
  • OAuth code exchange and refresh
  • accessible resources
  • issue search pagination
  • issue view/create/edit/delete
  • comments/worklogs/attachments
  • 401/403/404/429/5xx mapping

CLI tests:

  • help/version/completions
  • no-args help
  • non-TTY output defaults
  • --no-input no-hang behavior
  • JSON and JSONL schemas
  • dry-run output

Snapshot tests:

  • table formatting
  • normalized issue JSON
  • error JSON
  • ADF Markdown output

Property/fuzz tests:

  • Markdown to ADF to Markdown stability
  • JQL lexer/parser once implemented
  • custom field value builders

Optional live tests:

  • behind JIRA_LIVE_TESTS=1
  • use a dedicated test Jira site/project
  • never run in PR CI

Risks and Mitigations

ADF round-trip complexity is the highest product risk. Mitigate with a real corpus, explicit supported-node matrix, and raw unknown-node preservation.

OAuth 3LO details may not match the PRD's PKCE assumption. Mitigate with an early spike and by shipping API-token auth first for CI/agent workflows.

Jira scopes drift over time. Mitigate with an endpoint scope catalogue and tests that compare known command requirements against the current pinned endpoint metadata.

Custom fields are unpredictable. Mitigate by caching field schema, supporting raw JSON escape hatches, and adding focused builders only for common types.

Release target complexity can slow v1. Mitigate by using cargo-dist for artifact planning and keeping manual Homebrew/Scoop code small and tested.

Agent safety is easy to regress. Mitigate with CI tests that run commands with closed stdin/non-TTY stdout and fail on prompts, colors, or spinners.

Suggested Timeline

Week 1:

  • Phase 0 and Phase 1
  • basic config/output/error foundations

Week 2:

  • API-token auth
  • API client
  • search pagination fixtures

Week 3:

  • issue view, issue list, issue body
  • JSON/JSONL/table/csv/tsv/yaml/plain output

Week 4:

  • ADF v1
  • comments
  • issue create/edit

Week 5:

  • transitions, assignment, links, worklogs, attachments
  • project/field metadata

Week 6:

  • bulk operations
  • cache
  • Agile API

Week 7:

  • OAuth 3LO
  • auth doctor
  • release automation

Week 8:

  • MCP
  • docs
  • hardening, live test pass, beta release

If time tightens, cut MCP, bulk, and Agile from v1.0 and keep the first public release focused on reliable issue/search/comment workflows.

Immediate Next Steps

  1. Bootstrap the Rust repo and CI.
  2. Implement config/output/error/no-input behavior before any Jira API calls.
  3. Implement API-token auth and token storage.
  4. Implement Jira client and /search/jql pagination with wiremock fixtures.
  5. Ship the first vertical slice: jira issue view, jira issue list, jira issue body, and jira comment add/list with stable JSON.

Sources

  • Atlassian Jira Cloud REST API v3 issue search: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-search/
  • Atlassian Jira Cloud REST API v3 issues and ADF fields: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/
  • Atlassian Jira Cloud REST API v3 intro and ADF support: https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/
  • Atlassian OAuth 2.0 3LO apps: https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/
  • GitHub Actions Rust guide: https://docs.github.com/en/actions/tutorials/build-and-test-code/rust
  • GitHub Actions secure use reference: https://docs.github.com/en/actions/reference/security/secure-use
  • GitHub Actions workflow syntax: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
  • GitHub workflow artifacts docs: https://docs.github.com/en/actions/tutorials/store-and-share-data