pm-jira
Jira issue sync for pm-cli
Installieren
Mit installiertem pm
pm install npm:pm-jira --projectMit npm, ohne pm zu installieren
npx -y @unbrained/pm-cli install npm:pm-jira --projectMit Bun, ohne pm zu installieren
bunx @unbrained/pm-cli install npm:pm-jira --projectREADME
A pm-cli extension that syncs Jira issues into pm items using the Jira REST API v3.
Cloud imports use the enhanced JQL search API
at /rest/api/3/search/jql. All import entrypoints follow opaque
nextPageToken cursors until isLast or the requested --max-results limit.
Progress reports fetched counts and the configured limit because this API has
no exact total. Dry runs show the same initial request without making a network
call. The exported buildSearchRequest helper now takes a cursor string or
undefined as its third argument, replacing the removed numeric offset.
Malformed pages, repeated issue keys, missing or cycling continuation tokens, oversized responses, and searches exceeding 1,000 pages fail before any tracker write. Empty intermediate pages may advance the cursor; an empty final result succeeds without opening an atomic transaction. Narrow the JQL query if the page ceiling is reached. Jira search is eventually consistent: cursor validation does not guarantee a point-in-time snapshot. This integration targets Jira Cloud; Jira Data Center's separate search contract is not implemented.
Features
- Pull issues from any Jira project into pm items via
pm jira importorpm jira sync - Export pm items back out as Jira create payloads via
pm jira export(preview, or--pushto create issues) - Convenience JQL filters —
--project,--status,--assignee,--issue-type,--label,--updated-sincecompose into a single JQL query (or pass full--jqlto override) - Rich field mapping — Jira status (by name, with a
statusCategoryfallback for custom workflows), priority, issue type → pm type, labels/fix-versions/components/sprints → tags, assignee → tag; configurable with--status-mapand a general--map jiraField=pmField --dry-runeverywhere — both import and export print the exact request / mutations they would make and perform no network call (the offline-testable, creds-free path)pm jira validate— report Jira credential/base-URL readiness without leaking any secret (hostname-only preview);--jsonaware- Fail-fast preflight credential gate — a network-mutating
pm jira sync/pm jira import(andpm jira export --push) aborts immediately with a clear, actionable message before any pm-store read or Jira call ifJIRA_BASE_URL/JIRA_EMAIL/JIRA_API_TOKENare missing.--dry-runandpm jira validateare exempt (offline). See Preflight gate. - Optional, opt-in export-on-write hook (
PM_JIRA_PUSH_ON_WRITE) — best-effort, never breaks your pm command, no-op without credentials - Jira provenance (key + browse URL) persisted in the item description and declared as
jira_key/jira_urlschema fields; on export, items that already carry a Jira key become anupdate(PUT) instead of a duplicate create - Works as a
pm jira sync/pm jira importcommand, apm jira exportexporter, and a config-drivenjira-syncimporter
Which features need live Jira credentials? Everything except the actual network round-trip is usable and testable offline. Building JQL, previewing requests/mutations with
--dry-run, field mapping in both directions, andpm jira validateall work with no creds and no network. You only needJIRA_BASE_URL/JIRA_EMAIL/JIRA_API_TOKENfor: a real import fetch,pm jira export --push(creating/updating issues), and live reachability.
Installation
Install with pm from GitHub:
pm install github.com/unbraind/pm-jira
Or build locally from source:
npm ci
npm run build
Jira API Setup
You need a Jira API token to authenticate. To create one:
- Go to https://id.atlassian.com/manage-profile/security/api-tokens
- Click Create API token
- Give it a label (e.g.
pm-cli-sync) and copy the token
Required Environment Variables
| Variable | Description | Example |
|---|---|---|
JIRA_BASE_URL |
Your Jira instance base URL | https://company.atlassian.net |
JIRA_EMAIL |
Email address for your Jira account | [email protected] |
JIRA_API_TOKEN |
API token generated above | <jira-api-token> |
Set them in your shell or .env:
export JIRA_BASE_URL=https://company.atlassian.net
export [email protected]
export JIRA_API_TOKEN=<jira-api-token>
Usage
Command: pm jira sync
# Sync all open issues from a project (default JQL: statusCategory != Done)
pm jira sync --project PROJ
# Sync up to 200 issues
pm jira sync --project PROJ --max-results 200
# Use custom JQL
pm jira sync --jql "project = PROJ AND assignee = currentUser() ORDER BY updated DESC"
# Preview without writing (dry run)
pm jira sync --project PROJ --dry-run
# Only sync issues that map to the "wip" pm status
pm jira sync --project PROJ --status wip
# Combine flags
pm jira sync --project PROJ --max-results 100 --status todo --dry-run
Command / Importer: pm jira import
pm jira import is the native importer pipeline equivalent of pm jira sync — it
pulls issues via JQL and creates pm items. Both share the same flags and logic.
# Pull all open issues from a project
pm jira import --project PROJ
# Use a custom Jira host (instead of JIRA_BASE_URL) + custom JQL
pm jira import --host https://company.atlassian.net --jql "project = PROJ AND assignee = currentUser()"
# Override status mapping
pm jira import --project PROJ --status-map "QA=blocked,Done=closed"
# Atomic import (pm-cli >= 2026.7.20): one crash-recoverable transaction.
# Ordinary failures request delete compensation; rollback is not guaranteed.
# Interruptions can retain creates; retry the same input to resume.
pm jira import --project PROJ --atomic
Pull flags (pm jira sync / pm jira import)
| Flag | Type | Default | Description |
|---|---|---|---|
--project |
string | — | Jira project key (e.g. PROJ). Composed into JQL. Alias: --project-key. |
--jql |
string | — | Custom JQL query. Used verbatim; overrides all convenience filters below. |
--status |
string | — | Filter by pm status (open/in_progress/closed/blocked, mapped to a statusCategory clause) or a raw Jira status name. Also filters imported items client-side. |
--assignee |
string | — | Filter by assignee (accountId, name, or a function like currentUser()). |
--issue-type |
string | — | Filter by Jira issue type (e.g. Bug). |
--label |
string | — | Filter by Jira label. |
--updated-since |
string | — | Filter by updated date, relative (-7d) or absolute (2026-01-01). |
--status-map |
string | — | Override status mapping, e.g. "In Review=in_progress,QA=blocked". |
--map |
string | — | Override field mapping, e.g. "issuetype=Task,assignee=skip". Alias: --field-map. |
--host |
string | $JIRA_BASE_URL |
Jira base URL override. |
--max-results |
number | 500 |
Maximum number of issues to pull. |
--dry-run |
boolean | false |
Print the JQL + exact GET request that would run; no network call. |
--atomic |
boolean | false |
Import all creates in ONE crash-recoverable, workspace-writer-locked transaction via the official commitItemMutations SDK helper (pm-cli >= 2026.7.20). Ordinary failures request delete compensation; an exception alone does not confirm rollback. Interrupted runs retain applied work and resume with the same input. A --dry-run + --atomic invocation previews like a normal dry-run and commits no transaction. |
When no --jql is given, the convenience filters are AND-combined; if you don't
filter on status, a statusCategory != Done clause is appended so an unscoped
pull stays focused on active work (the historical default).
--map field overrides
--map accepts a comma list of jiraField=pmTarget pairs. Recognized Jira-side
keys: status, statuscategory, priority, issuetype (alias type),
labels, fixversions, components, sprint/sprints/customfield_10020,
assignee, duedate. Imported tags include component:<name> from Jira
components and sprint:<name> from Jira's common Sprint custom field
(customfield_10020) when present; set noisy context fields to skip or
ignore to suppress them. Examples:
# Pin every imported item's type, and skip the assignee tag
pm jira import --project PROJ --map "issuetype=Task,assignee=skip"
# Keep labels but suppress sprint/component context tags
pm jira import --project PROJ --map "components=ignore,sprint=ignore"
# Force a pm status regardless of the Jira workflow state
pm jira import --project PROJ --map "status=in_progress"
Progress + transparency notes (STDERR)
For large paginated imports the importer prints Fetched N (limit M)... progress to
STDERR after each page, so a multi-page pull surfaces feedback instead of
looking hung. The enhanced JQL cursor search returns no total, so N counts the
issues fetched so far and M is the configured --max-results ceiling (default
500), never a denominator. This is additive and never touches the stdout /
--json output.
If any fetched issue carries attachments or comments, the importer logs a one-line note to STDERR that those are not imported (pm-jira imports title / body / status / priority / labels / due-date only). This prevents a silent expectation that attachment or comment data came across.
Exporter: pm jira export
Local selection uses the public in-process SDK listAllComplete with bodies,
all lifecycle states, strict source reads, no extensions, and unbounded output.
There is no 10,000-item ceiling or CLI JSON buffer. Both export previews and
pushes certify the whole corpus before constructing payloads. Import and sync
also certify it before local writes and skip issues whose browse URL already
exists, including closed and canceled items. Equal keys on different Jira hosts
remain distinct. Import matching preserves existing items; it does not update
or reopen them. Re-import reports zero newly imported items when all issues match.
An absent/malformed items array, incomplete source scan, pagination, counts that
disagree, compact projection, missing or contradictory receipts, output
compaction/omission, duplicate or missing IDs, or malformed payload fields causes
a CommandError before writes. The error includes a strict, all-status,
unbounded inspection command and a tracker/SDK recovery hint. A certified empty
tracker succeeds; a missing or uninitialized tracker fails. See
complete-read verification for the refusal matrix
and regression evidence.
Render pm items as Jira create payloads. Prints JSON by default; with --push
(and credentials + --project) it POSTs each payload to Jira's create-issue API.
# Preview the Jira create payloads for all pm items (no network, no creds needed)
pm jira export --project PROJ
# Print the exact mutations that WOULD run (create vs update), no network/creds
pm jira export --project PROJ --dry-run
# Derive Jira issuetype + priority from each pm item's type/priority
pm jira export --project PROJ --rich --dry-run
# Actually create the issues in Jira (requires creds + --project)
pm jira export --push --project PROJ
# Also PUT changed fields back to issues that already carry a Jira key
pm jira export --push --project PROJ --update-existing
# Preview exactly what --update-existing would do (no network)
pm jira export --project PROJ --update-existing --dry-run
| Flag | Type | Default | Description |
|---|---|---|---|
--project |
string | — | Target Jira project key for created issues (required for --push). Alias: --project-key. |
--map |
string | — | Override field mapping, e.g. "issuetype=Story". Alias: --field-map. |
--rich |
boolean | false |
Derive Jira issuetype + priority from the pm item type/priority. |
--update-existing |
boolean | false |
PUT changed fields to issues that already carry a Jira key. Without it, those items are skipped (no duplicate, no mutation). |
--dry-run |
boolean | false |
Print the Jira POST/PUT mutations that would run; no network call. |
--host |
string | $JIRA_BASE_URL |
Jira base URL override. |
--push |
boolean | false |
POST payloads to Jira (requires credentials + --project). |
Items whose description carries a Jira <KEY>: <url> provenance marker (added on
import) are matched back to their upstream issue and become an update (PUT):
- By default (
--pushalone) those items are skipped so a re-export never duplicates or unexpectedly mutates an existing Jira issue — only items without a key are created.--dry-runshows them asSKIP. - With
--update-existingeach matched item is PUT to Jira's edit-issue endpoint (/rest/api/3/issue/<KEY>) with its changed fields (the immutableprojectfield is stripped, as Jira's edit API rejects it).--dry-runshows them asUPDATE PUT ...so you can review the exact mutations offline first.
Command: pm jira validate
Report whether pm-jira has the credentials/base URL it needs — without making a network call and without leaking any secret value (it prints a hostname-only preview, never the token or email):
pm jira validate # human-readable readiness summary
pm jira validate --json # structured object: { ready, baseUrlPresent, ... }
pm jira validate --host https://company.atlassian.net
Preflight gate
pm-jira registers a preflight credential gate (pm-cli preflight capability /
registerPreflight). Before a network-mutating command runs, it checks that the
required credentials are present and, if not, aborts immediately with a clear,
actionable error and a non-zero exit code — before any pm-store read or Jira REST
call. This turns a deep, late failure into a fast, obvious one.
It fires only for these invocations:
| Invocation | Gated? |
|---|---|
pm jira sync (no --dry-run) |
yes — pulls over the network |
pm jira import (no --dry-run) |
yes — pulls over the network |
pm jira export --push (no --dry-run) |
yes — POSTs/PUTs to Jira |
pm jira sync|import --dry-run |
no — offline preview, no creds needed |
pm jira export (no --push) |
no — prints payloads offline |
pm jira validate |
no — diagnostics, must run without creds |
| any other / non-pm-jira command | no |
Example (no credentials set):
$ pm jira sync --project PROJ
pm-jira preflight: cannot run "pm jira sync" — missing Jira credentials:
JIRA_BASE_URL (or --host), JIRA_EMAIL, JIRA_API_TOKEN. Set JIRA_BASE_URL
(or pass --host), JIRA_EMAIL, and JIRA_API_TOKEN before a mutating command.
Create a token at https://id.atlassian.com/manage-profile/security/api-tokens .
Run "pm jira validate" to diagnose, or add --dry-run to preview offline.
# exit code 2
The message names only the missing variable names — never the token or email value. When credentials are present the gate is a silent pass-through.
Export-on-write hook (opt-in)
Setting PM_JIRA_PUSH_ON_WRITE=1 activates a best-effort onWrite hook. It is a
strict no-op unless both the env flag is truthy and Jira credentials are
present, and it can never fail your pm command (the pm hook runtime swallows
any error). It intentionally does not auto-POST on every write; use the
explicit, reviewable pm jira export --push to mirror items upstream.
Importer: jira-sync (config-driven)
Use the jira-sync importer in your pm-cli config for automated syncing:
{
"importers": {
"jira-sync": {
"project": "PROJ",
"maxResults": 300
}
}
}
Credentials are read from environment variables or from the importer config:
{
"importers": {
"jira-sync": {
"JIRA_BASE_URL": "https://company.atlassian.net",
"JIRA_EMAIL": "[email protected]",
"JIRA_API_TOKEN": "<jira-api-token>",
"project": "PROJ"
}
}
}
Status Mapping
The default mapping (override per-status with --status-map):
| Jira Status | pm Status |
|---|---|
| To Do, Open, Backlog, (any other) | open |
| In Progress, In Review, In Development, Code Review | in_progress |
| Done, Resolved, Closed, Complete, Completed | closed |
| Blocked | blocked |
When the Jira status name is unrecognized (custom workflows), pm-jira falls
back to the issue's statusCategory bucket: new → open, indeterminate →
in_progress, done → closed.
Issue type mapping
| Jira Issue Type | pm Type |
|---|---|
| Bug, Defect | Bug |
| Story, Epic | Feature |
| Task, Sub-task | Task |
| (any other) | Issue |
Override with --map issuetype=<pmType> (import) or --map issuetype=<jiraType>
(export, with --rich).
Priority Mapping
| Jira Priority | pm Priority |
|---|---|
| Highest, Critical | 1 (highest) |
| High | 2 |
| Medium, (any other) | 3 |
| Low, Lowest | 4 (lowest) |
Item Structure
Each imported item includes:
- title:
[PROJ-123] Issue summary - body: Issue description (converted from Atlassian Document Format to plain text)
- description: A provenance marker
Jira PROJ-123: https://…/browse/PROJ-123so the Jira key + URL survive round-trips and powerpm jira export. The extension also declaresjira_keyandjira_urlas optional item schema fields (capabilityschema). - status: Mapped from Jira status (see table above)
- priority: Mapped from Jira priority (see table above)
- tags: Jira labels + fix version names
- deadline: Jira due date (
YYYY-MM-DD), if set
Note: pm's
createhas no generic custom-field setter for a standalone extension, so provenance is stored in the description marker rather than as structured metadata.
JQL Examples
# All open issues in a project, by priority
project = PROJ AND statusCategory != Done ORDER BY priority ASC
# Only issues assigned to you
project = PROJ AND assignee = currentUser()
# Issues updated in the last 7 days
project = PROJ AND updated >= -7d ORDER BY updated DESC
# Issues in a specific sprint
project = PROJ AND sprint in openSprints()
# Issues with a specific label
project = PROJ AND labels = "backend"
# Issues by type
project = PROJ AND issuetype = Bug AND statusCategory != Done
Development
# Install dev dependencies
npm install
# Build TypeScript
npm run build
# Watch mode
npm run dev
Multi-agent merge safety
This repo tracks its own project management in .agents/pm/ and ships a committed
.gitattributes that maps those tracker artifacts to pm-cli's field-aware Git merge
drivers, so concurrent-branch tracker edits merge cleanly instead of hard-conflicting.
The driver definitions live in per-clone Git config, so each clone must wire them
once. npm install / npm ci does this automatically via the prepare script, scripts/prepare-merge-driver.ts: the launcher template pm-ops ships, copied unchanged, which a test compares byte for byte with the pinned template. It runs pm-ops's installer, which calls pm merge install when the pm CLI is on PATH and skips with a notice when it is not. A production install of a clone (npm ci --omit=dev) has no pm-ops, so the launcher skips with one notice, while a stale or broken pm-ops fails the install. Registry installs of this package never run prepare. Being Node-based, it behaves identically on POSIX shells and Windows cmd.exe; to (re)run it manually:
npm run merge:install # or: pm merge install
After merging a branch that touched .agents/pm/, reconcile any residual history-hash drift with
pm merge reconcile (pm-cli ≥ 2026.7.22): preview with pm merge reconcile --dry-run, apply with
pm merge reconcile --message "post-merge reconcile", then confirm with pm validate, which scans the
whole tracker and flags remaining history drift across every affected item (pm merge reconcile
itself lists each affected stream in its output; pm history --verify <id> spot-checks one item). The field-aware driver already unions every author's
content, so reconcile only re-greens the hash chain (no data loss) — see the authoritative
pm-cli merge-safety guide. The
older blunt pm history-repair --all remains available as a lower-level primitive.
Requirements
- Node.js
>=22.18.0(uses nativehttpsmodule andBuffer) - pm-cli
>=2026.10.4 - TypeScript 6.x (dev dependency)
License
MIT
Release Automation
This package is release-ready for GitHub, npm, and Bun-compatible installs. CI runs type checking, build, production dependency audit, package packing, Bun install verification, and pm-changelog validation. The daily release workflow publishes only when commits exist after the latest release tag and uses pm-changelog to generate CHANGELOG.md and GitHub release notes.
Plan a lifecycle transition
pm jira plan-transition discovers the issue's current status and the transitions
permitted for the authenticated Jira user, including required screen fields:
pm jira plan-transition --issue DEMO-123 --to closed --json
pm jira plan-transition --issue DEMO-123 --to closed --transition 31 \
--fields '{"resolution":{"id":"1"}}'
Set JIRA_BASE_URL, JIRA_EMAIL, and JIRA_API_TOKEN as for sync. --host
overrides the base URL. Targets accept the existing pm status aliases; use
--status-map 'QA=blocked,Shipped=closed' for custom workflow meanings. Explicit
mappings win, then Blocked, then Jira's status category. Existing import mappings
are unchanged. The host renders compact TOON by default or JSON with --json.
The result is ready, noop, or refused, always with writes: 0. Refusals
include a stable code, remediation, compact permitted choices and the host-owned
exit_code: 2 contract; the CLI exits 2.
Required fields need explicit nonempty values, even if Jira advertises a default.
Supplied fields must support set on the selected screen. For schema.type: array
fields, supply a JSON array: each member must match an advertised allowed value
exactly. An optional empty array clears the selection; required arrays must be
nonempty. Other fields match their entire supplied value against an allowed value.
Values are never echoed. This conservative check can refuse equivalent values
with a different JSON representation. It does not
replace Jira's execution-time schema checks, validators or permission checks.
Only a direct currently permitted transition can be ready. Multiple matching
transitions require --transition. An indirect route returns
no_permitted_transition with available next steps: have an authorized actor
perform an approved intermediate transition separately, then rediscover. The
API cannot certify future-state permissions. Rediscover immediately before any
external execution; the plan is advisory, has no execution token, and performs
neither Jira nor local tracker mutations. Authentication, permission and network
failures return a redacted discovery_failed refusal.
The typed SDK exports JiraTransitionIntent, JiraTransitionPlan,
discoverJiraTransitionPlan(intent, options?), and the offline
planJiraTransition(intent, issueResponse, transitionsResponse) planner. See
the SDK example for an intermediate-state refusal.
Without git
ADF evidence capture/replay, create-field completion previews, JQL selection comparison, transition planning, credential diagnostics and Jira
import/export previews work in plain directories and non-git trackers. Import/sync and explicit export push
also use the tracker and Jira APIs without requiring git. Ordinary imports create
items through the pm SDK in process, so they do not need a separate pm executable
on PATH. Atomic imports continue to use commitItemMutations. Changelog generation
from release tags requires a git repository. Transition planning invokes no git
subprocess and never writes a tracker. Selection comparison also invokes no git
subprocess; it reads only the two explicit JSON files and never reads or writes
local items or calls Jira.
Explain JQL selection changes
Compare two explicit snapshots of a synchronized selection without removing omitted local work:
pm jira explain-selection --before before.json --after after.json --limit 32 --json
pm jira explain-selection --before before.json --after after.json --limit 32 --offset 32
The typed SDK exports explainJqlSelectionChanges(before, after, options?),
JqlSelectionSnapshot, JqlVisibilityEvidence, JqlSelectionOptions,
JqlSelectionResult, and the related page, change, explanation and refusal types.
See the complete JSON/CLI/SDK example for the
snapshot contract and evidence requirements, and the
public tracker validation for measured data.
The default output is compact TOON; --json uses the same typed result.
kind: explained includes exact aggregate counts, a stable key-sorted page of
entries/exits, queryChanged, and an omission/next-offset receipt. Only change
keys and classifications are returned; queries, principals, tokens, issue bodies
and summaries are not echoed. Defaults are 32 changes per page, maximum 256;
offset is a nonnegative safe integer. Host output budgets also apply. If the
host reports additional omissions, retry the same offset with
--output-budget unbounded --output-limit unbounded before advancing.
Exits are query_excluded only with explicit independently established
nonmembership evidence, permission_lost only with explicit permission-loss
evidence, and otherwise unresolved. Visibility alone or a 404 is insufficient.
Entries mean selected now and absent before; they do not imply a newly created
Jira issue. All rows carry localAction: preserve. Every result, including a
refusal, has writes: 0 and deletionProposals: 0.
Both snapshots must have the same canonical site origin, principal and scope, and must be chronological. A changed principal refuses rather than guessing permission loss. The entire initial-to-terminal cursor chain must be present; empty intermediate pages may advance tokens. Missing, disconnected, repeated, cycling or premature-terminal pages and duplicate keys fail closed. Incomplete page chains produce no change rows or deletion proposals. A capped import is not a complete selection snapshot. No local tracker or Jira mutation is offered.
Limits are 8 MiB per CLI file, 1,000 pages, 100 keys per page, 10,000 unique keys and 10,000 visibility observations per snapshot. Identifiers are bounded; JQL and opaque tokens have an 8,192-character limit. SDK callers supply parsed objects and receive the same structural limits. Narrow the entire synchronized scope when a limit is reached; never truncate a selection.
Refusals have kind: refused, an empty changes array, stable code, actionable
remediation, and exit_code: 2 (the host exits 2):
| Code | Remedy |
|---|---|
invalid_snapshot |
Supply valid v1 metadata, unique keys and valid observations. |
incomplete_chain |
Recapture every page through the terminal response. |
snapshot_limit |
Narrow the complete scope within file/page/key/evidence limits. |
boundary_mismatch |
Compare the same site, principal and scope. |
time_order |
Put the earlier snapshot first. |
conflicting_evidence |
Recapture consistent visibility observations. |
invalid_options |
Supply both files and valid limit/offset integers. |
input_read / input_json |
Supply readable regular files containing valid JSON. |
These are explanations of supplied membership and evidence. Jira's eventual consistency and caller assertions remain explicit limits; a complete chain does not prove atomic capture, live permissions, or why a query stopped matching. Core SDK complete reads/snapshots retain ownership of tracker capture and restore; pm-graph compares relationships rather than Jira query membership.
SDK adoption verification
Expected failures use the SDK createPmCliExpectedError contract. Error messages
and semantic exit codes are retained; the error name is now the SDK's
PmCliError. SDK callers should use isPmCliExpectedError rather than the
removed package-specific CommandError class.
Run node scripts/sdk-adoption-differential.ts after building to compare the
current build with an origin/main build against copies of the public tracker.
Additional public package checkouts may be passed as arguments. Override the
baseline with PM_JIRA_BASELINE_REF. The harness leaves the source checkouts and
snapshots unchanged, exercises writes only in disposable non-git copies, and
compares create fields, counts, repeat imports, diagnostics, command previews,
and expected failures. Generated item IDs and timestamps are excluded from
field comparison. The expected error name is an intentional SDK difference.
Certified complete local reads remain mandatory before import matching and
export planning. Neither SDK replacement substitutes the cached event index for
verified history. The regression suite also primes the event cache, corrupts
authoritative SDK-created history, and checks that verifyHistoryEntries still
detects the corruption. No Jira create, link or comment call is introduced by
these replacements; imports only read Jira and create local items in one commit
per item.
Create-field completion previews
Preview the required bindings and missing answers for an explicitly selected Jira project/type, using revisioned create metadata:
pm jira preview-create --contract docs/examples/create-contract.json --json
# Add the required Team answer, then protect the complete create batch:
pm jira export --project DEMO --create-contract create.json --push --json
The SDK exports previewJiraCreate and typed JiraCreate* contracts. Custom
required fields and exact allowed values are checked before any guarded POST.
Diagnostics fit a declared JSON byte budget and expose page.nextOffset.
See the contract, limits and export guarantees and
the example fixture. The preview is read-only
and validates supplied metadata; it does not establish live Jira permissions.
All Jira commands reject supplied blank option values with invalid_option
(exit 2) before I/O. Leave unused options omitted, and supply nonblank values for
contracts and other guards. The shared boundary checks the whole bag, including
secondary aliases and legacy importer credential options. See
the option contract and table-driven validation.
Payload completeness follows each Jira metadata required flag. Optional empty
values (including native labels: [] for untagged items) are omitted from guarded
POST bodies. Required empty values stop the complete batch. The CLI blank-option
rule applies to option values, while JSON payload fields follow their schemas;
see the refuse/allow corpora.
Create previews and guarded exports share one final-body builder: explicit
contract answers win over mapped item fields, which win over generated --rich
and default values. previewJiraExport(plan, contract) reports each exact POST
bodyDigest; runExportPush validates and sends that same JSON representation.
Optional empty fields and native mappings absent from the captured create screen
are omitted. Option references preserve schema-supported id/name/value
forms; Jira Cloud users use accountId. See the
agreement example and schema projection rules.
Project and issue type stay fixed outside field precedence. Every native and contract source must agree with the selected target before merging; matching contract overrides cannot conceal a plan for another project/type. Scope refusals remain typed in SDK, installed JSON/TOON and packed Node/Bun consumers.
Selected ADF block evidence
pm jira capture-adf --contract capture.json --json preserves selected description
blocks with original source coordinates, including table cells, code and lists.
Unselected siblings and media/card content are excluded; unsupported nodes are
counted. Preview first, then approve the observed source revision and digest.
Changed sources refuse capture. Output is a bounded portable packet; native
items and Jira remain untouched. The SDK exports captureAdfEvidence,
replayAdfEvidence and their typed contracts. See the contract and refusal guide
and the runnable example. Snapshot approval
requires a fresh caller-supplied source read; it does not attest live Jira freshness.
Programmatic callers can reuse a bound filesystem tracker via bindJiraPersistence.
See persistence scope and remaining backend roadmap
for its guarantees, recovery diagnostics and conformance limits.
Aus der README des Pakets auf GitHub. Auf GitHub ansehen