@pmelab/gtd 52.1.0 → 54.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.
Files changed (94) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +91 -129
  3. package/claude/hooks/drive.ts +0 -3
  4. package/claude/hooks/register.tsx +3 -68
  5. package/claude/hooks/ship.ts +85 -1595
  6. package/dist/chunks/{reserved-DxB5CROj.mjs → reserved-CQ7amcKG.mjs} +45 -132
  7. package/dist/chunks/{review-CKMSdvgW.mjs → review-CXzUXJHL.mjs} +12 -5
  8. package/dist/chunks/{tail-QZc7Uz2U.mjs → tail-JZ9PAOwp.mjs} +2 -14
  9. package/dist/chunks/{wire-BJuZWR3C.mjs → wire-C12dahrH.mjs} +2 -130
  10. package/dist/flows.mjs +1 -16
  11. package/dist/gtd.bundle.mjs +476 -982
  12. package/dist/testkit.mjs +58 -417
  13. package/dist/wire.mjs +2 -2
  14. package/dist/workflows/cleanup.mjs +2 -2
  15. package/dist/workflows/feature.mjs +112 -363
  16. package/dist/workflows/fix.mjs +2 -2
  17. package/dist/workflows/review.mjs +3 -3
  18. package/dist/workflows/rollout.mjs +1 -1
  19. package/dist/workflows.mjs +321 -677
  20. package/package.json +1 -1
  21. package/src/cli/Cli.test.ts +1 -86
  22. package/src/cli/Cli.ts +13 -133
  23. package/src/cli/Metrics.test.ts +21 -31
  24. package/src/cli/Metrics.ts +25 -36
  25. package/src/cli/Program.test.ts +1 -35
  26. package/src/cli/Program.ts +5 -64
  27. package/src/cli/ToolCommands.ts +0 -3
  28. package/src/edge/Edge.test.ts +20 -322
  29. package/src/edge/Edge.ts +10 -181
  30. package/src/edge/index.ts +0 -1
  31. package/src/flows/runtime.test.ts +0 -27
  32. package/src/flows/runtime.ts +1 -49
  33. package/src/install/Install.ts +15 -24
  34. package/src/replay/Replay.test.ts +0 -169
  35. package/src/replay/Replay.ts +4 -93
  36. package/src/replay/index.ts +0 -1
  37. package/src/testkit/Layers.ts +0 -1
  38. package/src/testkit/steps.ts +23 -0
  39. package/src/wire/BeatDocument.ts +2 -12
  40. package/src/wire/BeatStatus.ts +0 -3
  41. package/src/wire/WireSchema.test.ts +0 -18
  42. package/src/wire/index.ts +0 -2
  43. package/src/wire/types.ts +0 -7
  44. package/src/workflow/Workflow.ts +1 -9
  45. package/src/workflows/feature/criteria.test.ts +1 -14
  46. package/src/workflows/feature/criteria.ts +6 -38
  47. package/src/workflows/feature/feature.ts +34 -118
  48. package/src/workflows/feature/hands-on-skip.feature +2 -70
  49. package/src/workflows/feature/index.ts +0 -1
  50. package/src/workflows/feature/lens-review.feature +50 -0
  51. package/src/workflows/feature/one-step-land.feature +0 -4
  52. package/src/workflows/feature/prototype-rounds.feature +1 -1
  53. package/src/workflows/feature/prototype.feature +3 -3
  54. package/src/workflows/feature/prototype.ts +18 -29
  55. package/src/workflows/feature/refactor-absorbs.feature +3 -8
  56. package/src/workflows/feature/refactor-first.feature +0 -5
  57. package/src/workflows/feature/refactor-rebuild.feature +0 -6
  58. package/src/workflows/feature/refactor-review.feature +49 -11
  59. package/src/workflows/feature/refactor.ts +30 -64
  60. package/src/workflows/feature/review-gate.feature +1 -1
  61. package/src/workflows/feature/reviewer-walkthrough.feature +0 -31
  62. package/src/workflows/feature/seam-rejection.feature +0 -4
  63. package/src/workflows/feature/seam.test.ts +7 -26
  64. package/src/workflows/feature/seam.ts +52 -165
  65. package/src/workflows/index.ts +0 -1
  66. package/src/workflows/shared/lenses.ts +0 -13
  67. package/src/workflows/shared/options.test.ts +2 -11
  68. package/src/workflows/shared/options.ts +4 -21
  69. package/src/workflows/shared/review.test.ts +3 -3
  70. package/src/workflows/shared/review.ts +12 -2
  71. package/src/workflows/shared/steps.ts +0 -2
  72. package/src/workflows/shared/text.test.ts +10 -80
  73. package/src/workflows/shared/text.ts +35 -211
  74. package/src/workflows/shared/vars.ts +2 -8
  75. package/src/workflows/shared/workflows.steps.ts +0 -13
  76. package/claude/hooks/context.ts +0 -66
  77. package/src/replay/Slices.test.ts +0 -73
  78. package/src/replay/Slices.ts +0 -45
  79. package/src/wire/ContextLimit.fixture.ts +0 -30
  80. package/src/wire/ContextLimit.test.ts +0 -96
  81. package/src/wire/ContextLimit.ts +0 -169
  82. package/src/wire/Slices.ts +0 -25
  83. package/src/wire/golden/1/slices.json +0 -11
  84. package/src/workflows/feature/context-limit.feature +0 -37
  85. package/src/workflows/feature/continuation-cap.feature +0 -69
  86. package/src/workflows/feature/continuation-rebuild.feature +0 -92
  87. package/src/workflows/feature/continuation-slices.feature +0 -68
  88. package/src/workflows/feature/continuation.feature +0 -209
  89. package/src/workflows/feature/slice-findings.feature +0 -256
  90. package/src/workflows/feature/slicing-cap.feature +0 -23
  91. package/src/workflows/feature/slicing.feature +0 -297
  92. package/src/workflows/feature/slicing.test.ts +0 -49
  93. package/src/workflows/feature/slicing.ts +0 -105
  94. package/src/workflows/shared/continuation.ts +0 -92
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtd",
3
- "version": "52.1.0",
3
+ "version": "54.0.0",
4
4
  "description": "Drive the gtd loop inside Claude Code: agent turns run as subagents, gtd decides every beat",
5
5
  "author": {
6
6
  "name": "Philipp Melab"
package/README.md CHANGED
@@ -310,18 +310,10 @@ cost on its landing, answers judge gates through `gtd judge run`, and maps the
310
310
  workflow's `smart`/`base` model hints to real model names through
311
311
  `GTD_LOOP_MODEL_SMART`/`GTD_LOOP_MODEL_BASE`.
312
312
 
313
- Both it and the Claude Code mod stop an agent turn that outgrows its context:
314
- past 60% of the model's window the agent is asked to wrap up with a handoff
315
- note, past 70% after a tool call (or when the context is about to be compacted)
316
- the turn stops and nothing lands. A step's `context` option, or the bundled
317
- workflows' `contextLimit` option, moves the two limits — see
318
- [Context limits](https://github.com/pmelab/gtd/blob/main/docs/driver.md#context-limits).
319
- In `feature`, a naive pass, refactor or build turn that wrapped up that way is a
320
- snapshot: a fresh turn picks up from it with the handoff note and the criteria
321
- still open, up to 3 times per phase, across its retries (`continuations`), and a
322
- phase whose continuations keep stopping, or close nothing twice in a row
323
- (`continuationStall`), rests for a person — see
324
- [Continuations](https://github.com/pmelab/gtd/blob/main/docs/configuration.md#continuations).
313
+ Neither guards an agent turn's context: a long turn relies on the agent
314
+ harness's own compaction, and a pass that falls short is caught by its
315
+ acceptance tests and retried. Size the work before the sketch — a change too big
316
+ for one process is several processes.
325
317
 
326
318
  ### Or drive it from inside Claude Code
327
319
 
@@ -354,34 +346,23 @@ plan or the diff, records what you decide in the steering file the way the step
354
346
  asks, and moves the process on only when you say so; a review you leave
355
347
  untouched signs off. While a step runs you can keep asking; requests for changes
356
348
  wait for the next rest. When the process finishes, Claude offers to squash it
357
- and open its pull request(s) (or run `/gtd ship`; `GTD_SHIP_MODE` picks one
358
- commit per slice under one pull request (the default) or, set to `stack`, one
359
- stacked pull request per slice, see the [driver doc](docs/driver.md)); a process
360
- started for an issue ships with `Closes #N` on its top pull request; a closed
361
- pull request whose branch was deleted from origin is left behind and a new one
362
- opens; on a branch an earlier ship in this clone stacked (unless
363
- `GTD_SHIP_MODE=commits`), a later process, such as review fixes, lands one
364
- commit per slice on the top pull request and keeps the stack, and re-running
365
- `/gtd ship` after a lower stacked pull request merged restacks the rest (it
366
- refuses, with nothing changed, when that pull request merged anywhere but the
367
- default branch (unless into a lower slice branch before that one merged into
368
- it), a slice branch is checked out in another worktree, an unrelated local
369
- branch sits inside the rebased commits, or a slice's change is already upstream;
370
- a failed rebase is rolled back; to tear a stack down from its worktree, delete
371
- the top branch with `git push origin --delete`, since
372
- `gh pr close --delete-branch` cannot). A process can change hands at any gate:
373
- ask Claude to hand it off (or run `/gtd throw @dev`) and it opens a draft pull
374
- request assigned to them, and `/gtd catch <pr>` picks it up exactly where it
375
- waits, so whoever wrote the requirements can hand the build to someone else.
376
- `/gtd pr` brings a pull request's unresolved review threads into the review:
377
- each becomes a note in `.gtd/REVIEW.md` ticked "fix as suggested" (untick it for
378
- "won't fix" plus a reason, or your own answer), the review door fixes them in
379
- place, and each thread then gets a reply naming the fixing commit (or your
380
- reason) and is resolved. Ship, hand-off and throw answer at once and run in the
381
- background, with progress on the status line; they report by waking Claude, a
382
- toast, a transcript line and a push notification, and a failed push or `gh` call
383
- reports as a failure. While a ship or hand-off runs or is queued, `/gtd catch`,
384
- the doors, `/gtd <requirements>` and bare `/gtd` wait for its report. See
349
+ and open its pull request (or run `/gtd ship`: one commit under one pull
350
+ request, see the [driver doc](docs/driver.md)); a process started for an issue
351
+ ships with `Closes #N` on its pull request; a closed pull request whose branch
352
+ was deleted from origin is left behind and a new one opens. A process can change
353
+ hands at any gate: ask Claude to hand it off (or run `/gtd throw @dev`) and it
354
+ opens a draft pull request assigned to them, and `/gtd catch <pr>` picks it up
355
+ exactly where it waits, so whoever wrote the requirements can hand the build to
356
+ someone else. `/gtd pr` brings a pull request's unresolved review threads into
357
+ the review: each becomes a note in `.gtd/REVIEW.md` ticked "fix as suggested"
358
+ (untick it for "won't fix" plus a reason, or your own answer), the review door
359
+ fixes them in place, and each thread then gets a reply naming the fixing commit
360
+ (or your reason) and is resolved. Ship, hand-off and throw answer at once and
361
+ run in the background, with progress on the status line; they report by waking
362
+ Claude, a toast, a transcript line and a push notification, and a failed push or
363
+ `gh` call reports as a failure. While a ship or hand-off runs or is queued,
364
+ `/gtd catch`, the doors, `/gtd <requirements>` and bare `/gtd` wait for its
365
+ report. See
385
366
  [Inside Claude Code](https://github.com/pmelab/gtd/blob/main/docs/driver.md#inside-claude-code-the-gtd-mod).
386
367
 
387
368
  ### Then let an agent build your own
@@ -509,12 +490,8 @@ noted in steps 3 and 4 below.
509
490
  unsure verdict (below `qualityTriageMinP`, `0.7`) is `design`; mechanical
510
491
  findings the fix turns leave become notes too. This lap is where code quality
511
492
  is looked at, and every round pays for it. It never replaces step 4 — your
512
- review stays the final gate, and nothing here skips it. Every
513
- [coarse slice](docs/configuration.md#coarse-slices) runs the same triaged lap
514
- and never rests for its findings: its notes are carried to the review after
515
- the last slice, each naming its slice and lens, beside every slice's fixes.
516
- The `fix` and `cleanup` doors triage their lap too, and hand its notes to
517
- their own review.
493
+ review stays the final gate, and nothing here skips it. The `fix` and
494
+ `cleanup` doors triage their lap too, and hand its notes to their own review.
518
495
 
519
496
  A red suite that keeps failing past a few fix attempts escalates instead of
520
497
  retrying forever: an agent turn reads the failing output and writes
@@ -529,49 +506,49 @@ noted in steps 3 and 4 below.
529
506
  `Gtd-Mark: flaky=<check>` (see
530
507
  [Re-check before a person](docs/configuration.md#re-check-before-a-person)).
531
508
 
532
- 4. **You review.** After the last slice's quality lap a reviewer turn
509
+ 4. **You review.** After the quality lap a reviewer turn
533
510
  (`build.review.reviewing`) walks you through the whole change: `## ` chunks
534
511
  grouped by concern, **every chunk pointing at its code**
535
512
  (`./path#start-end`), so the phone shows the diff beside each one. Every
536
- design note the slices' laps left gets a chunk of its own, pointing at the
537
- code it cites; gtd adds the note's text and three tick boxes — **fix as
538
- suggested**, **won't fix**, or **your own answer** written over
539
- `_your answer_` (`build.review.carrying`) — then, for reference, no tick
540
- boxes, no answer needed — what was **fixed automatically** (with the fixing
541
- commit) and what was **dropped as noise**. A review with a chunk pointing at
542
- no code, or a note left out, is refused (`review-pointers`). A pointer note
543
- the reviewer opens with `Risk:` is fixed before you see the review
513
+ design note the lap left gets a chunk of its own, pointing at the code it
514
+ cites; gtd adds the note's text and three tick boxes — **fix as suggested**,
515
+ **won't fix**, or **your own answer** written over `_your answer_`
516
+ (`build.review.carrying`) — then, for reference, no tick boxes, no answer
517
+ needed — what was **fixed automatically** (with the fixing commit) and what
518
+ was **dropped as noise**. A review with a chunk pointing at no code, or a
519
+ note left out, is refused (`review-pointers`). A pointer note the reviewer
520
+ opens with `Risk:` is fixed before you see the review
544
521
  (`build.review.fix.risks.fixing`), then the review is written again. **What
545
522
  matters most comes first:** a judge (`build.review.ranking`) rates every
546
523
  chunk on the four severity questions below, and the review lists `critical`
547
524
  chunks first (security, then one-way doors), then `should`, then `could`,
548
525
  each led by its tier and reason (`_critical: security, one-way door_`) — the
549
526
  phone shows it on the chunk's card. A chunk the judge is unsure of, or whose
550
- evidence the budget cut, is `critical`. On `refactor-first` the refactor
551
- slice gets a walkthrough of its own first, covering the whole refactor on
552
- every round, before the feature is built; see
553
- [the naive pass](#the-naive-pass). **Every note needs exactly one tick before
554
- `gtd land` accepts the review** (`answer-completeness`; an open `- H:` thread
555
- waiting on the agent is the one exception). Fix as suggested joins the nit
556
- batch below, unjudged; won't fix drops the note and records it as
557
- `Gtd-Mark: wontfix=<title>` on the gate's commit; your own answer is judged
558
- like a note. A note you answered is left out of the fresh review after a nit
559
- fix. Land with every note answered and nothing else changed to approve, or
560
- write what is wrong — disagreeing with a fix or a drop means writing a note
561
- of your own. Approving ends the process (at the refactor review, it moves on
562
- to the feature); feedback is judged note by note, each as `edit`, `question`,
563
- `nit` or `praise`. An `edit` sends the process back to step 2 for re-derived
564
- requirements — the built criteria keep their IDs (reworded in place when
565
- their behaviour changes) and new behaviour gets new ones — then the
566
- implementation is amended to meet them, with no new naive pass or seam judge,
567
- the hands-on test runs again, the quality lap runs, and you review again. At
568
- the refactor review an `edit` re-derives the refactor instead. A `question`
569
- is answered inline under your note and the process stops at the review again
570
- — no new plan. A `nit` is fixed in one batch, the suite must go green (a red
571
- one gets fix turns first), then a fresh review of the change stops at the
572
- review again. `praise` is dropped; a round of only praise signs off. When a
573
- round mixes them, questions are answered and nits fixed first, then the edits
574
- are planned — risk: the planning lap may redo nit fixes it touches.
527
+ evidence the budget cut, is `critical`. On `refactor-first` the refactor gets
528
+ a walkthrough of its own first, covering the whole refactor on every round,
529
+ before the feature is built; see [the naive pass](#the-naive-pass). **Every
530
+ note needs exactly one tick before `gtd land` accepts the review**
531
+ (`answer-completeness`; an open `- H:` thread waiting on the agent is the one
532
+ exception). Fix as suggested joins the nit batch below, unjudged; won't fix
533
+ drops the note and records it as `Gtd-Mark: wontfix=<title>` on the gate's
534
+ commit; your own answer is judged like a note. A note you answered is left
535
+ out of the fresh review after a nit fix. Land with every note answered and
536
+ nothing else changed to approve, or write what is wrong — disagreeing with a
537
+ fix or a drop means writing a note of your own. Approving ends the process
538
+ (at the refactor review, it moves on to the feature); feedback is judged note
539
+ by note, each as `edit`, `question`, `nit` or `praise`. An `edit` sends the
540
+ process back to step 2 for re-derived requirements — the built criteria keep
541
+ their IDs (reworded in place when their behaviour changes) and new behaviour
542
+ gets new ones — then the implementation is amended to meet them, with no new
543
+ naive pass or seam judge, the hands-on test runs again, the quality lap runs,
544
+ and you review again. At the refactor review an `edit` re-derives the
545
+ refactor instead. A `question` is answered inline under your note and the
546
+ process stops at the review again — no new plan. A `nit` is fixed in one
547
+ batch, the suite must go green (a red one gets fix turns first), then a fresh
548
+ review of the change stops at the review again. `praise` is dropped; a round
549
+ of only praise signs off. When a round mixes them, questions are answered and
550
+ nits fixed first, then the edits are planned — risk: the planning lap may
551
+ redo nit fixes it touches.
575
552
 
576
553
  Each `edit` note also gets a severity tier from four judge questions
577
554
  (security, reversibility, blast radius, new concept). Every tier is
@@ -684,45 +661,38 @@ Incidental changes land: the pass itself is the implementation, with no rebuild,
684
661
  straight through the health loop and the quality lap. A needed seam change
685
662
  resets: the pass is never applied. An agent reads its whole diff and writes a
686
663
  refactor note (`.gtd/REFACTOR-NOTE.md`: which seams, which shape); the seam is
687
- refactored first, flag-free with the existing suite green, in its own slice with
688
- its own quality lap (`refactorQualityReviews`) and review; then the feature is
664
+ refactored first, flag-free with the existing suite green, on its own with its
665
+ own quality lap (`refactorQualityReviews`) and review; then the feature is
689
666
  rebuilt on the refactored base, behind a release flag, with the note and the
690
667
  naive diff as reference. The rebuild is refused until its tests carry every
691
668
  criterion ID the naive pass's tests named, and the suite must be green with
692
669
  them. A wrong approach is retried twice, then rests for you to steer or overrule
693
- it. `gtd slices` lists the `refactor` and `feature` slices. A refactor that
694
- already carried the whole feature leaves the rebuild only the carried-over
695
- tests, and the feature's quality lap and review cover the whole change. Once the
696
- implementation is green, a judge asks, per acceptance criterion, whether a
697
- person can observe it by using the software; an agent then uses the slice by
698
- hand for those — the real program in a scratch directory, the real page, guided
699
- by a project skill or a manual testing section in `AGENTS.md`, `CLAUDE.md` or
700
- `README.md` — and writes `.gtd/PROTOTYPE.md`: per criterion pass, fail or
701
- blocked, with the steps run and what it saw. A criterion the judge finds no one
702
- can observe (a refactor, something left unchanged, internal shape), or one
703
- design tagged `(no hands-on)`, is skipped; a slice with none left skips this
704
- step. This is the one check that a criterion is met: with `prototypeRounds` set
705
- to `0` nothing checks the criteria beyond the green suite. Failures are fixed
706
- and re-tested before the quality lap, up to `prototypeRounds` (3) fix rounds;
707
- past them, with only blocked items, or with no way to test found, it rests for
708
- you. See [The hands-on test](docs/configuration.md#the-hands-on-test). Feedback
709
- at the feature review re-runs design and the implementation, never the naive
710
- pass; feedback at the refactor review re-runs the refactor, never design; a
711
- refactor-review change the refactor cannot build is refused, and the only way
670
+ it. A refactor that already carried the whole feature leaves the rebuild only
671
+ the carried-over tests, and the feature's quality lap and review cover the whole
672
+ change. Once the implementation is green, a judge asks, per acceptance
673
+ criterion, whether a person can observe it by using the software; an agent then
674
+ uses the change by hand for those — the real program in a scratch directory, the
675
+ real page, guided by a project skill or a manual testing section in `AGENTS.md`,
676
+ `CLAUDE.md` or `README.md` — and writes `.gtd/PROTOTYPE.md`: per criterion pass,
677
+ fail or blocked, with the steps run and what it saw. A criterion the judge finds
678
+ no one can observe (a refactor, something left unchanged, internal shape), or
679
+ one design tagged `(no hands-on)`, is skipped; a change with none left skips
680
+ this step. This is the one check that a criterion is met: with `prototypeRounds`
681
+ set to `0` nothing checks the criteria beyond the green suite. Failures are
682
+ fixed and re-tested before the quality lap, up to `prototypeRounds` (3) fix
683
+ rounds; past them, with only blocked items, or with no way to test found, it
684
+ rests for you. See [The hands-on test](docs/configuration.md#the-hands-on-test).
685
+ Feedback at the feature review re-runs design and the implementation, never the
686
+ naive pass; feedback at the refactor review re-runs the refactor, never design;
687
+ a refactor-review change the refactor cannot build is refused, and the only way
712
688
  out is `gtd abandon`. A process from 27.5.0 or later whose judge ruled
713
- `refactor-first` must `gtd abandon` too. Each slice's quality lap reviews only
714
- that slice. Details in
689
+ `refactor-first` must `gtd abandon` too. Details in
715
690
  [the naive-pass path](docs/configuration.md#the-naive-pass-path).
716
691
 
717
- **Coarse slices (`sliceMaxCriteria`, default 8).** A change with more acceptance
718
- criteria than the cap is built in slices: after design an agent groups related
719
- criteria (same flow or subsystem) into `.gtd/SLICES.md`, as few slices as the
720
- cap allows, and each slice — naive pass, refactor and rebuild when judged so,
721
- health loop, quality lap — runs in order from where the previous one landed; the
722
- review follows the last one and covers the whole change. `gtd slices` lists them
723
- as `feature-1`, `feature-2`, … (`refactor-<n>` ahead of a refactored one). A
724
- change within the cap is one `feature` slice, as before. See
725
- [Coarse slices](docs/configuration.md#coarse-slices).
692
+ **One process, one build.** A change is built in one pass — one naive pass, one
693
+ build, one quality lap, one review — however many criteria it has. Sizing the
694
+ work is yours: split a change too big for one process into several before the
695
+ sketch.
726
696
 
727
697
  **Flag mode (`flagMode`, on by default).** On, the naive pass's judge runs as
728
698
  above and a rebuilt implementation is asked for a new release flag (none at a
@@ -787,8 +757,8 @@ When a process finishes, the landing that closes it also keeps the whole run
787
757
  behind a ref, `refs/gtd/history/<entry>`, so a squash or a deleted branch
788
758
  doesn't lose it. `/gtd ship` pushes this process's own ref to origin alongside
789
759
  the branch (never the others) and writes a `Gtd-History: <ref>` trailer on the
790
- commit of every slice. The push is forced, so it replaces origin's copy of that
791
- one ref. If that push fails, the ship fails and nothing is squashed. Recover the
760
+ squashed commit. The push is forced, so it replaces origin's copy of that one
761
+ ref. If that push fails, the ship fails and nothing is squashed. Recover the
792
762
  full trail with `gtd history fetch | sh`, then `gtd history show <ref>`.
793
763
 
794
764
  ```sh
@@ -803,12 +773,10 @@ gtd history fetch | sh # pull every kept ref from origin
803
773
  — every ref, or the ones named. It reads commit subjects and trailers only, so
804
774
  it never replays and a config changed since is no refusal:
805
775
 
806
- - **refactor-first rate** — of the slices whose naive pass was decided, the
776
+ - **refactor-first rate** — of the builds whose naive pass was decided, the
807
777
  share rebuilt rather than landed as it is; a landed pass that no longer
808
778
  applies and is built afresh counts as rebuilt (`refactored` counts the
809
779
  rebuilds a refactor came first for)
810
- - **continuations** — agent turns that picked up a turn stopped at its context
811
- limit, per phase (`seam.naive`, `implement.building`, `refactor.building`, …)
812
780
  - **cost** — the `Gtd-Cost` a driver recorded with `gtd land --cost --model`, by
813
781
  model and by phase (`naive`, `refactor`, `implement`, `other`), and the
814
782
  **double work** of a rebuild: its naive pass plus the implement turns that
@@ -824,7 +792,7 @@ it never replays and a config changed since is no refusal:
824
792
  `--json` prints `{ processes, total }`; `--json=total.refactorFirstRate` prints
825
793
  one value. Model, phase and lens keys may hold dots a path cannot reach: select
826
794
  their record whole (`--json=total.cost.byModel`). A branch name selects every
827
- process kept from that branch. A rate is `null` without a decided slice. Each
795
+ process kept from that branch. A rate is `null` without a decided build. Each
828
796
  process names its `workflow` (`null` for the default one); the total spans every
829
797
  ref measured, so name the refs to leave another workflow's processes out.
830
798
 
@@ -908,7 +876,7 @@ gtd is one package, `@pmelab/gtd`, and every entrypoint shares its version and
908
876
 
909
877
  | Import | What it is |
910
878
  | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
911
- | `@pmelab/gtd/flows` | The flow API a workflow is written in: the steps (`agent`, `human`, `run`, …), `scope` and `slice` (named spans of a process), workflow factories, `defineConfig` and `FLOWS_PROTOCOL`. |
879
+ | `@pmelab/gtd/flows` | The flow API a workflow is written in: the steps (`agent`, `human`, `run`, …), `scope`, workflow factories, `defineConfig` and `FLOWS_PROTOCOL`. |
912
880
  | `@pmelab/gtd/wire` | The driver protocol: `WIRE_SCHEMA`, the exit codes and the types of every `--json` document. |
913
881
  | `@pmelab/gtd/steering` | The steering-file formats (`qa`, `review`) and the review-note readers. |
914
882
  | `@pmelab/gtd/workflow-kit` | Policy-free building blocks to compose a workflow from: health checks, quality laps, scenario freezing, review tails. |
@@ -921,17 +889,11 @@ install for any of these but `./testkit`: gtd resolves a `gtd.config.ts`'s
921
889
  `@pmelab/gtd/*` imports to its own copy.
922
890
 
923
891
  The `gtd` bin's commands — `next`, `land`, `abandon`, `restore`, `validate`,
924
- `check`, `uncheck`, `install`, `summary`, `base`, `door`, `doors`, `slices`,
925
- `version`, `help`, `history list`, `history show`, `history metrics`,
926
- `history judges`, `history fetch`, `strays`, and the tools `ui`, `lsp`,
927
- `context-hook`, `judge` (`judge answer`, `judge run`) — are listed in the
892
+ `check`, `uncheck`, `install`, `summary`, `base`, `door`, `doors`, `version`,
893
+ `help`, `history list`, `history show`, `history metrics`, `history judges`,
894
+ `history fetch`, `strays`, and the tools `ui`, `lsp`, `judge` (`judge answer`,
895
+ `judge run`) — are listed in the
928
896
  [CLI reference](https://github.com/pmelab/gtd/blob/main/docs/cli.md).
929
- `gtd slices` lists the spans a flow's `slice()` calls mark. It refuses (exit 1)
930
- when HEAD neither closes nor sits inside a process, or when today's config
931
- disagrees with history about the process; a version mismatch only warns on
932
- stderr. `gtd summary --slice <name>` prints the closing-message prompt for one
933
- of those slices — its own range, human commits and cost — and inherits those
934
- refusals; an unknown name is refused with every valid slice listed.
935
897
 
936
898
  ## License
937
899
 
@@ -20,7 +20,6 @@ export type Beat = {
20
20
  skills?: string[]
21
21
  validate?: string
22
22
  access?: AccessDef
23
- context?: { soft?: number; hard?: number }
24
23
  judge?: unknown
25
24
  changes?: { status: string; path: string }[]
26
25
  session?: { id?: string; resume?: boolean | string }
@@ -43,7 +42,6 @@ export type Turn = {
43
42
  skills: readonly string[]
44
43
  scope: string
45
44
  access?: AccessDef
46
- context?: { soft?: number; hard?: number }
47
45
  }
48
46
 
49
47
  // `isLost`: the scope's subagent no longer takes messages.
@@ -185,7 +183,6 @@ function turnOf(b: Beat): Turn {
185
183
  skills: b.skills ?? [],
186
184
  scope: memory.split("#")[0]!,
187
185
  access: b.access,
188
- context: b.context,
189
186
  }
190
187
  }
191
188
 
@@ -23,9 +23,6 @@ import { personaSpec, resumable } from "./persona"
23
23
  import { JUDGE_SYSTEM, judgePrompt, judgeQuestions, judgeRunEnv, toVerdicts } from "./judge"
24
24
  import type { Judgment } from "./judge"
25
25
  import { catchFrom, throwTo } from "./handoff"
26
- import { classicResult, decide, guardOf } from "./context"
27
- import { contextHook } from "../../src/wire/ContextLimit.js"
28
- import type { Guard, HookEvent } from "./context"
29
26
  import { jobs } from "./jobs"
30
27
  import { documents, readDocument } from "./schema"
31
28
  import { READ_ONLY_GIT, ship } from "./ship"
@@ -82,23 +79,12 @@ const ours = new Set<string>()
82
79
  const accesses = new Map<string, AccessDef>()
83
80
  const setAccess = (id: string, a: AccessDef | undefined) =>
84
81
  void (a ? accesses.set(id, a) : accesses.delete(id))
85
- // Each turn agent's context limit, reset with its access; and why a worker
86
- // was stopped at it, for the turn's end to report.
87
- const guards = new Map<string, Guard>()
88
- const contextStops = new Map<string, string>()
89
82
  async function workerModel($: $, hint: string | undefined) {
90
83
  return subagentModel(hint, {
91
84
  smart: await $.env.get("GTD_PLANNERMODEL"),
92
85
  base: await $.env.get("GTD_CODERMODEL"),
93
86
  })
94
87
  }
95
- async function setGuard($: $, id: string, t: Pick<Turn, "context" | "model">) {
96
- const model = await workerModel($, t.model)
97
- const session = model === undefined ? (await $.session.usage()).context.window : undefined
98
- const guard = guardOf(t.context, model, await $.env.get("GTD_LOOP_CONTEXT_WINDOW"), session)
99
- if (guard) guards.set(id, guard)
100
- else guards.delete(id)
101
- }
102
88
  const waiting = new Map<string, (end: TurnEnd) => void>()
103
89
  const ended = new Map<string, TurnEnd>()
104
90
  const personas = new Set<string>()
@@ -151,8 +137,6 @@ async function send($: $, agentId: string, text: string) {
151
137
  async function forget($: $, memory: string, agentId: string) {
152
138
  $.ui.log(lostLine(memory.split("#")[0]!))
153
139
  accesses.delete(agentId)
154
- guards.delete(agentId)
155
- contextStops.delete(agentId)
156
140
  await update($, scopes, (s) => {
157
141
  const rest = { ...s }
158
142
  if (rest[memory]?.agentId === agentId) delete rest[memory]
@@ -224,7 +208,6 @@ function io($: $): Io {
224
208
  if (t.resume && entry && !known) $.ui.log(restartLine(t.scope))
225
209
  if (t.resume && known) {
226
210
  setAccess(known, t.access)
227
- await setGuard($, known, t)
228
211
  const end = send($, known, t.prompt)
229
212
  await update($, run, (r) => ({ ...r, inflight: { agentId: known, memory: t.memory } }))
230
213
  const ended = await end
@@ -244,7 +227,6 @@ function io($: $): Io {
244
227
  if (!id) return settle($, { ok: false, why: spawned.deny ?? "subagent spawn refused" })
245
228
  ours.add(id)
246
229
  setAccess(id, t.access)
247
- await setGuard($, id, t)
248
230
  await update($, agents, (list) => [...list, id].slice(-200))
249
231
  await update($, scopes, (s) => ({ ...s, [t.memory]: { agentId: id, persona: name } }))
250
232
  await update($, run, (r) => ({ ...r, inflight: { agentId: id, memory: t.memory } }))
@@ -771,7 +753,7 @@ async function shipNow($: $, isDry: boolean, isInTurn: boolean) {
771
753
  isInTurn,
772
754
  async () => {
773
755
  $.ui.status(isDry ? "previewing the pull request…" : "opening the pull request…")
774
- return ship(shipIo($), isDry, await $.env.get("GTD_SHIP_MODE"))
756
+ return ship(shipIo($), isDry)
775
757
  },
776
758
  async (shipped) => {
777
759
  // a failed ship leaves the run as it was; a dry run changes nothing
@@ -1076,40 +1058,6 @@ async function isOurs($: $, id: string) {
1076
1058
  return isWorker
1077
1059
  }
1078
1060
 
1079
- // `gtd context-hook`'s decision for a worker: past its soft limit it is asked
1080
- // for a handoff note; past its hard limit, or about to compact, its task is
1081
- // stopped and its turn ends as a failure carrying the stop reason. Stopped off
1082
- // the hook, which runs inside the worker's own tool call.
1083
- async function stopWorker($: $, id: string, stopReason: string) {
1084
- if (contextStops.has(id)) return
1085
- contextStops.set(id, stopReason)
1086
- $.clock.after(0, () => {
1087
- void $.tool.call({ tool: "TaskStop", task_id: id }).catch((err: unknown) => {
1088
- $.ui.log(`gtd could not stop a subagent at its context limit: ${String(err)}`)
1089
- })
1090
- })
1091
- }
1092
-
1093
- async function contextGuard($: $, e: HookEvent) {
1094
- const id = e.agent_id
1095
- if (!id || !ours.has(id)) return undefined
1096
- const decision = await decide(e, guards.get(id), async (path) =>
1097
- (await $.fs.exists(path)) ? $.fs.read(path) : undefined,
1098
- )
1099
- if (decision?.kind === "hard") await stopWorker($, id, decision.stopReason)
1100
- return decision && classicResult(decision)
1101
- }
1102
-
1103
- // A worker's own compaction carries its id here (`classic.PreCompact` is not
1104
- // documented to): compaction about to happen means its limit was missed.
1105
- async function compactGuard($: $, agentId: string | undefined) {
1106
- if (!agentId || !ours.has(agentId) || !guards.has(agentId)) return undefined
1107
- const decision = contextHook({ event: "PreCompact", tokens: undefined, ...guards.get(agentId)! })
1108
- if (decision?.kind !== "hard") return undefined
1109
- await stopWorker($, agentId, decision.stopReason)
1110
- return { skip: decision.stopReason }
1111
- }
1112
-
1113
1061
  // What a subagent this mod spawned may not do: write outside its step's
1114
1062
  // access, or, answering into a file, anything but that.
1115
1063
  function subagentDenial(agentId: string, e: Record<string, unknown>) {
@@ -1180,13 +1128,8 @@ export const register: Register = (on) => {
1180
1128
  void launchPending($)
1181
1129
  }
1182
1130
  if (e.agentId && ours.has(e.agentId)) {
1183
- const stopped = contextStops.get(e.agentId)
1184
- contextStops.delete(e.agentId)
1185
- const end: TurnEnd = stopped
1186
- ? { ok: false, why: stopped }
1187
- : e.reason === "answer"
1188
- ? { ok: true }
1189
- : { ok: false, why: `agent turn ended: ${e.reason}` }
1131
+ const end: TurnEnd =
1132
+ e.reason === "answer" ? { ok: true } : { ok: false, why: `agent turn ended: ${e.reason}` }
1190
1133
  delegates.delete(e.agentId)
1191
1134
  const resolve = waiting.get(e.agentId)
1192
1135
  waiting.delete(e.agentId)
@@ -1196,11 +1139,6 @@ export const register: Register = (on) => {
1196
1139
  return next(e)
1197
1140
  })
1198
1141
 
1199
- // A worker's tool call hands settings hooks the MAIN session's
1200
- // `transcript_path`, marked only by `agent_id`/`agent_type`; its own
1201
- // transcript (`agent_transcript_path`) is named only at SubagentStop, too
1202
- // late to measure a running worker's context.
1203
- //
1204
1142
  // The loop lands a turn when it ends; work left running in the background
1205
1143
  // would still be writing the tree gtd is committing.
1206
1144
  on("tool.call", async ($, e, next) => {
@@ -1217,9 +1155,6 @@ export const register: Register = (on) => {
1217
1155
  return next(e)
1218
1156
  })
1219
1157
 
1220
- on("classic.PostToolUse", async ($, e, next) => (await contextGuard($, e)) ?? next(e))
1221
- on("session.compact", async ($, e, next) => (await compactGuard($, e.agentId)) ?? next(e))
1222
-
1223
1158
  // A subagent's hand-back arrives as a prompt to the main session, whose model
1224
1159
  // would then act on it. gtd reads the turn's result from git instead.
1225
1160
  on("prompt.submit", async ($, e, next) => {