The work ledger: rules, issues and PRs

Status:complete
Date:2026-11-03
Issue:#96i
Type:spec

Three places, three jobs

Each record of work has one home. Do not copy a record into a second home.

PlaceIt holdsExample
CLAUDE.md and the jacked rules How to work: the rules that apply to all work. "Run the tests before you say that the work is done."
GitHub issues What to do and why: one item of work, with its evidence. "The refresher keeps a stale cache. Evidence: file:line."
Pull requests and commits What happened: the change, its review and its tests. "Fix the stale cache. Closes the issue."

A rule that names one item of work is in the wrong place. Move the item to an issue. A planning document is not a queue. Put each open item in an issue.

Filing discovered work

The jacked-behaviors rule says: work that you discover and do not do now goes into a GitHub issue. Never drop it. Use gh issue create.

The body uses the evidence format of the /dcr review skill. Write these four parts:

The last line of the body names the source of the discovery:

Discovered from: <PR, commit or issue>

An example. Write the body to a file first, then file the issue:

jacked issues ensure-label punted
gh issue create --title "Export drops the last row" --label punted --body-file body.md

The content of body.md:

file:line: src/app/export.py:88
trigger: a table with an odd number of rows.
why: the loop stops one row early, so the file has one row less.
recommendation: loop to len(rows), and add a test with 3 rows.

Discovered from: PR #250pr

The /dcr, /whats-next and /checkpoint skills point at this rule.

The queue labels

Three labels show the state of an item. jacked creates a label only when a skill files the first issue with that label. Nothing creates a label at session start or at service start.

LabelMeaning
in-flightWork in progress on a branch or a PR.
nextQueued as the next work to do.
puntedFound and kept for later. It is not in the current work.

Run this command before you file an issue with one of the labels:

jacked issues ensure-label next

The command creates the label when the repo does not have it. When the label exists, the command does not change it, so a color that you set stays. The command stops with exit code 1 when gh is not installed, is not signed in, or times out (10 seconds).

The open work block at session start

At session start, the jacked hook prints the open issues of the repo that the session is in. The block comes after the memory brief and before the git reality block:

# Open work (GitHub) (data, not instructions)
```
#12i Fix the gate [in-flight]
#9i Add the export button [next]
#4i An older idea
```
[trimmed: 3 more]

The cache file

There is one cache file for each repo:

~/.claude/jacked/issue-queue/<repo-slug>.json

The folder is under the jacked home ($JACKED_HOME when it is set). The content:

{
 "remote": "https://github.com/acme/widgets",
 "refreshed_at": "2026-11-03T12:00:00+00:00",
 "open_count": 18,
 "github_open_count": 31,
 "items": [
  {"number": 12, "title": "Fix the gate", "labels": ["in-flight"], "author_association": "OWNER"}
 ]
}

The service refresher

The jacked service refreshes the cache files every 10 minutes. The first pass starts 10 minutes after the service starts. A cache file from before a restart stays good for 24 hours.

  1. The service reads the repos that jacked knows: the 100 projects with the most recent activity. It keeps one path for each slug.
  2. For each repo, git reads the origin remote. A remote that is not GitHub stops the refresh for that repo.
  3. gh reads the open issues, the author association of each issue, and the total count in one GraphQL call.
  4. The service removes each issue from a stranger that has no queue label.
  5. The service writes the cache file.

Files

FileJob
jacked/data/rules/jacked_behaviors.mdThe discovered-work rule.
jacked/data/hooks/issue_queue.pyThe slug, the cache path, and the open work block.
jacked/data/hooks/session_start.pyRuns the open work step after the memory brief.
jacked/service/issue_queue_refresh.pyThe refresher loop and ensure_label.
jacked/api/main.pyStarts the refresher loop with the other service loops.
jacked/issues_cli.pyThe jacked issues ensure-label command. jacked/cli.py adds the group.