rai backlog
Manage backlog items via ProjectManagementAdapter. The adapter (Jira, filesystem, etc.) is selected automatically or via -a.
Setup¶
Machine Requirements¶
The Jira adapter requires Atlassian CLI (ACLI) installed and authenticated.
# Verify ACLI is installed
acli --version
# Authenticate (opens browser for OAuth)
acli jira auth login --site your-org.atlassian.net
For detailed setup, multi-instance configuration, and troubleshooting, see Configuring Integrations.
Project Configuration¶
.raise/backlog.yaml — Required. Defines Jira instances and project routing.
# .raise/backlog.yaml (minimal)
default_instance: myorg
instances:
myorg:
site: myorg.atlassian.net
email: you@myorg.com
projects: [PROJ]
projects:
PROJ:
instance: myorg
name: My Project
Adapter Selection¶
Resolution order:
-a <name>flag on the command — targets a single adapter directly.-a all— explicitly composes every configured adapter.- No flag — auto-detect. With exactly one adapter registered, that adapter
is used directly. With 2+ adapters registered (e.g. the always-on local
filesystem/sqliteadapters plus a configured remote likejira), they auto-compose into aCompositeBacklogAdapter: writes go to every local adapter and every configured remote, reads prefer the remote when available.
There is no manifest-level default adapter — auto-detect + auto-compose handles the common local+remote case without configuration.
Jira Notes¶
Search requires JQL¶
rai backlog search passes the query string directly to Jira's search API. Plain text does not work — you must use JQL.
# wrong — returns no results
rai backlog search "PROJ-302"
# correct — JQL
rai backlog search "issue = PROJ-302"
rai backlog search "project = PROJ AND status = 'In Progress'"
If your project key is a reserved JQL keyword, quote it: project = "MYPROJECT".
Status names for transition¶
Status names are converted by convention: in-progress → In Progress, done → Done. Use lowercase with hyphens:
| Status name | Jira state |
|---|---|
backlog |
Backlog |
selected |
Selected For Development |
in-progress |
In Progress |
done |
Done |
rai backlog create¶
Create a new backlog item.
| Argument | Description |
|---|---|
SUMMARY |
Issue title (required) |
| Flag | Short | Description |
|---|---|---|
--project |
-p |
Project key, e.g. PROJ (required) |
--type |
-t |
Issue type. Default: Task |
--labels |
-l |
Comma-separated labels |
--parent |
Parent issue key | |
--description |
-d |
Issue description (markdown) |
--field |
-F |
Custom field by ID (repeatable, e.g. -F customfield_13267=Value) |
--adapter |
-a |
Adapter name override |
--format |
-f |
Output format: human, agent. Default: human |
# Create a task
rai backlog create "Add CLI docs" -p PROJ
# Create with labels and parent
rai backlog create "Fix login bug" -p PROJ -t Bug -l "priority,frontend" --parent PROJ-100
rai backlog get¶
Retrieve details for a single backlog item.
| Argument | Description |
|---|---|
KEY |
Issue key, e.g. PROJ-123 (required) |
| Flag | Short | Description |
|---|---|---|
--adapter |
-a |
Adapter name override |
rai backlog get-comments¶
Retrieve comments for a backlog item.
| Argument | Description |
|---|---|
KEY |
Issue key (required) |
| Flag | Short | Description |
|---|---|---|
--limit |
-n |
Max comments. Default: 10 |
--offset |
Pagination offset. Default: 0 |
|
--all |
Retrieve all comments | |
--adapter |
-a |
Adapter name override |
rai backlog search¶
Search backlog items. Query format is adapter-specific (JQL for Jira).
| Argument | Description |
|---|---|
QUERY |
Search query (required) |
| Flag | Short | Description |
|---|---|---|
--limit |
-n |
Max results. Default: 50 |
--offset |
Start from result N. Default: 0 |
|
--all |
Return all results (ignores limit) | |
--adapter |
-a |
Adapter name override |
--format |
-f |
Output format: human, agent. Default: human |
# JQL search
rai backlog search "project = PROJ AND status = 'In Progress'"
# Limit results
rai backlog search "project = PROJ" -n 10
rai backlog close-drift¶
Report Done issues in the active release fixVersion whose evidence commit
never landed on the development branch (RAISE-14589). Read-only — it never
transitions, updates, or writes anything, and always exits 0.
Landing evidence is resolved from git commit messages, not from a branch named after the issue: branches are deleted after merge, so branch resolution would fail in the healthy case. Each candidate is classified:
| Verdict | Meaning |
|---|---|
landed |
evidence commit is an ancestor of the development ref (not listed unless --all) |
unlanded |
evidence commit exists but is not an ancestor — high-confidence drift |
no-evidence |
no commit anywhere cites the key — weaker signal (spike, docs-only close, work under a sibling key) |
| Flag | Short | Description |
|---|---|---|
--project |
-p |
Remote project key. Default: RAISE |
--fix-version |
Override the resolved fixVersion instead of deriving it | |
--fetch |
Fetch the development ref before classification (opt-in; a failure is a warning, not a hard stop) | |
--all |
Also list landed issues, not just drifted ones |
|
--adapter |
-a |
Adapter name override |
--format |
-f |
Output format: human, agent. Default: human |
# Report drift for the resolved active fixVersion
rai backlog close-drift
# Refresh the development ref first, then check a different project
rai backlog close-drift --fetch --project RAISE
# Machine-readable: key|verdict|sha|summary, one line per non-landed candidate.
# If the run couldn't fully verify (unresolved dev ref, or a broken git
# evidence search), a `#degraded: <reason>` line is printed first — a
# consumer that doesn't check for it before treating an empty/clean output
# as "no drift found" will misread a degraded run as a confident all-clear.
rai backlog close-drift --format agent
# Check against an explicit fixVersion instead of the resolved one
rai backlog close-drift --fix-version 3.1.0
Verdicts depend on which refs exist locally
unlanded requires the abandoned commit to be reachable from some
local ref. A checkout that never fetched that branch reports
no-evidence instead of unlanded for the same issue. --fetch
narrows this gap for the development ref; it cannot close it for a
deleted remote branch, which is unreachable to every checkout. Both
buckets are always reported, so no candidate is silently dropped.
rai backlog transition¶
Transition a backlog item to a new status.
| Argument | Description |
|---|---|
KEY |
Issue key (required) |
STATUS |
Target status (required) |
| Flag | Short | Description |
|---|---|---|
--adapter |
-a |
Adapter name override |
rai backlog batch-transition¶
Transition multiple backlog items at once.
| Argument | Description |
|---|---|
KEYS |
Comma-separated issue keys (required) |
STATUS |
Target status (required) |
| Flag | Short | Description |
|---|---|---|
--adapter |
-a |
Adapter name override |
rai backlog update¶
Update fields on a backlog item.
| Argument | Description |
|---|---|
KEY |
Issue key (required) |
| Flag | Short | Description |
|---|---|---|
--summary |
-s |
New summary |
--labels |
-l |
Comma-separated labels |
--priority |
Priority name | |
--assignee |
Assignee identifier | |
--field |
-F |
Custom field by ID (repeatable, e.g. -F customfield_13267=Value) |
--adapter |
-a |
Adapter name override |
rai backlog update PROJ-123 -s "Updated title" -l "urgent"
rai backlog update PROJ-123 --priority High --assignee alice
rai backlog update PROJ-123 -F customfield_13267=Interface
rai backlog link¶
Link two backlog items.
| Argument | Description |
|---|---|
SOURCE |
Source issue key (required) |
TARGET |
Target issue key (required) |
LINK_TYPE |
Link type, e.g. blocks, relates (required) |
| Flag | Short | Description |
|---|---|---|
--adapter |
-a |
Adapter name override |
rai backlog comment¶
Add a comment to a backlog item.
| Argument | Description |
|---|---|
KEY |
Issue key (required) |
BODY |
Comment text in markdown (required) |
| Flag | Short | Description |
|---|---|---|
--adapter |
-a |
Adapter name override |
rai backlog sync¶
Regenerate governance/backlog.md from a remote adapter.
| Flag | Short | Description |
|---|---|---|
--project |
-p |
Project key filter (e.g., PROJ) |
--adapter |
-a |
Adapter name override |
rai backlog pending-ops¶
Inspect and manage the pending-ops journal — the queue of backlog operations that failed to sync to a remote adapter (e.g., Jira) and are waiting for retry.
rai backlog pending-ops list¶
List active pending ops or dead-letter ops.
| Flag | Short | Description |
|---|---|---|
--dead |
Show dead-letter ops instead of the active queue | |
--format |
-f |
Output format: human (default), agent |
# Active queue (ops waiting to retry)
$ rai backlog pending-ops list
0 ops queued
# Dead-letter queue (ops that exhausted all retries)
$ rai backlog pending-ops list --dead
2 dead-letter ops:
50c9f836f47e transition_issue RAISE-4000 2026-05-06T04:33:24+00:00 (5 attempts)
5bf892ffbe3c transition_issue RAISE-4017 2026-05-06T04:48:21+00:00 (5 attempts)
rai backlog pending-ops count¶
Print the number of active pending ops. Useful for scripting and health checks.
rai backlog pending-ops purge¶
Remove ops from the active queue.
| Flag | Short | Description |
|---|---|---|
--id |
Remove only the op with this ID | |
--yes |
-y |
Skip the confirmation prompt |
# Purge all active ops (prompts for confirmation)
$ rai backlog pending-ops purge
3 ops queued. Purge all? [y/N]: y
Purged 3 ops.
# Purge a single op by ID
$ rai backlog pending-ops purge --id 50c9f836f47e
Removed op 50c9f836f47e (transition_issue RAISE-4000)
# Skip confirmation (useful in scripts)
$ rai backlog pending-ops purge -y
Dead-letter ops cannot be purged with this command
purge only clears the active queue (.raise/sync/backlog-pending-ops.jsonl).
Dead-letter ops live in a separate file (.raise/sync/backlog-dead-letter.jsonl) and are not removed by purge. To clear dead-letter entries, delete or edit that file directly:
# Clear all dead-letter ops
rm .raise/sync/backlog-dead-letter.jsonl
# Or inspect first, then delete
rai backlog pending-ops list --dead
rm .raise/sync/backlog-dead-letter.jsonl
Why do ops end up in dead-letter? When a remote operation (e.g., a Jira transition) fails, RaiSE queues it for retry. After 5 consecutive failures it moves the op to dead-letter to prevent infinite retry loops. Common cause: a status name typo (e.g., "commited" instead of "committed").
See also: rai adapter