vinta-ai-workflows 0.7.0-alpha32 → 0.7.0-alpha33

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/CHANGELOG.md CHANGED
@@ -7,6 +7,7 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [0.7.0] — YYYY-MM-DD
9
9
 
10
+ <!-- pre-release: 0.7.0-alpha33 on 2026-10-16 -->
10
11
  <!-- pre-release: 0.7.0-alpha31 on 2026-10-09 -->
11
12
  <!-- pre-release: 0.7.0-alpha30 on 2026-10-09 -->
12
13
  <!-- pre-release: 0.7.0-alpha20 on 2026-09-24 -->
@@ -32,6 +33,62 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
32
33
 
33
34
  ### Added
34
35
 
36
+ - **`vinta-ai-maestro`: ways past a stale gate verdict.** `gate <id>
37
+ --no-cache` runs a gate past its cached result and keeps the new one in its
38
+ place; a cached red now says so. `gate-cache invalidate <run-id> <gate-id>
39
+ [--tree <hash>]` forgets a gate's results for the operator and the run
40
+ coordinator (`POST /api/runs/:id/gates/:gate/invalidate`, journalled as
41
+ `gate_cache_invalidated`; an agent's token cannot reach it). Both are for a
42
+ verdict whose cause git does not track — an ignored file, a tool's cache, an
43
+ installed dependency — which the tree-keyed cache would otherwise replay.
44
+
45
+ - **`vinta-ai-maestro`: a phase's decisions outlive the session they were
46
+ made in.** Each node now keeps a list of what was settled for it: agents'
47
+ questions with their answers (marked as the operator's, the coordinator's,
48
+ or unattended), the operator's `node context` and `redirect` text, and the
49
+ findings the review rejected with their counter-evidence. Every later
50
+ prompt carries the list — implementer, fixer, chores, and the review, which
51
+ hands it to its reviewer — so a fresh reviewer, a replaced session or a
52
+ retry no longer re-asks or re-raises what was already decided. Before
53
+ this, an unattended run answered one question four times and a phase ran
54
+ some thirty rounds without converging, and operator context sent with
55
+ `node context` had to be re-sent after a session change. The review now
56
+ rejects a finding that re-opens a decision, citing it, and asks the
57
+ operator about it at most once, and only with new evidence. It ends its
58
+ report with a `REJECTED:` line per rejected finding, which the run keeps.
59
+ The list is bounded (the newest 12 answers and notes and the newest 8
60
+ rejected findings), kept across retries, written to
61
+ `runs/<id>/nodes/<node>/decisions.jsonl` and read back when a run resumes.
62
+
63
+ - **`vinta-ai-maestro judge calibrate`: measure a permission-judge question
64
+ before a run relies on it.** It replays a past run's `Bash` calls
65
+ (`--run <run-id>`), or a file of commands each optionally labelled `safe` or
66
+ `unsafe` (`--commands <file>`), against a candidate question
67
+ (`--question` / `--question-file`) and threshold (`--threshold`) through the
68
+ classifier in `--system-one`. Nothing is executed. It reports how many would
69
+ be allowed and refused, the score distribution, every labelled command
70
+ judged the wrong way, and the highest-scoring must-deny command, and exits 1
71
+ on a misjudged one so a case file can guard a project's question in CI.
72
+ Commands are printed as recorded, never their output.
73
+
74
+ - **`vinta-ai-maestro`: `project.reset_cmd` and `project.recycle_keep`.**
75
+ `reset_cmd` is a project hook run inside a lane when it is recycled for the
76
+ next phase, and only then, after maestro's own resets and before
77
+ `setup_cmd`. `recycle_keep` lists gitignore patterns a recycled lane keeps
78
+ (`.venv`, say) now that the recycle cleans ignored files. Both optional, in
79
+ `workflow.v1`.
80
+
81
+ - **`vinta-ai-maestro`: `node fresh <run> <phase>` drops a phase's agent
82
+ session without failing the attempt.** The phase's next turn starts cold with
83
+ the whole brief, journalled `node_session` `reason: operator_fresh`; the turn
84
+ in flight is not stopped (pair it with `redirect` for that). It is the way out
85
+ of a session gone wrong — an agent replaying killed work or carrying on with
86
+ the previous phase — that used to cost an `abort`. Also `POST
87
+ /api/runs/:run/nodes/:node/fresh`, and the run coordinator can use it. The
88
+ post-mortem's `operations.node_operations[].op` gains `fresh` (additive, in
89
+ `postmortem.v1.schema.json`).
90
+
91
+
35
92
  - **`vinta-ai-maestro`: a busy crew member is replaced, not borrowed
36
93
  (`defaults.max_spare_crew`, default 2).** When the member a phase is planned
37
94
  for — or the one an operator picked with `retry with <member>` — is busy, or
@@ -552,6 +609,15 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
552
609
 
553
610
  ### Changed
554
611
 
612
+ - **`vinta-ai-maestro`: a recycled lane no longer keeps the last phase's
613
+ ignored files.** A lane handed to the next phase kept everything gitignored,
614
+ and one kept `apps/api/.mypy_cache` and a deleted package's `__pycache__`,
615
+ so mypy reported 18 errors on clean code. The recycle now cleans ignored
616
+ files too, keeping only the copied `node_modules`, the `env_files` and the
617
+ new `project.recycle_keep` patterns. **Migration:** anything expensive your
618
+ lanes build and should keep across phases, such as a `.venv`, goes in
619
+ `recycle_keep`; otherwise `setup_cmd`, which already runs on every
620
+ recycle, rebuilds it.
555
621
  - **`vinta-ai-maestro`: agents wait for background work the way a normal
556
622
  Claude Code session does.** A headless session no longer ends at the first
557
623
  turn that leaves background work running. It stays open, the agent is woken
@@ -891,6 +957,126 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
891
957
 
892
958
  ### Fixed
893
959
 
960
+ - **`vinta-ai-maestro`: a fix loop that changes nothing now stops and asks.**
961
+ A typecheck red because of ignored files left in a lane kept coming back
962
+ from the gate cache after they were gone, and twenty fixers in a row found
963
+ nothing to fix. When a gate is red again on the very tree a fixer turn left
964
+ unchanged, the scheduler reruns that gate once without the cache; if it is
965
+ still red the same way, `standard-phase` goes to `exhausted` instead of
966
+ spawning another fixer — with or without `max_fix_rounds` — and the run
967
+ coordinator is woken. New guard fact `gate.stalled`, new `run_gate` param
968
+ `no_cache`, new journal event `gate_stalled`. A fixer that moved the tree at
969
+ all is never a stall. A custom pipeline keeps its own guards and can opt in
970
+ on `gate.stalled`.
971
+
972
+ - **`vinta-ai-maestro`: a claude-code review no longer loses a reviewer answer
973
+ that comes back early.** When a reviewer resumed with `SendMessage` answered
974
+ while the agent was still writing its last message, the session ended at the
975
+ turn's `result` and killed the turn the CLI starts to hand over the answer.
976
+ The review then stated no verdict and went to the operator as `unapproved`.
977
+ The session now waits for that turn, for at most a minute of silence.
978
+
979
+ - **`vinta-ai-maestro purge` no longer ends a run you did not name.** A bulk
980
+ `purge --lanes` removed the lanes of paused, failed and interrupted runs —
981
+ the integration worktree included — so `run --resume` had nothing to adopt,
982
+ and a bulk `purge` deleted those runs' frozen snapshots. A run that could
983
+ still be resumed is now kept whole, directory and lanes, and named with the
984
+ reason; purge it by name, or pass the new `--force`. A run whose job is
985
+ still running is kept even then.
986
+ - **`vinta-ai-maestro purge --lanes` tears a lane down, not just its
987
+ worktree.** It used to leave every forked database, compose stack and lane
988
+ summary behind, including summaries whose worktree was already gone. Each
989
+ reaped lane's summary is now its teardown manifest: `docker compose -p
990
+ <project> down`, `docker volume rm` for its forked volumes, the `reset_cmd`
991
+ of its own service namespaces, and `dropdb` (or the project's `dropdb_cmd`)
992
+ for its forked databases — every command listed before anything runs, and
993
+ under `--dry-run` nothing runs. Only what is provably that lane's is
994
+ touched: never a compose-delivered database, an index-numbered service slot,
995
+ or a summary `prepare-worktree` wrote for a worktree you made. A step that
996
+ fails is reported, and its lane's summary is kept so a rerun retries it.
997
+ - **`vinta-ai-maestro run --help` says which runs resume.** It claimed a run
998
+ that "finished" could not be resumed, while a `failed` run resumes — its
999
+ failed phases and the ones they blocked are attempted again, and `status`
1000
+ prints the command for it. The help now names paused, interrupted and
1001
+ failed as resumable, and only `done` and `cancelled` as refused.
1002
+ - **`vinta-ai-maestro`: the shipped permission-judge question no longer
1003
+ refuses routine commands.** Under `--permission judged` it allowed 44 of 69
1004
+ commands from a real run, refusing `ls .env*`, `cat .env.example`,
1005
+ `docker ps` and the project's own `make` targets. The question now says a
1006
+ secret is a *value* — listing env files and reading templates is allowed,
1007
+ reading a real `.env` is not — allows read-only inspection and the project's
1008
+ own commands in its worktree, and still refuses pushes, `sudo`, writes
1009
+ outside the worktree and another project's containers or volumes. A
1010
+ project that set its own `judges.permission.question` is unaffected; the
1011
+ default `allow_above` stays 0.9.
1012
+
1013
+ - **`vinta-ai-maestro`: the disk preflight sizes the pool the run will
1014
+ really create.** `run --resume` with every worktree still on disk was
1015
+ refused (`3 lanes + 1 integration worktree needs 37.9 GiB, only 18.0 GiB
1016
+ free`) by a doctor that charged for them all again; it now charges only the
1017
+ worktrees still to be made, and passes a resume that makes none. A staffed run
1018
+ is counted as the pool provisions it — a worktree per crew member, not per
1019
+ unit of `resources.lane.capacity` — plus `defaults.max_spare_crew`
1020
+ headroom, and the doctor, the pool and the refusal line now name the same
1021
+ count. The per-lane estimate is the tracked tree at the base branch, the
1022
+ copied `node_modules` and the `env_files`, instead of a walk of the whole
1023
+ main checkout that counted `.git`, the `.vinta-ai-maestro/` store (lanes
1024
+ included) and ignored caches — one run's estimate had grown from 4.0 to
1025
+ 9.5 GiB a lane against real lanes of about 1.1 GiB.
1026
+
1027
+ - **`vinta-ai-maestro`: an integration merge a pause, stop or kill caught
1028
+ half-way no longer wedges the run.** Every later attempt used to fail on
1029
+ `integration worktree is mid-merge` until someone ran `git merge --abort` by
1030
+ hand. The integrator now recognises a merge it started — one of the plan's
1031
+ phase branches (or a kept resolution, or the plan branch) into one of its
1032
+ `integ-`/`wave-` branches — keeps what it had under
1033
+ `refs/vinta-ai-maestro/abandoned/<branch>`, aborts it and redoes it, so the
1034
+ result is gated again; each one journals `integration_reclaimed`. The same
1035
+ sweep runs on `run --resume` and when a stop outlives its deadline. A conflict
1036
+ left for a person that nobody finished is redone on the retry the same way.
1037
+ A merge the run did not start is still refused by name. A failed `git_merge`
1038
+ of a named branch now aborts its merge.
1039
+
1040
+ - **`vinta-ai-maestro`: aborting the only runnable phase no longer ends the
1041
+ run.** A run whose remaining phases all depended on an aborted one ended
1042
+ `failed` at once, and the `node retry` that followed was refused as `run has
1043
+ ended`. Aborted phases now hold the run open for their retry (no timer retries
1044
+ them); `pause` or `stop` ends it. Under `--on-failure stop` an abort still ends
1045
+ the run. A retry sent while the aborted attempt is still winding down is
1046
+ applied once it has.
1047
+
1048
+ - **`vinta-ai-maestro`: a gate run inside `with` no longer deadlocks every
1049
+ lane.** `vinta-ai-maestro with test-suite -- vinta-ai-maestro gate test`
1050
+ held the only `test-suite` slot while the gate queued for it, and every
1051
+ lane's tests and gates queued behind the pair (55 minutes in one run). The
1052
+ gate guard now refuses `gate` inside `with` and tells the agent to run the
1053
+ gate on its own. The daemon refuses a gate whose resources the asking phase
1054
+ already holds through `with` (`holds_required:<resource>`), naming the
1055
+ process holding them. The agent prompts state the same rule.
1056
+ - **`vinta-ai-maestro`: `with` and `gate` say who they are waiting on.** A
1057
+ queued answer names each holder of the resource: the phase, its lane, and
1058
+ how it holds it (`with` with its process id, a gate an agent ran, or the
1059
+ phase's own gate step). When the holder is the asking phase itself, the
1060
+ message says so. It used to say "held by another lane" in exactly that case.
1061
+ `gate` now says "queued" until the gate has its resources and "running"
1062
+ after; it used to say "running" throughout.
1063
+ - **`vinta-ai-maestro`: commands left behind by an ended agent session stop
1064
+ holding capacity.** Each agent session gets a turn id
1065
+ (`VINTA_AI_MAESTRO_TURN_ID`), which `with` and `gate` send with every
1066
+ request. When the session ends, the leases its commands hold are released,
1067
+ their queued waits and queued gates are cancelled, and their next request is
1068
+ refused (`turn_ended`). A request for a phase that is not running is refused
1069
+ too (`holder_not_running`). A command backgrounded with `&` used to keep its
1070
+ place in the queue for as long as it lived: one run had nine such waiters,
1071
+ up to 55 minutes old.
1072
+ - **`vinta-ai-maestro`: `pause` finishes while an agent waits on a lease or a
1073
+ gate.** A pause (or stop) now answers every queued `with` and `gate` with
1074
+ `run_pausing` (`run_stopping`) and refuses new ones. The CLIs tell the agent
1075
+ to end its turn, which is the step boundary the pause waits for. Commands
1076
+ and gates already running finish as before. The halt log names each node
1077
+ the drain is still waiting on and what it is doing, and
1078
+ `vinta-ai-maestro pause` prints the same list.
1079
+
894
1080
  - **`vinta-ai-maestro`: a turn the agent never took part in is no longer read
895
1081
  as work.** A session that ended with no text and no tool call — observed when
896
1082
  a resumed claude-code session closed a replay of killed background tasks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vinta-ai-workflows",
3
- "version": "0.7.0-alpha32",
3
+ "version": "0.7.0-alpha33",
4
4
  "description": "Bootstrap AI tooling (AGENTS.md, skills, sub-agents) across Claude Code, Codex, Cursor, and VS Code + GitHub Copilot.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -680,7 +680,8 @@
680
680
  "add_context",
681
681
  "redirect",
682
682
  "pause",
683
- "abort"
683
+ "abort",
684
+ "fresh"
684
685
  ]
685
686
  },
686
687
  "by": {
@@ -704,7 +705,7 @@
704
705
  ],
705
706
  "additionalProperties": false
706
707
  },
707
- "description": "Steering, pauses and aborts, per phase."
708
+ "description": "Steering, pauses, aborts and dropped sessions, per phase."
708
709
  },
709
710
  "questions": {
710
711
  "type": "object",
@@ -360,6 +360,20 @@
360
360
  "description": "The project’s own lane-setup command, run inside each freshly provisioned lane with that lane’s environment applied. The escape hatch for whatever a project needs that no field here describes. It MUST be idempotent: it runs again every time the lane is recycled for another phase.",
361
361
  "type": "string",
362
362
  "minLength": 1
363
+ },
364
+ "reset_cmd": {
365
+ "description": "Run inside a lane when it is recycled for another phase, and only then — never on a freshly provisioned lane. Runs with the lane’s environment applied, after maestro has reset the worktree, the env files, the databases and the services, and before `setup_cmd`. For what a phase leaves behind that the clean does not reach: a cache outside the worktree, a `recycle_keep` directory that needs pruning rather than deleting.",
366
+ "type": "string",
367
+ "minLength": 1
368
+ },
369
+ "recycle_keep": {
370
+ "default": [],
371
+ "description": "Ignored paths a recycled lane keeps. A recycle removes every untracked and ignored file the previous phase left — caches such as `.mypy_cache` and `__pycache__` included, which once kept a deleted package importable and failed a type check on clean code — except the copied dependency tree, the `env_files` and what is listed here. Each entry is a gitignore pattern handed to `git clean -e`: `.venv` keeps one at any depth, `/apps/api/.venv` only that one. For what is expensive to rebuild; anything not listed is rebuilt by `setup_cmd`, which runs on every recycle.",
372
+ "type": "array",
373
+ "items": {
374
+ "type": "string",
375
+ "minLength": 1
376
+ }
363
377
  }
364
378
  },
365
379
  "required": [