@workit-dev/pi 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -43
- package/dist/worker.js +10272 -0
- package/dist/workit.js +29682 -0
- package/package.json +47 -6
- package/skills/workit-architecture/SKILL.md +72 -0
- package/skills/workit-architecture/agents/openai.yaml +3 -0
- package/skills/workit-architecture/references/instruction-files.md +52 -0
- package/skills/workit-architecture/references/vocabulary.md +53 -0
- package/skills/workit-bdd/SKILL.md +53 -0
- package/skills/workit-continue/SKILL.md +54 -0
- package/skills/workit-debug/SKILL.md +45 -0
- package/skills/workit-deslop/SKILL.md +58 -0
- package/skills/workit-fanout/SKILL.md +71 -0
- package/skills/workit-fanout/references/brief.md +141 -0
- package/skills/workit-fanout/references/orchestration.md +169 -0
- package/skills/workit-implement/SKILL.md +71 -0
- package/skills/workit-retro/SKILL.md +72 -0
- package/skills/workit-retro/agents/openai.yaml +3 -0
- package/skills/workit-retro/references/sources.md +35 -0
- package/skills/workit-retro/references/steering.md +39 -0
- package/skills/workit-review/SKILL.md +66 -0
- package/skills/workit-review/references/impact.md +24 -0
- package/skills/workit-shape/SKILL.md +71 -0
- package/skills/workit-shape/references/diagrams.md +17 -0
- package/skills/workit-shape/references/knowledge.md +61 -0
- package/skills/workit-shape/references/mockups.md +15 -0
- package/skills/workit-shape/references/slicing.md +44 -0
- package/skills/workit-ship/SKILL.md +71 -0
- package/skills/workit-ship/references/changelog.md +44 -0
- package/skills/workit-ship/references/pr-body.md +32 -0
- package/skills/workit-ship/references/release.md +39 -0
- package/skills/workit-test-audit/SKILL.md +54 -0
- package/skills/workit-verify-app/SKILL.md +68 -0
- package/skills/workit-verify-app/references/template.md +51 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Worker brief template
|
|
2
|
+
|
|
3
|
+
`workit fanout brief <slice>` renders this brief from the plan, the standing
|
|
4
|
+
orders in force (`workit ledger standing list`) and the slice's scratch dir;
|
|
5
|
+
pass its output verbatim. The template below is what it fills in. Every field
|
|
6
|
+
is required. A brief with an empty field is not spawned. Point to files and
|
|
7
|
+
ledger rows instead of pasting their content. Size the slice so the worker
|
|
8
|
+
finishes it in about 150k tokens of context; split a larger one first.
|
|
9
|
+
|
|
10
|
+
```md
|
|
11
|
+
MODE: <new | resume (a replacement continuing a branch with commits)>
|
|
12
|
+
WORKER: <slice id: a spawn prompt that names it binds that worker on OpenCode>
|
|
13
|
+
GOAL: <one observable outcome, in the user's terms>
|
|
14
|
+
SCOPE: <file-scope manifest: the globs this worker may write; everything else is read-only>
|
|
15
|
+
branch: <type>/<slug> base: <trunk or parent branch>
|
|
16
|
+
CONTEXT: <pointers: spec section, ledger decisions, the neighbour file to imitate>
|
|
17
|
+
ACCEPTANCE:
|
|
18
|
+
- Given <state>, When <action>, Then <observable result>
|
|
19
|
+
VERIFY: <exact commands, e.g. `workit check test`, the verify-<app> feature to drive>
|
|
20
|
+
TIER: <mundane | standard | hard: how much model the slice needs>
|
|
21
|
+
TIMEBOX: <wall clock, N tool calls (hard: 180, else 120) and the call by which the full gates ran (60%); past it without a new commit you will be replaced>
|
|
22
|
+
SCRATCH: <your own temp dir: the one `fanout worktree create` printed, else `mktemp -d`; never a shared path>
|
|
23
|
+
FORBIDDEN: <no edits outside SCOPE; no new dependencies; ...>
|
|
24
|
+
FAN-IN: <one PR per slice: no rebase, retarget, merge or force-push | integration: merge the integration tip before reporting, nothing else>
|
|
25
|
+
REPORT: branch, head SHA, files changed, each VERIFY command with its exit code,
|
|
26
|
+
each ACCEPTANCE line met / not met, rulings you made (`workit ledger ruling`),
|
|
27
|
+
anything out of scope as a follow-up, not a diff.
|
|
28
|
+
STANDING: <the standing orders, verbatim: `workit ledger standing add` records each one>
|
|
29
|
+
WORKTREE: <the path `workit fanout worktree create <slice>` made; the worker runs `workit <verb> --cwd <it> …` there>
|
|
30
|
+
<identity line, per the lead's host: see "Identity and git rules per host" below>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Worked example
|
|
34
|
+
|
|
35
|
+
```md
|
|
36
|
+
MODE: new
|
|
37
|
+
WORKER: usage-endpoint
|
|
38
|
+
GOAL: `GET /v1/usage` returns the workspace's run count per UTC day for the last 7 days.
|
|
39
|
+
SCOPE: src/routes/usage.ts, src/queries/usage.ts, test/usage.test.ts
|
|
40
|
+
branch: feature/usage-endpoint base: main
|
|
41
|
+
CONTEXT: spec docs/usage/spec.md "Behavior"; ledger decision "counts are per UTC day";
|
|
42
|
+
imitate src/routes/runs.ts for auth and error shape.
|
|
43
|
+
ACCEPTANCE:
|
|
44
|
+
- Given 3 runs today and 1 yesterday, When GET /v1/usage, Then the last two entries are {"runs":1} and {"runs":3}
|
|
45
|
+
- Given no auth header, When GET /v1/usage, Then the status is 401
|
|
46
|
+
VERIFY: `workit check test`; verify-api feature "usage"
|
|
47
|
+
TIER: standard
|
|
48
|
+
TIMEBOX: 45 minutes, 120 tool calls (run your full VERIFY gates by call 72)
|
|
49
|
+
SCRATCH: ~/.local/state/workit/worktrees/app/usage-endpoint/.workit-scratch
|
|
50
|
+
FORBIDDEN: no edits outside SCOPE; no schema migration; no new packages
|
|
51
|
+
FAN-IN: one PR per slice. Never rebase, retarget, merge or force-push: the lead owns topology.
|
|
52
|
+
REPORT: as in the template
|
|
53
|
+
STANDING: conventional commits; no comments that restate code; ask nothing, record rulings instead
|
|
54
|
+
WORKTREE: ~/.local/state/workit/worktrees/app/usage-endpoint (made by `workit fanout worktree create usage-endpoint`; yours alone)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Plan file
|
|
58
|
+
|
|
59
|
+
`workit fanout plan <plan.json>` (keep it in `workit dir plans`) records the slices before any spawn. Each
|
|
60
|
+
slice carries the brief fields the plan checks (goal, scope, acceptance,
|
|
61
|
+
verify, forbidden must be filled; tier is mundane, standard or hard). `base`
|
|
62
|
+
defaults to the trunk, or to the branch of a single `dependsOn` slice (a
|
|
63
|
+
stack); `worktree` defaults to `<state>/worktrees/<repo>/<id>` (`workit dir state`). `owns` claims a shared
|
|
64
|
+
file another slice's glob also matches. Globs that match no file yet are compared
|
|
65
|
+
through a sample path. Use `/` as the separator; a backslash only escapes
|
|
66
|
+
literal brackets: `"app/\\[id\\]/page.tsx"`. A `reason` (`explore`, `parallel`, `backstop` or `high-risk-verify`) is rendered as the brief's `REASON:` line and is
|
|
67
|
+
required unless the workspace sets `delegation` to `lead-orchestrates`. A `timebox` such as `45 minutes`
|
|
68
|
+
is the slice's STUCK threshold in `workit fanout status`. `"fanIn":
|
|
69
|
+
"integration"` (with an integration branch as `trunk`) is the one-PR mode in
|
|
70
|
+
`orchestration.md`; the default `"prs"` lands one PR per slice.
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"name": "usage",
|
|
75
|
+
"trunk": "main",
|
|
76
|
+
"slices": [
|
|
77
|
+
{
|
|
78
|
+
"id": "usage-endpoint",
|
|
79
|
+
"branch": "feature/usage-endpoint",
|
|
80
|
+
"tier": "standard",
|
|
81
|
+
"scope": ["src/routes/usage.ts", "src/queries/usage.ts", "test/usage.test.ts"],
|
|
82
|
+
"owns": ["package.json"],
|
|
83
|
+
"goal": "GET /v1/usage returns the run count per UTC day for the last 7 days",
|
|
84
|
+
"acceptance": ["Given no auth header, When GET /v1/usage, Then the status is 401"],
|
|
85
|
+
"verify": ["workit check test"],
|
|
86
|
+
"forbidden": ["no edits outside SCOPE", "no rebase or force-push"],
|
|
87
|
+
"reason": "parallel",
|
|
88
|
+
"context": "docs/usage/spec.md Behavior",
|
|
89
|
+
"timebox": "45 minutes"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "usage-docs",
|
|
93
|
+
"branch": "docs/usage",
|
|
94
|
+
"tier": "mundane",
|
|
95
|
+
"dependsOn": ["usage-endpoint"],
|
|
96
|
+
"scope": ["docs/usage/**"],
|
|
97
|
+
"goal": "The API guide documents GET /v1/usage",
|
|
98
|
+
"acceptance": ["Given the guide, When a reader looks up usage, Then the response shape is shown"],
|
|
99
|
+
"verify": ["workit check docs"],
|
|
100
|
+
"forbidden": ["no edits outside SCOPE"]
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Identity and git rules per host
|
|
107
|
+
|
|
108
|
+
`workit fanout brief` renders the identity line, the model lines and RULES 1
|
|
109
|
+
and 3 for the worker's host: `--host <host>` (claude_code, codex, opencode,
|
|
110
|
+
cursor, pi), else the lead's (`WORKIT_HOST`, or the host's own session
|
|
111
|
+
variable). With no known host it warns on stderr and names the valid ones.
|
|
112
|
+
RULE 3 carries the host's concrete Co-Authored-By line as a `--trailer`.
|
|
113
|
+
|
|
114
|
+
| Lead's host | Identity line | RULES 1 and 3 |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
| Claude Code | `Session: your env already has WORKIT_SESSION_ID (the lead's id)`; no `export`, no hand-minted id (SubagentStart issues `<lead>:<agent id>` only to verifiers and reviewers, never to an implementer, so the worker's commits carry the lead's id) | `workit git branch <branch> --base <base>`, `workit git commit -m <msg> -- <paths in SCOPE>` in the Workit worktree (the spawn hook drops `isolation`); only a host-isolated `.claude/worktrees/agent-<id>` takes plain git, as its SubagentStart text says, since that isolation refuses a git wrapper |
|
|
117
|
+
| OpenCode, Pi, Codex | `Session: your host already sets WORKIT_SESSION_ID in your shell`; export nothing (the host derives the id and an export cannot replace it) | `workit git branch <branch> --base <base>`, `workit git commit -m <msg> -- <paths in SCOPE>` |
|
|
118
|
+
| Cursor, CI, a plain terminal | `export WORKIT_SESSION_ID=<lead>-w-<slice>` (`+try<n>` for a race attempt): declared, not checked | the same `workit git` forms |
|
|
119
|
+
|
|
120
|
+
Once `workit fanout worktree create <slice>` made the worktree, the brief's
|
|
121
|
+
WORKTREE line names it and RULES 1 and 3 run against it on every host:
|
|
122
|
+
`workit git --cwd <worktree> commit …`, `workit check --cwd <worktree> <name>`,
|
|
123
|
+
one verb per call. The worktree is already on the branch (MODE new or resume),
|
|
124
|
+
so no branch command comes first. Without one, `MODE: resume` is
|
|
125
|
+
`git switch <branch>` (the branch exists), then continue from its head. A race
|
|
126
|
+
attempt (`--attempt <n>`) follows its host's row with the branch
|
|
127
|
+
`<branch>-try<n>`.
|
|
128
|
+
|
|
129
|
+
## Worker rules (`workit fanout brief` appends them as RULES)
|
|
130
|
+
|
|
131
|
+
1. Work only in WORKTREE, already on the branch, one verb per call against it
|
|
132
|
+
(`workit <verb> --cwd <worktree> …`); Workit's hooks deny an implementer's change
|
|
133
|
+
outside it. With no worktree made yet: create the branch (`MODE: new`) or
|
|
134
|
+
`git switch` to it (`MODE: resume`), as the table above says.
|
|
135
|
+
2. Decide ambiguities yourself and record them:
|
|
136
|
+
`workit ledger ruling "<what>" --why "<why>" --cost-if-wrong "<cost>"`.
|
|
137
|
+
Stop only for an irreversible action, a security-sensitive one, or a side
|
|
138
|
+
effect outside the worktree.
|
|
139
|
+
3. Commit with `workit git --cwd <worktree> commit -m "<msg>" --trailer "<host's Co-Authored-By>" -- <paths in SCOPE>`;
|
|
140
|
+
push only if the brief says so.
|
|
141
|
+
4. Never record a verdict on your own work.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# Running a fanout
|
|
2
|
+
|
|
3
|
+
How the lead picks models, keeps workers flowing, retries, races, verifies
|
|
4
|
+
and fans in. Workit records and checks; the host's own subagents run the work.
|
|
5
|
+
|
|
6
|
+
## TIER to model
|
|
7
|
+
|
|
8
|
+
TIER is a field of each slice and of its brief. Role models come from the
|
|
9
|
+
workspace (`models.roles`; `fanout.tierModels` still feeds the implementer
|
|
10
|
+
tiers) and, on Claude Code, built-in defaults: the brief has a `model:` line
|
|
11
|
+
(with `effort:` when set) under TIER and a `verifier:` line; `workit fanout
|
|
12
|
+
status` names the model next to each spawnable slice; `workit models show
|
|
13
|
+
[--role r] [--host h] --json` lists every role (decider, implementer tiers,
|
|
14
|
+
verifier, reviewer, explore, babysit). Pass exactly that `model` (and `effort`
|
|
15
|
+
where the host's spawn call takes one) on the spawn call: a subagent that
|
|
16
|
+
passes none inherits your model. Scouting and PR babysitting use the `explore`
|
|
17
|
+
and `babysit` roles. A role with no model (other hosts without config) runs
|
|
18
|
+
on the host's model, and TIER only sizes the timebox and decides whether to
|
|
19
|
+
race. Claude Code's built-in defaults, when nothing is configured:
|
|
20
|
+
|
|
21
|
+
| Role or TIER | `model` on the Agent call |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| decider | `fable`, effort `high` |
|
|
24
|
+
| hard | `opus` |
|
|
25
|
+
| standard | `sonnet` |
|
|
26
|
+
| mundane | `haiku` |
|
|
27
|
+
| verifier | `sonnet` |
|
|
28
|
+
| reviewer | `opus` |
|
|
29
|
+
| explore, babysit | `haiku` |
|
|
30
|
+
|
|
31
|
+
Claude Code and OpenCode also get the role's model set on the spawn by
|
|
32
|
+
Workit; a configured one beats a `model` you pass unless
|
|
33
|
+
`models.allowLeadOverride` is true. A general spawn takes
|
|
34
|
+
`models.roles.default`, or the role its prompt's `ROLE: <role>` line names.
|
|
35
|
+
`models.lead` (your own model) is advisory. `workit models show` marks each
|
|
36
|
+
role `enforced` or `advisory` per host: on advisory, pass the model.
|
|
37
|
+
|
|
38
|
+
## Rolling window
|
|
39
|
+
|
|
40
|
+
Keep 4-6 workers in flight on Claude Code; elsewhere as many as the host runs
|
|
41
|
+
in the background, never more than 6. Do not wait for a whole wave: when one
|
|
42
|
+
worker finishes (its notification, or a new head or PR in `workit fanout
|
|
43
|
+
status`), verify it, then spawn the next slice from `spawnable` in the same
|
|
44
|
+
status output. A slice whose dependencies landed, or a stacked child whose
|
|
45
|
+
parent is verified, appears there by itself.
|
|
46
|
+
|
|
47
|
+
## Retry, then escalate
|
|
48
|
+
|
|
49
|
+
A slice is retried when it is STUCK, its worker exits without meeting
|
|
50
|
+
ACCEPTANCE, or its verdict fails. Stop the worker and observe that it exited.
|
|
51
|
+
Release its worktree: `workit fanout worktree release <slice>` (it records
|
|
52
|
+
`git status` first), and create it again for the retry. Then spawn one fresh
|
|
53
|
+
worker with `workit fanout brief <slice> --mode resume`: same branch, and the
|
|
54
|
+
brief points at its head and its ledger rows (last report, verdicts,
|
|
55
|
+
rulings). If the retry fails too, escalate instead of a third worker:
|
|
56
|
+
re-slice it smaller (`workit fanout plan` again), take it over yourself, or
|
|
57
|
+
report the gap to the user.
|
|
58
|
+
|
|
59
|
+
## Stuck calls: the decider
|
|
60
|
+
|
|
61
|
+
A failed review gets one fix round and one recheck (the changed hunks only).
|
|
62
|
+
If the recheck fails, or a worker and a reviewer disagree, spawn a decider
|
|
63
|
+
instead of a third round. A decider is a fresh read-only agent, not the author
|
|
64
|
+
or the reviewer. It returns three things: the options, a pick by
|
|
65
|
+
reversibility (the option cheapest to undo wins a tie), and the exact change
|
|
66
|
+
list. The fixer applies that list once, then one focused recheck follows.
|
|
67
|
+
|
|
68
|
+
- Hard call (shared contract, security, migration): two deciders on different
|
|
69
|
+
models (Claude Code, OpenCode, Cursor: the `decider` role model and a
|
|
70
|
+
different `model` on the spawn, kept on a configured decider role only with
|
|
71
|
+
`models.allowLeadOverride`; Codex and Pi: one decider). If they disagree, you take the
|
|
72
|
+
more reversible option.
|
|
73
|
+
- Record it: `workit ledger decision "<pick>" --by decider --why "<why it is
|
|
74
|
+
the more reversible>" --view "<decider A: view>" --view "<decider B: view>"`.
|
|
75
|
+
The row is listed as a decider call; it is never the user's answer to a
|
|
76
|
+
product choice and never a verdict.
|
|
77
|
+
- A product choice, or authority nobody here has, is not a decider's call:
|
|
78
|
+
ask the user with your recommendation.
|
|
79
|
+
|
|
80
|
+
## Race a hard slice
|
|
81
|
+
|
|
82
|
+
When a hard slice has an uncertain approach and a cheap VERIFY, run 2-3
|
|
83
|
+
attempts at once instead of retrying in series. `workit fanout brief <slice>
|
|
84
|
+
--attempt <n>` gives each attempt its own branch (`<branch>-try<n>`), session
|
|
85
|
+
and scratch dir. Each attempt needs its own worktree, and `fanout worktree
|
|
86
|
+
create` makes only the slice's own one, so run the attempts one after another
|
|
87
|
+
there on every host.
|
|
88
|
+
Verify every attempt, keep the one with the best verdict (accepted first,
|
|
89
|
+
then the fewest changed files, then the earliest), point the slice branch at
|
|
90
|
+
it (`git branch <branch> <winner>`), have the verifier record the verdict on
|
|
91
|
+
`<branch>` (same head), and delete the losing attempt branches.
|
|
92
|
+
|
|
93
|
+
## Verification
|
|
94
|
+
|
|
95
|
+
Follow the workspace `verification` setting (`workit grant show`); the
|
|
96
|
+
worker never records a verdict on its own work.
|
|
97
|
+
|
|
98
|
+
- `self` (the default): a verifier that wrote none of the slices records the
|
|
99
|
+
verdicts. A lead that authored none of the slices may record them in its
|
|
100
|
+
own session.
|
|
101
|
+
- `independent`, and any slice at high risk: a separate verifier session
|
|
102
|
+
records them, never the lead's own; at high risk one verifier per slice,
|
|
103
|
+
plus a review panel (below). This is doctrine, not enforced: the ledger
|
|
104
|
+
only tells a branch's authors from everyone else, and a lead that wrote
|
|
105
|
+
none of it counts as independent.
|
|
106
|
+
|
|
107
|
+
Which session id a verdict carries, per host:
|
|
108
|
+
|
|
109
|
+
- Claude Code: subagents inherit your `WORKIT_SESSION_ID`, so the
|
|
110
|
+
SubagentStart hook names each `verifier` and `reviewer` its own session
|
|
111
|
+
(`<lead>:<agent id>`) and a token only that subagent sees, passed exactly as
|
|
112
|
+
`--session` and `--token`: the hook records the ids it issues, and only
|
|
113
|
+
those, with their token, are accepted. An `implementer` is issued
|
|
114
|
+
none: it keeps your id in its env for its workit commands and commits.
|
|
115
|
+
- Codex: the `workit-verifier` and `workit-reviewer` agents get the same
|
|
116
|
+
issued `--session` and `--token` from SubagentStart; any other verifier passes
|
|
117
|
+
`--as verifier`.
|
|
118
|
+
- OpenCode: a child session's shell already has
|
|
119
|
+
`WORKIT_SESSION_ID=<lead>:<child>`; Pi: a supervised worker's shell has
|
|
120
|
+
`<lead>:<worker session>`. Set nothing for a verifier there.
|
|
121
|
+
- Cursor (no session id in the shell): the brief sets the verifier's
|
|
122
|
+
`WORKIT_SESSION_ID=<lead>:verifier-<random hex>`, a fresh suffix per
|
|
123
|
+
verifier. Cursor cannot check it: it is declared, not derived.
|
|
124
|
+
- A worker's commits: on Claude Code the lead's `WORKIT_SESSION_ID` already in
|
|
125
|
+
its env (SubagentStart issues no implementer id; no export, so the
|
|
126
|
+
lead authored those commits: a verifier or reviewer records the verdict, not
|
|
127
|
+
the lead); on OpenCode, Pi and Codex the id the host already
|
|
128
|
+
puts in its shell; on Cursor, CI and a plain terminal the brief's
|
|
129
|
+
`export WORKIT_SESSION_ID=<lead>-w-<slice>` (see `brief.md`, "Identity and
|
|
130
|
+
git rules per host"). A verdict under an id you made up (`<lead>-v1`,
|
|
131
|
+
`<lead>:v1`) is refused as `forged_session` on Claude Code, Codex,
|
|
132
|
+
OpenCode and Pi.
|
|
133
|
+
|
|
134
|
+
A batch verifier takes several slices on one surface in one session: for
|
|
135
|
+
each branch it checks out the head, runs that slice's VERIFY, and records its
|
|
136
|
+
own `workit ledger verdict <result> --branch <b> --how "<evidence>"`. Every
|
|
137
|
+
verdict is keyed to that branch's head SHA; a slice whose head moves after
|
|
138
|
+
it needs a new one. Batch at most what fits one context, about 4 slices.
|
|
139
|
+
|
|
140
|
+
## Review panel (high risk only)
|
|
141
|
+
|
|
142
|
+
At risk=high only, 2-3 fresh reviewers (read the `workit-review` skill's SKILL.md and follow it), each on a model
|
|
143
|
+
other than the author's (Claude Code: a different `model`), each records
|
|
144
|
+
`workit ledger verdict <result> --kind review --branch <b> --how "<findings>"`.
|
|
145
|
+
Land only when every panel verdict passes. Below high risk a panel costs
|
|
146
|
+
more than it finds.
|
|
147
|
+
|
|
148
|
+
## Integration-branch fan-in (one PR)
|
|
149
|
+
|
|
150
|
+
Only when the user wants one PR for the whole fanout:
|
|
151
|
+
|
|
152
|
+
1. Cut the integration branch (`workit git branch <integration> --base
|
|
153
|
+
<trunk>`) and plan with `"fanIn": "integration"` and `--trunk
|
|
154
|
+
<integration>`. Planning refuses integration mode on origin's default
|
|
155
|
+
branch.
|
|
156
|
+
2. Every brief then tells the worker to merge the integration tip into its
|
|
157
|
+
branch before reporting (the fast-forward rule). That merge is the only
|
|
158
|
+
one a worker makes, and only in this mode.
|
|
159
|
+
3. Land each verified slice with `git merge --ff-only <slice-branch>` in the
|
|
160
|
+
integration checkout. Not a fast-forward (the tip moved since the worker
|
|
161
|
+
merged)? Resume the worker to merge again; never a merge commit of your own.
|
|
162
|
+
4. `workit fanout check` gates against the integration branch; a slice whose
|
|
163
|
+
tip is on it reads as landed. When all have landed, ship the integration
|
|
164
|
+
branch as one PR (read the `workit-ship` skill's SKILL.md and follow it).
|
|
165
|
+
|
|
166
|
+
## Stacks
|
|
167
|
+
|
|
168
|
+
For stacked slices (`dependsOn` one parent): `workit stack plan <bottom> …
|
|
169
|
+
<top>` once, then `workit stack sync` and `workit stack land`.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workit-implement
|
|
3
|
+
description: Build a requested change in small verified steps - follow local patterns, run real checks with workit check, prove it on the running app, hand verification to a non-author. Use for implement, build, add a feature, make the change, code it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Implement and prove it works
|
|
7
|
+
|
|
8
|
+
## Steps
|
|
9
|
+
|
|
10
|
+
1. Read before writing: the files you will touch, their callers, and one
|
|
11
|
+
neighbour that already does something similar. Copy its patterns, names and
|
|
12
|
+
error handling. Repo rules (AGENTS.md, CLAUDE.md, lint config) win.
|
|
13
|
+
2. On the default branch? Branch first: `workit git branch --kind feature --slug <s>` (host note: a Claude Code host-isolated worktree uses plain `git switch -c`).
|
|
14
|
+
Tracking it? Judge once: `workit policy assess --judge risk=normal behavior=yes
|
|
15
|
+
product-choice=no plan=no` (trivial and no for a mechanical fix). Already
|
|
16
|
+
judged? Cite the plan with `--ref <path>` or record the decision; don't re-judge.
|
|
17
|
+
3. Small steps that each leave the tree green. Behavior change: write the
|
|
18
|
+
acceptance as Given/When/Then and see a test fail first (read the `workit-bdd` skill's SKILL.md and follow it).
|
|
19
|
+
Mechanical change: the existing checks are enough. No tautological tests:
|
|
20
|
+
a test must fail if the behavior breaks, never restate the implementation.
|
|
21
|
+
4. Run the real checks, local-first: the targeted test or check for the file
|
|
22
|
+
you touched while you work, then the full configured set once at the end
|
|
23
|
+
(`workit check test`, plus `lint` and `typecheck` when the repo has them),
|
|
24
|
+
not after every edit. Heavy work runs under one machine-wide lease: an ad-hoc
|
|
25
|
+
suite is `workit check --heavy -- <cmd>`, never a hand-made flock; a busy
|
|
26
|
+
lease waits and names its holder (`workit lock status`). A tool warning is a finding: fix it in this PR in the right layer, or record the false positive with evidence; pre-existing ones get their own PR.
|
|
27
|
+
5. Prove the feature on its real surface with the project's `verify-<app>`
|
|
28
|
+
skill; none yet? Write one (read the `workit-verify-app` skill's SKILL.md and follow it). Tests show branch behavior,
|
|
29
|
+
not that the feature works. The report carries what you observed: a UI
|
|
30
|
+
change a screenshot or console/network check (chrome devtools or
|
|
31
|
+
agent-browser), an API a quoted real response. App not runnable? Say so
|
|
32
|
+
plainly, never claim success.
|
|
33
|
+
6. Commit: `workit git commit -m "<type>: <what>" -- <paths>` (or `--all`); Co-Authored-By goes in with `--trailer "Co-Authored-By: <name> <email>"`. Host note: a Workit worktree (`workit fanout worktree create`) takes `workit git --cwd <worktree> …`; a Claude Code host-isolated one (`.claude/worktrees/agent-<id>`) takes plain git (its SubagentStart text: isolation refuses a git wrapper). One file holding two changes: stage one change's hunks with `workit git stage --patch <file>` (a `git diff -- <file>` cut to them), then `workit git commit -m "<msg>" --staged` (exactly the index); a path staged in part commits only its staged hunks (`--whole` takes the file).
|
|
34
|
+
No endpoint named? Stop here and state the next command. Hand delivery to
|
|
35
|
+
ship, which pushes and opens the PR with its body shape (read the `workit-ship` skill's SKILL.md and follow it), only
|
|
36
|
+
when that was requested, or the request implies delivery and the effective
|
|
37
|
+
endpoint in `workit grant show` is `pr`, `green` or `merged`; `green` and
|
|
38
|
+
`merged` keep babysitting. Otherwise it is `commit`.
|
|
39
|
+
7. Verify as far as the review lane asks (`workit policy assess`, `workit pr
|
|
40
|
+
status`). Lane none: no verdict. Lane self: after `workit check test` passes,
|
|
41
|
+
record `workit ledger verdict tests-verified --self --how "<what you ran>"`;
|
|
42
|
+
it reads self-reviewed, never verified, and is enough. Focused, full, high
|
|
43
|
+
risk or `verification: self|independent` merges: one fresh verifier per PR after the last push, its own host-derived session (Claude Code: the `verifier` agent with the `model` (and `effort`) of `workit models show --role verifier`; Codex:
|
|
44
|
+
the `verifier` agent; OpenCode: a child session; Pi: a supervised worker),
|
|
45
|
+
never a hand-minted id. Before saying done, reconcile
|
|
46
|
+
every named deliverable against the target checkout and observe it (for a push:
|
|
47
|
+
`workit verify-delivery push`).
|
|
48
|
+
|
|
49
|
+
Independent slices that could run in parallel: fan them out (read the `workit-fanout` skill's SKILL.md and follow it).
|
|
50
|
+
One `implementer` slice: `workit fanout worktree create <slice>` before spawning,
|
|
51
|
+
then `workit fanout brief <slice>`; no host isolation (Workit's hooks confine it).
|
|
52
|
+
|
|
53
|
+
Stay inline by default (workspace `delegation: inline-first`). Hand work off
|
|
54
|
+
only past the thresholds: an explorer after about 3 tool calls or 10k tokens
|
|
55
|
+
of searching, parallel writers for 2 or more disjoint units of about 100+
|
|
56
|
+
lines each.
|
|
57
|
+
|
|
58
|
+
## Example
|
|
59
|
+
|
|
60
|
+
Bad: "Done - added the --since flag, tests pass." (no check ran this turn; the
|
|
61
|
+
flag was never invoked)
|
|
62
|
+
|
|
63
|
+
Good: "Added `--since`. measured: `workit check test` exit 0;
|
|
64
|
+
`mytool log --since 2d` printed 3 entries against the fixture repo. inferred:
|
|
65
|
+
the GitLab path behaves the same (not run). Handed to the verifier agent."
|
|
66
|
+
|
|
67
|
+
## Check
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
workit check test # then, when the endpoint was a push or beyond: workit verify-delivery push
|
|
71
|
+
```
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workit-retro
|
|
3
|
+
description: Find repeated friction in recent sessions; propose cited fixes ranked by enforcer strength, never applied. Use for retro.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Retro: turn repeated friction into enforcers
|
|
8
|
+
|
|
9
|
+
User-invoked: offer it, never start it yourself. Run it after a session, PR,
|
|
10
|
+
stack or fan-in, including ones that went well; a smooth session still shows
|
|
11
|
+
where agents searched too long, worked around a tool or re-ran a check. Retro
|
|
12
|
+
proposes and stops. Nothing changes until the user approves.
|
|
13
|
+
|
|
14
|
+
1. **Scope.** Default: this repository's work since the last retro (its
|
|
15
|
+
`retro:` row in `workit ledger list --type decision`), else the last ~10
|
|
16
|
+
sessions. State the window in one line.
|
|
17
|
+
2. **Read through workit, cheapest first.** Every finding cites these:
|
|
18
|
+
- `workit ledger list --last 200`: rulings, failed/self verdicts, handoffs,
|
|
19
|
+
check runs, CI reruns, `skill.loaded` rows (skipped skills: routing).
|
|
20
|
+
- `workit pr status --pr <n>` for each recent PR: threads, failing checks.
|
|
21
|
+
- `git log --oneline -50`, plus reverts and fixups after review.
|
|
22
|
+
- `workit knowledge lint`: today's AGENTS.md and need-based files.
|
|
23
|
+
- Session transcripts **only if the user opts in**, and only this
|
|
24
|
+
workspace's (`references/sources.md`). Never read other projects.
|
|
25
|
+
|
|
26
|
+
Cite by location (ledger row, PR, commit, session file and line). Never
|
|
27
|
+
copy secrets, tokens or personal data from any source into the report.
|
|
28
|
+
3. **Group into classes.** Navigation cost (many searches before the right
|
|
29
|
+
file, a stale doc followed), repeated mistakes, workarounds (a hand-run
|
|
30
|
+
command where a verb exists, a skipped step), unstable checks (the same
|
|
31
|
+
`workit check <name>` red then green with no change). A class needs **2 or
|
|
32
|
+
more cited occurrences**; a one-off is not a learning.
|
|
33
|
+
4. **Name the strongest enforcer that works**, strongest first: architecture
|
|
34
|
+
or types (the mistake cannot be written) > lint rule > configured check
|
|
35
|
+
(`.workit/checks.json`, `workit check <name>`) or CI job > test >
|
|
36
|
+
`CODING_STANDARDS.md` (judgment the reviewer reads) > AGENTS.md pointer
|
|
37
|
+
(navigation only). A mechanical rule gets a check, not prose: a check can
|
|
38
|
+
fail, a sentence cannot. From types to test, the proof is that the new
|
|
39
|
+
enforcer fails on the cited past mistake. A rule whose mistake can no
|
|
40
|
+
longer happen is deleted.
|
|
41
|
+
5. **Upstream.** Friction a workit skill, verb or hook caused, or a rule for
|
|
42
|
+
agent behaviour, becomes an issue or PR on BrainerVirus/workit, not a host
|
|
43
|
+
memory (one host reads it). Never fork a local copy. Use a minimal synthetic
|
|
44
|
+
repro: no private repo name, path, code, ledger text, PR, thread or transcript.
|
|
45
|
+
Show the exact draft; once approved: `workit issue create --repo BrainerVirus/workit`.
|
|
46
|
+
6. **Bloat guards.** AGENTS.md stays within 8 KB: each addition names what it
|
|
47
|
+
removes. Create `CODING_STANDARDS.md` or `GLOSSARY.md` only in the same
|
|
48
|
+
edit as its first real entry, never as a scaffold. Edit steering text by
|
|
49
|
+
`references/steering.md`; `workit knowledge lint` passes after the slice.
|
|
50
|
+
7. **Report one ranked list, then stop** (save it under `workit dir retros`):
|
|
51
|
+
Accepted (proposed), Backlog, Dropped, each with its citations, enforcer
|
|
52
|
+
and reason. Each approved item becomes a slice to build (read the `workit-implement` skill's SKILL.md and follow it)
|
|
53
|
+
and ship (read the `workit-ship` skill's SKILL.md and follow it), a tracker issue, or `.out-of-scope/<concept>.md` when
|
|
54
|
+
rejected and likely to return. Record the user's answer so the next retro
|
|
55
|
+
starts there: `workit ledger decision "retro: <accepted ids>" --why "<window>"`.
|
|
56
|
+
|
|
57
|
+
## Example
|
|
58
|
+
|
|
59
|
+
Bad: "Agents seem lost in the build. Added 'read the build docs carefully' to
|
|
60
|
+
AGENTS.md." One vague occurrence, no citation, a no-op line, auto-applied.
|
|
61
|
+
|
|
62
|
+
Good: "Navigation, 3 occurrences (rulings 12, 19; PR #88 thread): agents sought
|
|
63
|
+
check names in package.json, missing `.workit/checks.json`. Enforcer: AGENTS.md
|
|
64
|
+
pointer, +74 bytes, minus the stale Commands paragraph (-210). Unstable check,
|
|
65
|
+
2 occurrences (ledger rows 31, 44: `e2e` red then green on one SHA): a debug
|
|
66
|
+
slice to fix the check. Approve?"
|
|
67
|
+
|
|
68
|
+
## Check
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
workit knowledge lint # exit 0 before and after each approved slice
|
|
72
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Session transcripts (opt-in, this workspace only)
|
|
2
|
+
|
|
3
|
+
Transcripts are the most expensive source and can hold private material. Read
|
|
4
|
+
them only after the user says yes to a question such as "Also read the last 10
|
|
5
|
+
session transcripts for this workspace? (local files, read-only)". The default
|
|
6
|
+
is no: the ledger, `pr status` and git are enough for most retros.
|
|
7
|
+
|
|
8
|
+
## Where they live
|
|
9
|
+
|
|
10
|
+
Typical locations; confirm each exists. Resolve the path from this workspace's
|
|
11
|
+
absolute path, never with a wildcard across projects. If a host's layout
|
|
12
|
+
differs from the one below, say so and skip it rather than search wider.
|
|
13
|
+
|
|
14
|
+
| Host | Location |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| Claude Code | `~/.claude/projects/<folder>/*.jsonl`, one folder per path from `git worktree list`: the absolute path with every `/` and `.` replaced by `-`. Compute each folder name; never glob for it |
|
|
17
|
+
| Codex | `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`. To filter, parse only line 1 (`session_meta`) and read only its `cwd` field; skip files whose `cwd` is not this workspace without reading or reporting anything else from them |
|
|
18
|
+
| Cursor | `~/.cursor/projects/<workspace slug>/agent-transcripts/` |
|
|
19
|
+
| Pi | `~/.pi/agent/sessions/--<workspace path, / replaced by ->--/*.jsonl` |
|
|
20
|
+
| OpenCode | this project's sessions from `opencode session list`, read with `opencode export <id>` |
|
|
21
|
+
|
|
22
|
+
Linked worktrees of the same repository count as this workspace; other
|
|
23
|
+
repositories never do.
|
|
24
|
+
|
|
25
|
+
## How to read them
|
|
26
|
+
|
|
27
|
+
- Newest first, at most the agreed number of sessions.
|
|
28
|
+
- On a host with subagents, one read-only analyst per lens, each returning
|
|
29
|
+
only cited occurrences (session file plus line or message index):
|
|
30
|
+
- navigation: searches and reads before the right file was found, stale docs
|
|
31
|
+
followed;
|
|
32
|
+
- tool economy: hand-run commands where a `workit` verb exists, repeated
|
|
33
|
+
reads of the same file, long outputs nobody used;
|
|
34
|
+
- repeated work: the same fix or check redone, a step undone later;
|
|
35
|
+
- request conflicts: instructions the agent had to reconcile or ask about.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Editing steering text (AGENTS.md, CODING_STANDARDS.md, skills)
|
|
2
|
+
|
|
3
|
+
Steering text is paid for on every session that reads it. Each line must
|
|
4
|
+
change what an agent does; everything else is cost.
|
|
5
|
+
|
|
6
|
+
## Write
|
|
7
|
+
|
|
8
|
+
- **Point, do not copy.** Link the file or name the command; never paste its
|
|
9
|
+
content. A pointer says when to follow it: "Read before editing a hook:
|
|
10
|
+
`docs/agents/hosts.md`".
|
|
11
|
+
- **Say what done looks like.** "Run `bun run check`; it must exit 0" beats
|
|
12
|
+
"make sure everything works".
|
|
13
|
+
- **Concrete over adjectives.** A command, a path, a number. Prefer the action
|
|
14
|
+
to take over a list of things to avoid.
|
|
15
|
+
- **One rule, one home.** A rule with an enforcer (type, lint, check, test)
|
|
16
|
+
appears in steering text at most as a pointer to that enforcer. The same
|
|
17
|
+
sentence in AGENTS.md and CODING_STANDARDS.md is a defect
|
|
18
|
+
(`duplicate-rule`).
|
|
19
|
+
- **Judgment goes to CODING_STANDARDS.md**, which the reviewer reads; only
|
|
20
|
+
navigation goes to AGENTS.md.
|
|
21
|
+
|
|
22
|
+
## Cut
|
|
23
|
+
|
|
24
|
+
- **No-ops.** Delete lines that would not change any behavior if removed:
|
|
25
|
+
"be thorough", "write clean code", "keep it concise", "follow best
|
|
26
|
+
practices".
|
|
27
|
+
- **Session residue.** No notes about one session, no implementation detail
|
|
28
|
+
the code already shows, no `path:line` references (they go stale).
|
|
29
|
+
- **Dead rules.** A rule whose mistake can no longer happen (a type or check
|
|
30
|
+
now prevents it) is deleted, not kept "for context".
|
|
31
|
+
|
|
32
|
+
## Budget
|
|
33
|
+
|
|
34
|
+
- AGENTS.md stays within 8 KB (`workit knowledge lint`, rule
|
|
35
|
+
`agents-budget`). A proposal that adds text names what it removes, or shows
|
|
36
|
+
the byte count still holds.
|
|
37
|
+
- A need-based file (`CODING_STANDARDS.md`, `GLOSSARY.md`) is created in the
|
|
38
|
+
same edit as its first real entry. Headers-only or "TBD" files fail the lint
|
|
39
|
+
(`scaffold-file`).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workit-review
|
|
3
|
+
description: Independent review of a diff, branch or PR - intent fidelity and standards as separate axes, test quality, blast radius - recorded as a non-author verdict. Use for review, code review, check this PR or MR, is this safe, blast radius.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review independently
|
|
7
|
+
|
|
8
|
+
Review the candidate, never the author's summary of it. A session that wrote a
|
|
9
|
+
commit on the branch cannot record a passing verdict: if that is you, hand the
|
|
10
|
+
review to a fresh agent with its own host-derived session: Claude Code and
|
|
11
|
+
Codex, the `reviewer` or `verifier` agent (`--session` and `--token` from SubagentStart);
|
|
12
|
+
OpenCode, a child session; Pi, a supervised worker. On Claude Code pass the
|
|
13
|
+
`model` and `effort` of `workit models show --role <verifier|reviewer>`. Never hand-mint one such
|
|
14
|
+
as `<lead>-v1`: it is refused as `forged_session`.
|
|
15
|
+
An author's `--self` verdict reads self-reviewed and never counts as
|
|
16
|
+
independent; `type-check-only` never proves a behavior change.
|
|
17
|
+
Depth follows the review lane in `workit pr status`: focused reads the diff and
|
|
18
|
+
runs its tests; full also drives the real surface (verify-<app>). Review once
|
|
19
|
+
per PR after its last push; a second pass on an unchanged head is waste.
|
|
20
|
+
A stale verdict showing `reverify: focused (<files>)` in `workit pr status`: re-check only
|
|
21
|
+
those files since the judged head and reuse green CI there (no fresh install, no full suite).
|
|
22
|
+
|
|
23
|
+
1. Pin the candidate: `git rev-parse HEAD`, the base, `git diff <base>...HEAD`;
|
|
24
|
+
for a PR, `workit pr status --json` (checks, unresolved threads).
|
|
25
|
+
2. Find the intent: acceptance criteria, spec, PR body, and the recorded
|
|
26
|
+
choices (`workit ledger list --type decision`).
|
|
27
|
+
3. Judge two axes separately, never merged or re-ranked:
|
|
28
|
+
- **Spec:** does the diff do what the acceptance says? Missing, creep or
|
|
29
|
+
wrong; quote the line.
|
|
30
|
+
- **Standards:** repo rules first (`CODING_STANDARDS.md` when present),
|
|
31
|
+
then a smell baseline (unclear name, long function, duplicated logic,
|
|
32
|
+
leaky abstraction). Judgment only; lint owns nits.
|
|
33
|
+
4. **Tests:** run suites under the heavy-check lease (`workit check test`,
|
|
34
|
+
`workit check --heavy -- <cmd>`); `workit test-audit --diff`. Would each new test fail if the
|
|
35
|
+
behavior broke? Triage the findings (read the `workit-test-audit` skill's SKILL.md and follow it). Every configured check (`packaging`
|
|
36
|
+
too) needs a run or green CI on the head, or `verified` is refused: see `pr status`.
|
|
37
|
+
5. **Blast radius:** for each touched contract, caller, config or migration,
|
|
38
|
+
state the one fact it is safe because of and run the proof. Anything
|
|
39
|
+
unproven is labeled UNPROVEN, never assumed safe: `references/impact.md`.
|
|
40
|
+
6. Each finding: file:line, severity (blocker, major, minor, nit), evidence
|
|
41
|
+
(hunk, test or command output), concrete fix. Introduced issues get fixed;
|
|
42
|
+
pre-existing ones become follow-ups; inconclusive ones escalate.
|
|
43
|
+
7. Record the verdict:
|
|
44
|
+
`workit ledger verdict verified|failed|blocked --kind review --branch <b> --how "<what you ran and read>"`
|
|
45
|
+
under your own session (the one the lead or the hook gave you).
|
|
46
|
+
8. **Bound the loop.** A failed verdict gets one fix round and one recheck of
|
|
47
|
+
the changed hunks. Still failing, or stuck: no third round; the lead spawns
|
|
48
|
+
a decider (read the `workit-fanout` skill's SKILL.md and follow it). A product choice goes to the user.
|
|
49
|
+
9. **Harness note** (optional): friction caused by the repo or harness, not
|
|
50
|
+
the change (a flaky fixture, a missing check, a misleading doc or skill
|
|
51
|
+
line), goes on its own `Harness note:` line in the report and any PR
|
|
52
|
+
comment, never as a finding or in the verdict, so a later retro finds it.
|
|
53
|
+
|
|
54
|
+
## Example
|
|
55
|
+
|
|
56
|
+
Bad: "Error handling could be improved." (no place, no consequence, no proof)
|
|
57
|
+
|
|
58
|
+
Good: "blocker - src/pay.ts:88: `catch {}` swallows the gateway's 402, so the
|
|
59
|
+
order is marked paid. Repro: `workit check -- bun test pay.test.ts -t declined`
|
|
60
|
+
fails with this diff. Fix: rethrow `PaymentDeclined`."
|
|
61
|
+
|
|
62
|
+
## Check
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
workit ledger check --pr <n> # accepted only when current, passing and independent
|
|
66
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Blast radius beyond the diff
|
|
2
|
+
|
|
3
|
+
A small diff is not a small risk. For every surface the change touches, name
|
|
4
|
+
the one fact it is safe because of and run the proof.
|
|
5
|
+
|
|
6
|
+
1. List what the change touches: exported symbols and every caller
|
|
7
|
+
(`git grep -nw <symbol>`), shared state, wire or file formats, config keys,
|
|
8
|
+
migrations, CLI flags and outputs, public types.
|
|
9
|
+
2. For each: the fact it is safe because of (a type boundary, an existing test
|
|
10
|
+
that covers the path, an unreachable branch, a version gate) and the command
|
|
11
|
+
that proves it.
|
|
12
|
+
3. Run the proofs with `workit check -- <cmd>` so the result is observed.
|
|
13
|
+
4. Anything you could not prove is a finding labeled UNPROVEN with what would
|
|
14
|
+
prove it. Never fold it into "looks safe".
|
|
15
|
+
5. A fix belongs at the shared root (one guard that every caller passes
|
|
16
|
+
through), not copied per caller.
|
|
17
|
+
|
|
18
|
+
Example note:
|
|
19
|
+
|
|
20
|
+
| Surface | Safe because | Proof |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `parseRange()` (4 callers) | callers pass validated input; new branch only for `--since` | `workit check -- bun test range.test.ts` exit 0 |
|
|
23
|
+
| `config.json` `since` key | additive, old readers ignore unknown keys | `workit check -- bun test config-compat.test.ts` exit 0 |
|
|
24
|
+
| GitLab adapter | UNPROVEN - no fixture for relative dates | add a `gitlab/relative-since.json` fixture |
|