Skip to content
Merged
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,9 @@ The skills a person types, in the order they meet them:
and writes it to Jira only on your yes.
- `design-doc`: turns your notes into a design doc for work that spans several tickets, settling the
problem and goals with you first, and publishes on your yes.
- `ticket-audit`: sweeps the Jira project for gaps, duplicates, stale tickets and links, and applies
the actions you approve in one write plan.
- `ticket-audit`: sweeps the Jira project for gaps, duplicates, stale tickets and links, or a
repository's GitHub issues for duplicates and stale issues, and applies the actions you approve
in one write plan.

**Build**
- `work`: works out where a ticket or its pull request stands and runs the next phase; each phase
Expand Down Expand Up @@ -511,7 +512,7 @@ Most days need one command, `work`. Started, in the skills table: `typed only` r
| | `drawio` | typed or asked | Draw a context, component, flow or deployment diagram as draw.io XML, checked by `scripts/drawio_check.py`, to paste into a Confluence draw.io macro; `architecture-doc`, `design-doc` and `process-doc` run it for their diagrams |
| | `writing` | typed or asked | How tickets, PR bodies, commit bodies and rule wording are structured and worded; run it to review existing text. Never changes a fact |
| | `revise` | typed only | Monthly: prepare the revision report before the meeting, with `measures` adding tickets, escaped defects and build yield; a sweep of the window's merged diffs reports where they follow or break the rules and the documented practice; `apply` drafts what the group accepted; `correct`, between revisions, corrects something the shared standards got wrong, everywhere it is carried, while a disagreement with a rule goes through Disagree and the revision; `capture`, weekly or whenever pull requests have merged, harvests and reads them into the standard's log so `prepare` reads the month from there |
| | `ticket-audit` | typed only | Sweeps across the project's Jira, written to `.review/audit/`, then the actions they propose applied in Jira through one write plan on your yes |
| | `ticket-audit` | typed only | Sweeps across the project's Jira, or on a GitHub tracker its issues' duplicates and its open pull requests, written to `.review/audit/`, then the actions they propose applied in the tracker through one write plan on your yes |
| | `skill-feedback` | typed or asked | File a complaint about a skill or agent as a `skill-feedback` issue here, in your words, with the session's last turns attached when you choose, or a draft `revise` wrote for a procedure finding; you see the whole issue before your yes |
| | `rebase` | typed or asked | Rebase the current branch onto the default branch, or its pull request's base when you choose it; resolve the conflicts with one objectively clear resolution and stop at any where the two sides differ in intent or approach, showing both with a recommendation; never pushes, and prints the push command, its destination explicit and any `--force-with-lease` pinned to the commit it fetched |

Expand Down Expand Up @@ -739,9 +740,9 @@ session-start line or `work` says something unexpected, these files are what it
| `context/<ticket>.send/` | `ticket-draft`'s write plan: each description and comment as shown (`.txt`) and as sent (`.md`), and the description as read back (`stored.txt`) | `scripts/jira_markdown.py`; the person, to see what was sent | Rewritten at each plan |
| `jira-plan.md` | The write plan, run by `ticket-draft` and `ticket-audit`: each item, numbered, with its text in full as it will be sent, written before the plan is shown | You, from the link at the plan's gate | Replaced at the next showing of a plan |
| `jira-approval.json` | The write plan, run by `ticket-draft` and `ticket-audit`: this session's id, the time and each approved item's tool and target, written at your yes before the first call | `hooks/atlassian-gate.sh`, which allows only a call it lists | Removed by the skill when the plan finishes or stops; allows nothing after 30 minutes |
| `github-plan.md` | The GitHub write plan, run by `ticket-draft` on a GitHub tracker: each item, numbered, with its text in full as it will be sent, written before the plan is shown | You, from the link at the plan's gate | Replaced at the next showing of a plan |
| `github-approval-items.json` | The GitHub write plan, run by `ticket-draft` on a GitHub tracker: the approved items, written with the Write tool so a title's quotes never pass through a command | The plan's `jq` command, which builds `github-approval.json` from it | Removed with the record |
| `github-approval.json` | The GitHub write plan, run by `ticket-draft` on a GitHub tracker: this session's id, the time and each approved item's tool and target, written at your yes before the first call | `hooks/issue-gate.sh`, which allows only a call it lists and leaves every other to your own permissions | Removed by the skill when the plan finishes or stops; allows nothing after 30 minutes |
| `github-plan.md` | The GitHub write plan, run by `ticket-draft` and `ticket-audit` on a GitHub tracker: each item, numbered, with its text in full as it will be sent, written before the plan is shown | You, from the link at the plan's gate | Replaced at the next showing of a plan |
| `github-approval-items.json` | The GitHub write plan, run by `ticket-draft` and `ticket-audit` on a GitHub tracker: the approved items, written with the Write tool so a title's quotes never pass through a command | The plan's `jq` command, which builds `github-approval.json` from it | Removed with the record |
| `github-approval.json` | The GitHub write plan, run by `ticket-draft` and `ticket-audit` on a GitHub tracker: this session's id, the time and each approved item's tool and target, written at your yes before the first call | `hooks/issue-gate.sh`, which allows only a call it lists and leaves every other to your own permissions | Removed by the skill when the plan finishes or stops; allows nothing after 30 minutes |
| `controlled-cleared.json` | `hooks/controlled-gate.sh`, after a read of a `.review/` file marked `Controlled:` that you allowed, or the session's own write of one: this session's id and the items cleared | The same hook, which lets this session's later reads of those items through | Replaced when another session clears an item |
| `context/<ticket>.writes.md` | `ticket-draft`'s write plan: each item and whether it was written, with its key, failed, dropped or left to paste | The person | Rewritten at each plan |
| `implementation-plan-<ticket>.md` | `implement-change`: a draft from the planner, before the plan review, `Approved by:` at it, `Base:` at the branch, `## Corrections` at the plan and diff gates, `## Provisional decisions` for each decision made for now, and each `## Revision` with its own `Approved by:`; named for the branch with no ticket | `implement-change` on resume and at step 8 (`Depth:`, and `## Corrections` for a lowered depth), `work` and the session-start line (`Approved by:`), `pr-create` (`Base:`, `Approved by:`, `## Provisional decisions`), `commit` (the reason) | Not cleared by the tools |
Expand Down
4 changes: 2 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ merged pull request is its record. Owners are roles. Status is `planned`, `defer
| --- | --- | --- | --- | --- |
| Neutral examples in generic skills (#21) | `quickstart` still checks for the plugin this one replaced, and `using-curryer` still ships in the plugin, loaded only in curryer and the repositories that depend on it (#67). `scripts/coupling.json` allows the rest and does not scan the docs (#15). `using-curryer` leaves for curryer's own standard, or a domain plugin installed beside this one | plugin maintainer | before the public flip | planned |
| Forge, tracker and wiki as roles (#24) | Every skill speaks GitHub, Jira or Confluence directly, so a repository on GitLab or tracking work in GitHub Issues gets little of the workflow. One documented shape per role, the neutral thread JSON as the forge's, with the current skills as the first adapters; GitLab next, then GitHub Issues as a tracker | plugin maintainer | a team on GitLab or GitHub Issues adopts the plugin | idea |
| The skills on the ticket shape (#58) | The shape, the format and the profile's `issue_tracker:` are tracker-neutral (`docs/contracts.md`, "The ticket shape"; `standards/ticket-format.md`), but `ticket-audit` still reads and writes only Jira, and `onboard` still writes `jira:`. No ticket is kept as a file in the repository: a ticket is drafted once, in the format, for whichever tracker files it | plugin maintainer | with #59 | planned |
| GitHub Issues as a tracker (#59) | Most repositories outside LASP track work in GitHub Issues, through a server already connected for pull requests; it is the first tracker adapter after Jira. Reading an issue, `work` routing by its state and labels, and `ticket-draft` drafting and filing one under an approved write plan with an allow-only gate have landed. Left: onboard detecting GitHub Issues as the tracker, the project's branch convention and mapping its labels to the roles; then the audit sweeps; no Projects fields or estimates | plugin maintainer | the ticket shape's profile and format land | planned |
| The skills on the ticket shape (#58) | The shape, the format and the profile's `issue_tracker:` are tracker-neutral (`docs/contracts.md`, "The ticket shape"; `standards/ticket-format.md`), but `onboard` still writes `jira:`. No ticket is kept as a file in the repository: a ticket is drafted once, in the format, for whichever tracker files it | plugin maintainer | with #59 | planned |
| GitHub Issues as a tracker (#59) | Most repositories outside LASP track work in GitHub Issues, through a server already connected for pull requests; it is the first tracker adapter after Jira. Reading an issue, `work` routing by its state and labels, `ticket-draft` drafting and filing one under an approved write plan with an allow-only gate, and `ticket-audit`'s `duplicates` and `pulls` sweeps closing issues through the same plan have landed. Left: onboard detecting GitHub Issues as the tracker, the project's branch convention and mapping its labels to the roles; no Projects fields, estimates or sub-issues | plugin maintainer | the ticket shape's profile and format land | planned |
| A GitLab forge adapter (#61) | A repository on GitLab gets local-only reviews; the adapter writes the thread shape (#60) through a GitLab server or `glab` | plugin maintainer | step 5 of #24's order, after #60 | planned |
| Bitbucket, other trackers, Markdown files as a wiki (#62) | No team has asked yet | plugin maintainer | a team asks | idea |

Expand Down
21 changes: 20 additions & 1 deletion agents/source-reader.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,16 @@ could not be read, and nothing else; never ask:
sizes or commits, with the error verbatim.
- The `pulls` sweep without Atlassian: write its file with each ticket's status as `not read:
<error verbatim>`; without GitHub, return the failure.
- On a GitHub tracker, a sweep needs GitHub, not Atlassian: without GitHub, return the failure.

A status a task or a skill names by its role (filed, approved, implementation, finished,
abandoned) is the one `python3 "${CLAUDE_PLUGIN_ROOT}/scripts/profile.py" --defaults --field
jira.roles` gives that role. An error from it, a non-zero exit, makes each line
that needs a role `not read: <error verbatim>`, and `not yet recorded` makes it `not read: no Jira
workflow is recorded for this repository`; a status is never taken from a skill's prose in its
place.
place. On a GitHub tracker the role's label is `--defaults --field issue_tracker.roles.<role>`, in
place of `jira.roles`, `none` meaning the role has no label, and an error from it makes the line
`not read: <error verbatim>` as above.

## Tasks

Expand Down Expand Up @@ -155,6 +158,22 @@ written to `.review/audit/<YYYY-MM-DD>-<slug>.md`. For `pulls`, the caller also
directory holding the state blocks and each pull request's `pr.json`, which you read in place
of fetching the pull requests again.

On a GitHub tracker, where `--field issue_tracker.kind` prints `github`, the sweep is `duplicates`
or `pulls`, as `${CLAUDE_PLUGIN_ROOT}/skills/ticket-audit/github.md` sets out, on the repository
the caller names, `Tracker: github <owner/repo>`, each issue written `#<n>`; a GitHub sweep
without that line returns `sweep: no issues repository named` and nothing else. `duplicates` reads the open issues with `list_issues`, state `OPEN`, paged
until `hasNextPage` is false, and the comments of each issue a finding names with `issue_read`
`get_comments`; for each issue of a pair, the pull requests naming it, with
`search_pull_requests` on this repository, the owner/repo `git remote get-url origin` names, since
pull requests live there and not in the tracker's: query `repo:<origin> "#<n>"` when
`--field issue_tracker.location` prints `none` or names that repository, and otherwise
`repo:<origin> "<location>#<n>"` and again `repo:<origin> "<location>/issues/<n>"` for a body
linking the issue, the search that also finds what satisfied an issue. `pulls` takes each pull request's issue from its state block's `ticket:` line, as
`${CLAUDE_PLUGIN_ROOT}/docs/contracts.md`'s "The record" reads a `Ticket:` line on a GitHub
tracker, and reads that issue with `issue_read` `get` for its state, `state_reason` and labels,
in the named repository, or in the pull request's own when `--field issue_tracker.location`
prints `none`.

```
## sweep — <slug>
<the sweep's summary line>
Expand Down
17 changes: 10 additions & 7 deletions docs/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ not parse in this shape, a subagent's call, a call with any other argument, such
missing.

Writers: the GitHub write plan (`skills/using-github/issues.md`, "Running it"), run by
`ticket-draft`, at the person's yes, with `jq` from the items it writes to
`ticket-draft` and `ticket-audit`, at the person's yes, with `jq` from the items it writes to
`.review/github-approval-items.json`; both removed when the plan finishes or stops. Readers:
`hooks/issue-gate.sh`.

Expand Down Expand Up @@ -290,7 +290,7 @@ Pinned by: tests/test_next_phase.py::test_an_agree_that_carries_its_response_is_

## The thread dump

Version: 6
Version: 7

Fields: `.review/threads/pr-NNNN/` (and `.review/harvest/threads/pr-NNNN/`): `pages/`, each
`pull_request_read` result as the server returned it, one file per call, from which
Expand All @@ -308,7 +308,9 @@ version 3 states the `html_url` requirement; version 4 added `pages/` and `threa
checks; version 5 has `thread_dump.py` refuse a directory not named `pr-NNNN`; version 6 lets a
list be paged below 100, named by `--per-page`, and has `save_page.py` refuse a response that is
not JSON, such as the harness's size-limit notice, and clear a pull request's
`get_review_comments` pages at its first page. Beside them, `judged.json`, "The
`get_review_comments` pages at its first page. Version 7 has `save_page.py` save the text of a
response that is a list of one text block, as Claude Code passes some servers' results, a stdio server's among them, and
refuse any other list. Beside them, `judged.json`, "The
judgments", is `pr-reader`'s own.

Writers: `pr-reader`, copying each page `hooks/save-page.sh` saved under
Expand Down Expand Up @@ -738,7 +740,7 @@ Pinned by: tests/test_profile.py::test_a_value_of_the_wrong_shape

## The ticket shape

Version: 2
Version: 3

Fields: a ticket, in whatever tracker files it, is an id (a Jira key, `<KEY>-NNNN`, or a GitHub
issue's number), a title (Jira's summary), a description in `standards/ticket-format.md`'s format,
Expand All @@ -759,13 +761,14 @@ A Jira workflow maps each role to exactly one status. A GitHub tracker maps each
label, and `--defaults --field issue_tracker.roles.<role>` prints `none` for a role with no label:
an issue's own open and closed states stand for `filed`, `finished` and `abandoned`. On a GitHub
tracker `ticket-draft` reads `issue_tracker.roles.<role>` and skips a move into a role whose label
is `none` (version 2); `ticket-audit` still reads `jira.roles`, which prints `not yet recorded` for
a GitHub tracker, and stops.
is `none` (version 2); `ticket-audit` reads `issue_tracker.roles` there in place of `jira.roles`,
for the label a close removes or adds and, in `source-reader`'s `pulls` sweep, for the `approved`
and `implementation` labels an open issue lacks when its pull request waits on approval (version 3).
An open issue that carries no mapped label is in `filed`, and `work` sends it to `ticket-draft`.

Writers: a project's standard, through `issue_tracker:` ("The profile"); `standards/ticket-format.md`
and the tracker's skill, `using-jira`, for the description. Readers: `scripts/profile.py`, and
through it `scripts/next_phase.py`, for a Jira workflow or an issue's labels, the skills that read `jira.roles`, and `ticket-draft` on a GitHub tracker.
through it `scripts/next_phase.py`, for a Jira workflow or an issue's labels, the skills that read `jira.roles`, and `ticket-draft` and `ticket-audit` on a GitHub tracker.

Pinned by: tests/test_profile.py::test_a_github_tracker_maps_at_most_one_label_to_each_role

Expand Down
Loading
Loading