Docs › Work items (Jira and Azure DevOps)
Work items (Jira and Azure DevOps)
The app's Work tab lists your open Jira issues and Azure DevOps work items, checks whether each one is ready to work on, and has a Start button that opens a Claude Code session on the hub for it. That session starts in plan mode: it reads the item, looks at the code and proposes a plan, and changes nothing until you approve the plan in the Claude app.
The tab only appears when app.json lists at least one source.
Setting up sources
Add a work section to ~/.config/sparehand/app.json on the hub (see app/app.example.json):
"work": {
"sources": [
{
"name": "Shop",
"type": "jira",
"site": "https://your-team.atlassian.net",
"jql": "assignee = currentUser() AND statusCategory != Done ORDER BY updated DESC",
"keychain": "sparehand-jira-your-team",
"account": "you@example.com",
"repos": { "SHOP": "/Users/you/code/shop" }
},
{
"name": "Platform",
"type": "azdo",
"org": "your-org",
"wiql": "SELECT [System.Id] FROM WorkItems WHERE [System.AssignedTo] = @Me AND [System.State] NOT IN ('Closed', 'Done', 'Removed')",
"keychain": "sparehand-azdo-your-org",
"multiRepo": true,
"lightStart": true,
"repos": { "*": "/Users/you/code/platform" }
}
]
}
| Field | Meaning |
|---|---|
name | Shown in the tab. |
type | jira (Jira Cloud) or azdo (Azure DevOps). |
site / org | Your Jira site URL / your Azure DevOps organisation. |
jql / wiql | Which items to list. Keep it to items assigned to you. |
keychain | Name of the stored token (below). |
account | Optional: the Keychain item's account (your email). Set it when you've saved more than one item under the same keychain name, e.g. after re-saving a token under a new email; otherwise the first one found is used. |
repos | Which folder a Start opens in, per Jira project key / Azure DevOps project, or "*" for all. |
lightStart | Optional: true lets you start items that only lack details (see Light starts). |
multiRepo | true when that folder holds several repositories: Claude works out which one the item is about and names it in its plan. Otherwise the session gets a fresh git worktree of the repository. |
Restart the app after editing app.json.
Tokens
Tokens are never stored in files. On macOS they live in the Keychain. Copy the token, then on the hub:
# Jira: an API token from https://id.atlassian.com/manage-profile/security/api-tokens
security add-generic-password -U -s sparehand-jira-your-team -a you@example.com -w "$(pbpaste)"; pbcopy </dev/null
# Azure DevOps: a personal access token with "Work Items: Read"
security add-generic-password -U -s sparehand-azdo-your-org -a you@example.com -w "$(pbpaste)"; pbcopy </dev/null
Paste it this way rather than with a bare -w, which prompts for the token: that prompt silently cuts input at 128 characters, and Atlassian API tokens are longer, so Jira would answer 401. The pbcopy </dev/null empties the clipboard afterwards; the token never appears in your shell history (only the $(pbpaste) text does).
If Jira or Azure DevOps answers 401 after you replaced a token, check for an older item under the same name (security find-generic-password -s sparehand-jira-your-team) and either delete it (security delete-generic-password -s … -a OLD-EMAIL) or set account on the source.
Give tokens the least access that works: read access to work items is enough, since Sparehand never writes to the tracker.
On Linux, set environment variables for the app instead, named after the keychain value in capitals with other characters turned into _: SPAREHAND_TOKEN_SPAREHAND_JIRA_YOUR_TEAM and, for Jira, SPAREHAND_ACCOUNT_SPAREHAND_JIRA_YOUR_TEAM=you@example.com.
Readiness
An item shows Ready when:
- it isn't an epic (start one of its stories instead);
- it isn't already in review or testing;
- it has a real description (more than a title or one line);
- it has acceptance criteria (Azure DevOps' field, or text such as "acceptance criteria", "done when" or given/when/then in the description);
- nothing open blocks it.
Otherwise it lists what's missing, so you know what to add to the ticket first. Start is offered for ready items (and light ones, below), only once per item (starts are remembered in ~/.config/sparehand/work-starts.json).
Light starts
Many real tickets are just a title and a line. With "lightStart": true on a source, items whose only gaps are a thin description or missing acceptance criteria show Start (light details) instead of a list of what's missing. The session is then told to read the item's comments and linked items and to ask you its questions first, in the Claude app, and to plan only once the scope and "done when" are clear. Epics, items already in review or testing, and blocked items can never be started, light or not.
What Start does
It runs Claude Code on the hub, in the folder from repos:
claude --bg --remote-control "<key> <title>" --permission-mode plan --name "<key> <title>" [--worktree <slug>] "<prompt>"
The prompt contains the item's link, type, status, description and acceptance criteria, and these rules:
- read the full item (comments, linked items) if Claude's tracker tools can reach it;
- follow the repository's own rules (CLAUDE.md: branch names, commit format, tests);
- stay in plan mode: investigate, present a concrete plan, and wait for approval;
- never push, merge, deploy or change the item's status without explicit approval.
You follow and approve the session in the Claude app (it's started with Remote Control, so it shows up on your phone too). The claude command must be installed and signed in on the hub, and the folders in repos must already be trusted in Claude Code.
The app looks for claude in ~/.local/bin, ~/.claude/local, /opt/homebrew/bin and /usr/local/bin (a background service doesn't see the PATH from your ~/.zshrc). If it's somewhere else, set its full path in the work settings: "work": { "claude": "/path/to/claude", "sources": [...] }.
In the cloud
In the cloud, next to Start, starts the item as a Claude Code cloud session instead: the hub only starts it, and the work happens in the cloud on a copy of the repository's GitHub remote, so the hub can sleep once it has started. It is a session in the cloud that the dashboard runs, so it shows in the Sessions tab, and its work comes back there as a branch to pull in. The prompt is the same, except that it presents its plan and waits for your approval in the session (on claude.ai or in the Claude app), and pushes its work only to its own claude/… branch, never merging, deploying, opening a pull request or changing the item.
It needs sessions from the dashboard switched on, a folder in repos that is one git repository (not a folder of several, nor a source with "multiRepo"), with its origin on GitHub and your commits pushed, and Claude Code on the web set up for your account.
Safety
- Ticket text is untrusted. Anyone who can edit a ticket can write its description. The app shows it as plain text (never as HTML), and the prompt tells Claude that the copied text is information about the task, not instructions. The hard stop is plan mode: nothing in the repository changes until you have read and approved the plan. (A cloud session isn't started in plan mode: there the prompt asks it to wait for your approval, and its changes stay on its own branch until you pull them in.)
- Start is an action like Stop or Pause: it needs the same access as the rest of the app (loopback, or an allowed Tailscale login), the app's header and a same-origin request. The browser only sends a source name and an item key; the item, folder and prompt are looked up on the hub.
- Sparehand only reads the trackers. It never comments, transitions or edits items.
- To turn the tab off, remove the
worksection fromapp.json.