voidmachine 5.0.3 → 5.0.5

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness",
3
- "version": "5.0.3",
3
+ "version": "5.0.5",
4
4
  "description": "VoidCorp universal craftsman skills (void-tdd, void-typescript-strict, void-hexagonal-architecture, void-domain-driven-design, void-functional, void-code-review, void-api-and-interface-design, void-source-driven-development, void-context, void-learn, void-decide, void-claude-md, void-observability, void-security-guidance, ...) plus 12 PreToolUse enforcement hooks (tdd-guard, no-any, protect-sensitive-files, block-dangerous-bash, no-ai-design-slop, ...) and PostToolUse/SessionStart lifecycle hooks (incl. trim-large-output token frugality), five read-only critics including doctrine-critic, native architecture/security/QA specialists, and the void-graph, void-doctor and void-audit gestures, which are skills like everything else.",
5
5
  "author": {
6
6
  "name": "VoidCorp",
@@ -5,7 +5,7 @@
5
5
  "source": {
6
6
  "kind": "adapter",
7
7
  "version": "3.0.0-alpha.1",
8
- "rootHash": "sha256:69ada8c7a668574252b442c0bb1cde65d4d878973c9c59cc86871a147393bba9"
8
+ "rootHash": "sha256:56012433234f5e7d537066868543df205e92f817003384489c7e698778a49ab2"
9
9
  },
10
10
  "nodes": [
11
11
  {
@@ -3551,7 +3551,7 @@
3551
3551
  }
3552
3552
  ],
3553
3553
  "id": "skill:void-autopilot",
3554
- "lines": 394,
3554
+ "lines": 395,
3555
3555
  "name": "void-autopilot",
3556
3556
  "owner": "folpe",
3557
3557
  "pack": null,
@@ -3560,7 +3560,7 @@
3560
3560
  "codex"
3561
3561
  ],
3562
3562
  "source": "packages/core/skills/void-autopilot/SKILL.md",
3563
- "staticTokens": 6967,
3563
+ "staticTokens": 7051,
3564
3564
  "type": "skill"
3565
3565
  }
3566
3566
  },
@@ -4340,7 +4340,7 @@
4340
4340
  "codex"
4341
4341
  ],
4342
4342
  "source": "packages/core/skills/void-implement/SKILL.md",
4343
- "staticTokens": 5664,
4343
+ "staticTokens": 5800,
4344
4344
  "type": "skill"
4345
4345
  }
4346
4346
  },
@@ -4677,7 +4677,7 @@
4677
4677
  }
4678
4678
  ],
4679
4679
  "id": "skill:void-orchestrate",
4680
- "lines": 311,
4680
+ "lines": 327,
4681
4681
  "name": "void-orchestrate",
4682
4682
  "owner": "folpe",
4683
4683
  "pack": null,
@@ -4686,7 +4686,7 @@
4686
4686
  "codex"
4687
4687
  ],
4688
4688
  "source": "packages/core/skills/void-orchestrate/SKILL.md",
4689
- "staticTokens": 4402,
4689
+ "staticTokens": 4673,
4690
4690
  "type": "skill"
4691
4691
  }
4692
4692
  },
@@ -5373,7 +5373,7 @@
5373
5373
  }
5374
5374
  ],
5375
5375
  "id": "skill:void-verify",
5376
- "lines": 184,
5376
+ "lines": 203,
5377
5377
  "name": "void-verify",
5378
5378
  "owner": "folpe",
5379
5379
  "pack": null,
@@ -5382,7 +5382,7 @@
5382
5382
  "codex"
5383
5383
  ],
5384
5384
  "source": "packages/core/skills/void-verify/SKILL.md",
5385
- "staticTokens": 2267,
5385
+ "staticTokens": 2552,
5386
5386
  "type": "skill"
5387
5387
  }
5388
5388
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "harnessVersion": "5.0.3",
3
+ "harnessVersion": "5.0.5",
4
4
  "capabilities": [
5
5
  {
6
6
  "id": "skill:pack-mobile/void-eas-build-profile",
@@ -1703,7 +1703,7 @@
1703
1703
  }
1704
1704
  ],
1705
1705
  "id": "skill:void-autopilot",
1706
- "lines": 394,
1706
+ "lines": 395,
1707
1707
  "name": "void-autopilot",
1708
1708
  "owner": "folpe",
1709
1709
  "pack": null,
@@ -1712,7 +1712,7 @@
1712
1712
  "codex"
1713
1713
  ],
1714
1714
  "source": "packages/core/skills/void-autopilot/SKILL.md",
1715
- "staticTokens": 6967,
1715
+ "staticTokens": 7051,
1716
1716
  "type": "skill"
1717
1717
  },
1718
1718
  {
@@ -2204,7 +2204,7 @@
2204
2204
  "codex"
2205
2205
  ],
2206
2206
  "source": "packages/core/skills/void-implement/SKILL.md",
2207
- "staticTokens": 5664,
2207
+ "staticTokens": 5800,
2208
2208
  "type": "skill"
2209
2209
  },
2210
2210
  {
@@ -2415,7 +2415,7 @@
2415
2415
  }
2416
2416
  ],
2417
2417
  "id": "skill:void-orchestrate",
2418
- "lines": 311,
2418
+ "lines": 327,
2419
2419
  "name": "void-orchestrate",
2420
2420
  "owner": "folpe",
2421
2421
  "pack": null,
@@ -2424,7 +2424,7 @@
2424
2424
  "codex"
2425
2425
  ],
2426
2426
  "source": "packages/core/skills/void-orchestrate/SKILL.md",
2427
- "staticTokens": 4402,
2427
+ "staticTokens": 4673,
2428
2428
  "type": "skill"
2429
2429
  },
2430
2430
  {
@@ -2859,7 +2859,7 @@
2859
2859
  }
2860
2860
  ],
2861
2861
  "id": "skill:void-verify",
2862
- "lines": 184,
2862
+ "lines": 203,
2863
2863
  "name": "void-verify",
2864
2864
  "owner": "folpe",
2865
2865
  "pack": null,
@@ -2868,7 +2868,7 @@
2868
2868
  "codex"
2869
2869
  ],
2870
2870
  "source": "packages/core/skills/void-verify/SKILL.md",
2871
- "staticTokens": 2267,
2871
+ "staticTokens": 2552,
2872
2872
  "type": "skill"
2873
2873
  }
2874
2874
  ],
@@ -11093,6 +11093,7 @@ function executeContextContinuity(rawInput, root, runtime3, now) {
11093
11093
 
11094
11094
  init_define_VOID_SYNTAX_WORKER_IDENTITY();
11095
11095
  import { spawnSync as spawnSync2 } from "node:child_process";
11096
+ import { realpathSync as realpathSync5 } from "node:fs";
11096
11097
  import { homedir as homedir2 } from "node:os";
11097
11098
  import { join as join12 } from "node:path";
11098
11099
 
@@ -12984,6 +12985,39 @@ function metadataCommands(snapshot, event, sequence, contextPercent, workspaceMi
12984
12985
  return commands;
12985
12986
  }
12986
12987
 
12988
+ init_define_VOID_SYNTAX_WORKER_IDENTITY();
12989
+ var discoverySchema = object2({ result: object2({ process_info: object2({
12990
+ pane_id: string2(),
12991
+ foreground_processes: array(object2({
12992
+ pid: number2().check(int(), _gte(2))
12993
+ })).check(_minLength(1), _maxLength(256))
12994
+ }) }) });
12995
+ function foreground(output, pane) {
12996
+ try {
12997
+ const value = JSON.parse(output.toString("utf8"));
12998
+ if (record3(value)?.["error"] !== void 0) return void 0;
12999
+ const result = discoverySchema.safeParse(value);
13000
+ if (!result.success || result.data.result.process_info.pane_id !== pane) return void 0;
13001
+ return result.data.result.process_info.foreground_processes.map((item) => item.pid);
13002
+ } catch {
13003
+ return void 0;
13004
+ }
13005
+ }
13006
+ function proveOwnership(pids, call) {
13007
+ let pid = process.pid;
13008
+ const visited = /* @__PURE__ */ new Set();
13009
+ for (let depth = 0; depth < 64; depth++) {
13010
+ if (visited.has(pid)) return "parent-cycle";
13011
+ visited.add(pid);
13012
+ if (pids.includes(pid)) return void 0;
13013
+ const parent = call("ps", ["-o", "ppid=", "-p", String(pid)]).toString("utf8").trim();
13014
+ if (!/^[0-9]+$/.test(parent) || !Number.isSafeInteger(Number(parent))) return "invalid-parent";
13015
+ pid = Number(parent);
13016
+ if (pid <= 1) return "ownership-unproven";
13017
+ }
13018
+ return "parent-depth-exceeded";
13019
+ }
13020
+
12987
13021
  init_define_VOID_SYNTAX_WORKER_IDENTITY();
12988
13022
  import { createHash as createHash4 } from "node:crypto";
12989
13023
  import { closeSync as closeSync3, constants as constants4, fstatSync as fstatSync3, lstatSync as lstatSync4, opendirSync, openSync as openSync3, readSync as readSync3, realpathSync as realpathSync4 } from "node:fs";
@@ -13294,9 +13328,9 @@ function executeHerdrMetadata(raw, root, env, runtime3, run = runCommand) {
13294
13328
  };
13295
13329
  try {
13296
13330
  const common = call("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"]).trim();
13331
+ const inventory = () => paneList.parse(JSON.parse(call("herdr", ["pane", "list"]))).result.panes;
13297
13332
  const snapshot = readOrchestra(join12(env["HOME"] ?? homedir2(), ".local/state/orchestra"), common, root, () => {
13298
- const response = paneList.parse(JSON.parse(call("herdr", ["pane", "list"])));
13299
- return response.result.panes.flatMap((pane) => typeof pane.label === "string" && typeof pane.cwd === "string" ? [{
13333
+ return inventory().flatMap((pane) => typeof pane.label === "string" && typeof pane.cwd === "string" ? [{
13300
13334
  pane_id: pane.pane_id,
13301
13335
  workspace_id: pane.workspace_id,
13302
13336
  label: pane.label,
@@ -13304,7 +13338,29 @@ function executeHerdrMetadata(raw, root, env, runtime3, run = runCommand) {
13304
13338
  ...pane.tokens === void 0 ? {} : { tokens: pane.tokens }
13305
13339
  }] : []);
13306
13340
  });
13307
- if (snapshot === void 0) return { status: "skipped", details: { reason: "no-orchestra-mission" } };
13341
+ if (snapshot === void 0) {
13342
+ if (event !== "SessionStart") return { status: "skipped", details: { reason: "no-orchestra-mission" } };
13343
+ const paneId = env["HERDR_PANE_ID"];
13344
+ if (!paneId || !env["HERDR_SOCKET_PATH"]) throw Error("missing-herdr-context");
13345
+ const panes = inventory();
13346
+ const matches2 = panes.filter((pane2) => pane2.pane_id === paneId);
13347
+ const pane = matches2[0];
13348
+ if (matches2.length !== 1 || !pane || !pane.cwd || realpathSync5(pane.cwd) !== realpathSync5(root)) {
13349
+ throw Error("Herdr caller pane missing or foreign worktree");
13350
+ }
13351
+ if (pane.label && panes.filter((other) => other.label === pane.label && typeof other.cwd === "string" && realpathSync5(other.cwd) === realpathSync5(root)).length !== 1) {
13352
+ throw Error("ambiguous Herdr coordinator identity");
13353
+ }
13354
+ const pids = foreground(Buffer.from(call("herdr", ["pane", "process-info", "--pane", paneId])), paneId);
13355
+ if (pids === void 0) throw Error("invalid Herdr process discovery");
13356
+ const denied = proveOwnership(pids, (command, args) => Buffer.from(call(command, args)));
13357
+ if (denied !== void 0) throw Error(denied);
13358
+ return { status: "ok", details: { host: "herdr", mission: "absent" }, output: { hookSpecificOutput: {
13359
+ hookEventName: "SessionStart",
13360
+ additionalContext: `Validated Herdr caller: ${paneId}. No Orchestra mission selected.
13361
+ Use void-orchestrate before delegating a ticket: register the mission, create or reuse its worker tab, and launch the worker once. Revalidate live identity before acting; this hook never launches workers.`
13362
+ } } };
13363
+ }
13308
13364
  const workspace = snapshot.coordinator ? record3(record3(JSON.parse(call("herdr", ["workspace", "get", snapshot.pane.workspace_id])))?.["result"]) : void 0;
13309
13365
  const workspaceMission = record3(record3(workspace?.["workspace"])?.["tokens"])?.["mission"];
13310
13366
  const percent = measureHerdrContext(input, root, runtime3, now);
@@ -13341,8 +13397,17 @@ Read mission.md and the current brief/report before resuming; Herdr IDs are hint
13341
13397
  };
13342
13398
  } catch (error) {
13343
13399
  const reason = (error instanceof Error ? error.message : String(error)).slice(0, 500);
13344
- return { status: "degraded", details: { reason }, diagnostic: `herdr-metadata: ${reason}
13345
- ` };
13400
+ return {
13401
+ status: "degraded",
13402
+ details: { reason },
13403
+ diagnostic: `herdr-metadata: ${reason}
13404
+ `,
13405
+ ...event === "SessionStart" ? { output: { hookSpecificOutput: {
13406
+ hookEventName: "SessionStart",
13407
+ additionalContext: `Herdr discovery refused: ${reason}.
13408
+ Do not act on this host until resolved. Native delegation independent of that action may continue.`
13409
+ } } } : {}
13410
+ };
13346
13411
  }
13347
13412
  }
13348
13413
 
@@ -13356,41 +13421,10 @@ var runCommand2 = (command, args, options) => {
13356
13421
  if (result.error !== void 0 || result.status !== 0) throw Error("process-failed");
13357
13422
  return result.stdout;
13358
13423
  };
13359
- var discoverySchema = object2({ result: object2({ process_info: object2({
13360
- pane_id: string2(),
13361
- foreground_processes: array(object2({
13362
- pid: number2().check(int(), _gte(2))
13363
- })).check(_minLength(1), _maxLength(256))
13364
- }) }) });
13365
13424
  function refused(reason) {
13366
13425
  return { status: "degraded", details: { reason }, diagnostic: `herdr-session: ${reason}
13367
13426
  ` };
13368
13427
  }
13369
- function foreground(output, pane) {
13370
- try {
13371
- const value = JSON.parse(output.toString("utf8"));
13372
- if (record3(value)?.["error"] !== void 0) return void 0;
13373
- const result = discoverySchema.safeParse(value);
13374
- if (!result.success || result.data.result.process_info.pane_id !== pane) return void 0;
13375
- return result.data.result.process_info.foreground_processes.map((item) => item.pid);
13376
- } catch {
13377
- return void 0;
13378
- }
13379
- }
13380
- function proveOwnership(pids, call) {
13381
- let pid = process.pid;
13382
- const visited = /* @__PURE__ */ new Set();
13383
- for (let depth = 0; depth < 64; depth++) {
13384
- if (visited.has(pid)) return "parent-cycle";
13385
- visited.add(pid);
13386
- if (pids.includes(pid)) return void 0;
13387
- const parent = call("ps", ["-o", "ppid=", "-p", String(pid)]).toString("utf8").trim();
13388
- if (!/^[0-9]+$/.test(parent) || !Number.isSafeInteger(Number(parent))) return "invalid-parent";
13389
- pid = Number(parent);
13390
- if (pid <= 1) return "ownership-unproven";
13391
- }
13392
- return "parent-depth-exceeded";
13393
- }
13394
13428
  function nativeHook(env) {
13395
13429
  const path2 = join13(
13396
13430
  env["CODEX_HOME"] || join13(env["HOME"] || homedir3(), ".codex"),
@@ -13453,7 +13487,7 @@ function executeHerdrSession(input, env, runtime3, run = runCommand2, clock = ()
13453
13487
 
13454
13488
  init_define_VOID_SYNTAX_WORKER_IDENTITY();
13455
13489
  import { randomUUID } from "node:crypto";
13456
- import { lstatSync as lstatSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync11, readdirSync as readdirSync3, realpathSync as realpathSync5, renameSync as renameSync4, writeFileSync as writeFileSync3 } from "node:fs";
13490
+ import { lstatSync as lstatSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync11, readdirSync as readdirSync3, realpathSync as realpathSync6, renameSync as renameSync4, writeFileSync as writeFileSync3 } from "node:fs";
13457
13491
  import { basename as basename5, dirname as dirname6, isAbsolute as isAbsolute7, join as join16 } from "node:path";
13458
13492
 
13459
13493
  init_define_VOID_SYNTAX_WORKER_IDENTITY();
@@ -13512,20 +13546,20 @@ function claimedPath(root, sessionId) {
13512
13546
  if (!within(runs, path2) || lstatSync5(dirname6(path2), { throwIfNoEntry: false })?.isDirectory() !== true) {
13513
13547
  return void 0;
13514
13548
  }
13515
- return within(realpathSync5(runs), realpathSync5(dirname6(path2))) ? path2 : void 0;
13549
+ return within(realpathSync6(runs), realpathSync6(dirname6(path2))) ? path2 : void 0;
13516
13550
  } catch {
13517
13551
  return void 0;
13518
13552
  }
13519
13553
  }
13520
13554
  function waitingRun(root, cwd, now) {
13521
13555
  try {
13522
- const here = realpathSync5(cwd);
13556
+ const here = realpathSync6(cwd);
13523
13557
  const directory = join16(root, "agents", "pending");
13524
13558
  return readdirSync3(directory).filter((name) => !name.startsWith(".")).slice(0, 64).some((name) => {
13525
13559
  const marker = record3(JSON.parse(readFileSync11(join16(directory, name), "utf8")));
13526
13560
  const createdAt = marker?.["createdAt"];
13527
13561
  const runCwd = marker?.["cwd"];
13528
- return typeof createdAt === "number" && now - createdAt < PARKING_WINDOW_MS && typeof runCwd === "string" && realpathSync5(runCwd) === here;
13562
+ return typeof createdAt === "number" && now - createdAt < PARKING_WINDOW_MS && typeof runCwd === "string" && realpathSync6(runCwd) === here;
13529
13563
  });
13530
13564
  } catch {
13531
13565
  return false;
@@ -13953,7 +13987,7 @@ import { createHash as createHash5 } from "node:crypto";
13953
13987
  import {
13954
13988
  lstatSync as lstatSync7,
13955
13989
  mkdirSync as mkdirSync5,
13956
- realpathSync as realpathSync6,
13990
+ realpathSync as realpathSync7,
13957
13991
  writeFileSync as writeFileSync4
13958
13992
  } from "node:fs";
13959
13993
  import { join as join18, relative as relative7 } from "node:path";
@@ -14024,11 +14058,11 @@ ${errors}
14024
14058
 
14025
14059
  function safeOutputDirectory(root) {
14026
14060
  try {
14027
- const canonicalRoot = realpathSync6(root);
14061
+ const canonicalRoot = realpathSync7(root);
14028
14062
  const directory = voidMachinePath(root, "outputs");
14029
14063
  mkdirSync5(directory, { recursive: true, mode: 448 });
14030
14064
  const info = lstatSync7(directory);
14031
- const canonicalDirectory2 = realpathSync6(directory);
14065
+ const canonicalDirectory2 = realpathSync7(directory);
14032
14066
  if (!info.isDirectory() || info.isSymbolicLink() || !within(canonicalRoot, canonicalDirectory2)) {
14033
14067
  return void 0;
14034
14068
  }
@@ -14064,7 +14098,7 @@ function executeTrim(rawInput, root, env) {
14064
14098
  const hash = createHash5("sha256").update(extracted.text).digest("hex").slice(0, 12);
14065
14099
  const tool = extracted.tool.replaceAll(/[^A-Za-z0-9_]/g, "_").slice(0, 80);
14066
14100
  const file = join18(directory, `${tool}-${process.pid}-${Date.now()}-${hash}.log`);
14067
- const spillPath = relative7(realpathSync6(root), file).replaceAll("\\", "/");
14101
+ const spillPath = relative7(realpathSync7(root), file).replaceAll("\\", "/");
14068
14102
  const plan = planOutputTrim(extracted.text, {
14069
14103
  tool: extracted.tool,
14070
14104
  thresholdBytes,
@@ -14351,13 +14385,13 @@ Resolve before claiming done. This never blocks.
14351
14385
 
14352
14386
  init_define_VOID_SYNTAX_WORKER_IDENTITY();
14353
14387
  import { spawnSync as spawnSync8 } from "node:child_process";
14354
- import { closeSync as closeSync4, existsSync as existsSync8, lstatSync as lstatSync8, openSync as openSync4, readSync as readSync4, realpathSync as realpathSync7 } from "node:fs";
14388
+ import { closeSync as closeSync4, existsSync as existsSync8, lstatSync as lstatSync8, openSync as openSync4, readSync as readSync4, realpathSync as realpathSync8 } from "node:fs";
14355
14389
  import { dirname as dirname8, isAbsolute as isAbsolute10, join as join21, resolve as resolve9 } from "node:path";
14356
14390
  var GIT_TIMEOUT_MS2 = 5e3;
14357
14391
  var GIT_MAX_OUTPUT_BYTES = 1e6;
14358
14392
  function canonical2(path2) {
14359
14393
  try {
14360
- return realpathSync7(resolve9(path2));
14394
+ return realpathSync8(resolve9(path2));
14361
14395
  } catch {
14362
14396
  return resolve9(path2);
14363
14397
  }
@@ -90,8 +90,8 @@ skip a step, merge, or decide that a refusal does not apply to it.
90
90
 
91
91
  **Orchestrator.** Runs the loop. Evaluates no ticket, edits no code, reads no diff.
92
92
 
93
- **Workers**, one per slot. Each carries one ticket from claim to an open pull request, in its own
94
- worktree, by running `void-implement` whole.
93
+ **Workers**, one per slot, are commit-only. Each carries one ticket to a committed candidate
94
+ and proof references in its own worktree; the coordinator owns pushes and pull requests.
95
95
 
96
96
  **Reviewer.** The independent pass of `void-implement`, invoked by ORCH through
97
97
  `void-orchestrate` in a fresh read-only context on the exact head SHA. `autopilot review`
@@ -203,8 +203,8 @@ in flight set it when they create or push their branch and drop it with a merged
203
203
  own settings still count. So start each worktree from
204
204
  `origin/<base>` and never move a local base branch while units are in flight. The baseline
205
205
  recorded at `assign` is written once: a second `--before` for the same ticket is refused, so a unit
206
- cannot re-record the state it left as the state it found. It is compared by the worker before it
207
- pushes, with `autopilot fingerprint --after <ticket>`, and again by the kernel before it arms a
206
+ cannot re-record the state it left as the state it found. It is compared by the coordinator before it
207
+ publishes, with `autopilot fingerprint --after <ticket>`, and again by the kernel before it arms a
208
208
  merge. A changed or missing baseline sends the ticket to a human, unpublished; only that person
209
209
  deletes the record.
210
210
 
@@ -273,21 +273,22 @@ It runs `void-implement` whole in that worktree, and starts its mission with the
273
273
  mission what it has done: each specialist result through `mission specialist-event`, each proof
274
274
  through `mission verify`, a committed candidate through `mission writer-event`. The journal accepts
275
275
  only these typed events, no free note; what is not yet one of them does not survive a respawn, and
276
- uncommitted edits survive only in the worktree. When its proofs are green it runs
277
- `autopilot fingerprint --after <ticket>`, pushes its own branch, opens one pull request towards the
278
- base, ready for review rather than as a draft, and moves the ticket to In Review. The reviewer the
279
- orchestrator invokes is that cycle's independent review; it reviews ready pull requests only, so a
280
- draft waits.
276
+ uncommitted edits survive only in the worktree. During development, the coordinator may create or reuse a draft pull request
277
+ for the branch; drafts are permitted for development, never for merge admission. After the worker
278
+ returns its commit and green proofs, the coordinator runs `autopilot fingerprint --after <ticket>`,
279
+ pushes, and must mark the same pull request ready (create one only if absent), then move the ticket
280
+ to In Review. The independent reviewer examines ready pull requests only; an unfinished draft waits.
281
281
  Blocking findings come back as a hand-back and are corrected as a batch, per `void-implement`.
282
282
 
283
283
  On a hand-back the worker reads the reason: failing checks, blocking findings, a conflict, or a
284
284
  base that moved. It updates its branch by merging the base into it,
285
- never by rewriting pushed history, re-runs its proofs, and pushes again.
285
+ never by rewriting pushed history, re-runs its proofs, and returns its commit to the coordinator.
286
+ The coordinator updates the same PR; the worker does not create another one.
286
287
 
287
288
  May: run every `void-implement` pass whose predicate fires, run its own gates, apply a migration in
288
- dev/local only, push its own branch without force, and open or update its own pull request.
289
+ dev/local only, and return its commits and proofs to the coordinator.
289
290
 
290
- May not: enable auto-merge, merge anything, post or record a verdict, run `autopilot review`, move a ticket to Done, close or cancel a ticket, touch another ticket's branch or worktree,
291
+ May not: enable auto-merge, merge anything, post or record a verdict, run `autopilot review`, push, create or change pull requests, move a ticket to Done, close or cancel a ticket, touch another ticket's branch or worktree,
291
292
  prune the mission journals, or write the git state the repository shares -- `refs/stash`, tags,
292
293
  notes, remotes, the repository config.
293
294
 
@@ -332,7 +333,7 @@ head, then sends the ticket to a human. An ejected head whose own checks fail go
332
333
  worker as failing checks. A pull request in conflict with the base goes back to its worker. The
333
334
  worker classifies the conflict as the typed `conflict` judgment on the conflicting head, posted
334
335
  through `autopilot judgment conflict-class`: `mechanical` it resolves, re-runs
335
- its proofs and pushes; `semantic` -- two intents that disagree -- it leaves alone, and the kernel
336
+ its proofs and returns its commit for coordinator publication; `semantic` -- two intents that disagree -- it leaves alone, and the kernel
336
337
  sends the ticket to a human. A worker never picks a side of a semantic conflict to keep the loop
337
338
  moving.
338
339
 
@@ -102,7 +102,7 @@ Run in order. Each pass names the skill it composes and the predicate that fires
102
102
  3. **Source grounding** (ALWAYS; the source depends on what the change touches). Read the relevant sources before the first line, per the Anti-rustine section of `PHILOSOPHY.md`. For a third-party configuration, schema or call signature, compose `void-source-driven-development`: official documentation **of the installed version**, never an upgrade by default. For internal code, read the owning contract, types, source and project docs of what you are about to change. Assumed semantics produce bugs that cost hours to find, and the assumption is invisible in the diff — which is why this runs before the writing rather than at review. Cite a source briefly when it helps understand or record a choice; a missing citation never blocks on its own.
103
103
  4. **Migration safety** (IF it changes a DB schema or ships a migration). Compose `void-migrations` (and `void-drizzle-migration-safe` on a Drizzle/Postgres stack): zero-downtime, two-phase, batched backfill, locking analysis. **Once the migration is generated and safety-reviewed, apply it to the dev/local database before the TDD and E2E passes run** — otherwise those tests execute against a stale schema and prove nothing about the new shape. **This cycle only ever applies to dev/local; production migrations run through CI / GitHub Actions on merge, never from a worker or this session** (see the `void-migrations` anti-rule). A schema change must never reach the rest of the cycle without this pass.
104
104
  5. **Convene the panel** (ALWAYS once, in `team` mode). With `panel.provider: orchestrator`, consume ORCH's supplied panel and never launch another. Otherwise call `mission dispatch --json`: its first `invoke-specialists` action is at `stage: 'pre-implementation'`, before code. Compose `void-orchestrate` for native invocation. Pass the envelope's runtime, agentName, missionId, contextPack, reviewSubject and reviewScope unchanged; record actual starts and complete results using `mission specialist-event`. Reconcile an existing invocation before dispatch; uncertain identity means no launch. Keep at most four simultaneous agents, wait in bounded slices, and never fail an agent merely because a wait timed out. Findings brief the single writer; a concrete blocked verdict is resolved before implementation. Later controller stages reuse this transport and never replay preparation. Missing required capability is diagnosed, never fabricated.
105
- 6. **TDD implementation** (ALWAYS). The single lead writer composes `void-tdd` + `void-testing`. Red, green, refactor. Unit tests for the behavior, green before moving on. Review specialists remain read-only.
105
+ 6. **TDD implementation** (ALWAYS). During development, the coordinator may create or reuse a draft pull request for the branch. Keep work-in-progress PRs in draft and run focused local checks; do not wait for full remote CI per iteration. `void-verify` owns the transition to complete integration checks and its portable CI template. The single lead writer composes `void-tdd` + `void-testing`. Red, green, refactor. Unit tests for the behavior, green before moving on. Review specialists remain read-only.
106
106
  7. **Async + idempotency** (IF it sends email, calls an external side-effecting API, enqueues a job, or mints a single-use token). Compose `void-async-safety`: idempotency keys, replay/dedup window, bounded retries, single-use enforcement.
107
107
  8. **End-to-end tests** (IF it touches a user-facing flow). Write/extend the E2E suite (Playwright). The path a user actually walks, not just the unit.
108
108
  9. **UX/UI pass** (IF it touches a UI surface). The interface is held to production craft, not just "it renders". Compose `void-frontend-design` (build-time craft) + `void-ui-review` (the audit/critique ceiling: AI-slop test, squint test, interaction-state coverage, technical audit) + `void-accessibility`, across the baseline (BACK+FRONT parity, mobile and desktop, and the states a user actually hits — loading / error / empty). Browser-verified QA (live screenshots) runs via `void-qa` (the claude-in-chrome MCP). A UI ticket is not shippable until this pass is **verified, not assumed**.
@@ -115,7 +115,7 @@ Run in order. Each pass names the skill it composes and the predicate that fires
115
115
  This exists because the passes above have a measured hit rate of zero on a whole class of defect. Six shipped on 2026-08-06 with typecheck, lint, 2,700 tests and five CI checks green: five were caught by using the thing on the real tree, one by the harness itself, none by CI and none by the human merge gate. One of them reported "5 path(s) not extracted" about files it had read, parsed and indexed — the exact lie the feature existed to prevent — and it surfaced by running the command on the repo, after merge. Under autopilot nobody comes back to the previous ticket, so a defect found that way is a defect not found at all.
116
116
  **A fixture is not a dogfood.** The fixture is the shortcut that would have missed every one of the six: the two oversized generated artifacts that exposed the false count existed only in the real tree. **And "the command did not crash" is not an observation** — the output has to be read, and quoted rather than summarised as "works". A surface that genuinely cannot run here (a deploy, a remote service) has its limitation named, never worked around in silence. Keep the run read-only or reversible.
117
117
  14. **Dispose of what you found** (ALWAYS). A cycle surfaces defects that are not this ticket: an incoherent skill, a stale doc, a contract that lies. Do not file them on their merits. Compare each against the unit you are building, judged against the program objective: it either blocks this unit and is fixed here, or it beats this unit and becomes the next one, or it is **dropped**. Write one recap line per finding naming what it lost to. Record only evidence that cannot be reconstructed — a failure seen once, a measurement — with the command that replays it. The admission rules are `void-ticket`'s; this pass is where they fire.
118
- 15. **Ship** (ALWAYS). Compose `void-commit-discipline`, open the PR, attach the PR and verification evidence, then move a tracker-backed ticket to **In Review**. Move it to **Done** only after merge and final verification of the merged state. Commits are **bisectable** — one logical change each, dependency-ordered (infra → domain + tests → edge/UI + tests), each independently valid. Under `void-autopilot` the worker pushes its own branch and opens the PR, but never enables auto-merge, merges, posts the review status or moves the ticket to Done; the loop's reviewer performs the independent review of step 11 on the PR head SHA.
118
+ 15. **Ship** (ALWAYS). Compose `void-commit-discipline`, reuse the existing PR for the branch (create one only if absent), attach verification evidence, and mark the same pull request ready when the candidate meets the review handoff requirements. Then move a tracker-backed ticket to **In Review**. Move it to **Done** only after merge and final verification of the merged state. Commits are **bisectable** — one logical change each, dependency-ordered (infra → domain + tests → edge/UI + tests), each independently valid. Under `void-autopilot` the worker is commit-only: it returns the commit and proof references to the coordinator, who owns pushes, PR creation/readiness and tracker updates. The worker never enables auto-merge, merges, posts the review status or moves the ticket to Done; the loop's reviewer performs the independent review of step 11 on the PR head SHA.
119
119
 
120
120
  ---
121
121
 
@@ -40,6 +40,22 @@ or act on an unrelated project. Native work independent of that action may conti
40
40
  mandatory independent review or required isolation remains a blocker; do not
41
41
  replace it with self-review or silently weaken its requirement.
42
42
 
43
+ ## First ticket and optional worker tabs
44
+
45
+ SessionStart discovers Herdr even before central mission files exist. Its advice
46
+ requires a fresh caller pane at the canonical checkout and process ownership;
47
+ environment variables alone never authorize a host action. Revalidate before launch.
48
+ On a new implementation ticket, reuse the assigned writer if one exists. Otherwise,
49
+ in a validated Herdr session, register the mission and planned worker first, then
50
+ create one background tab in the resolved coordinator workspace with the assigned
51
+ worktree as cwd. Read the installed `herdr tab` schema, preserve focus with
52
+ `--no-focus`, and use the returned root pane for the single agent start below.
53
+ Reattach a matching existing worker instead of opening another tab. The coordinator
54
+ stays in its existing pane. Hooks only discover and advise; they never create tabs,
55
+ launch agents or write central files. Without Herdr, use native delegation normally.
56
+ An invalid host or explicit mission selection refuses only that host action;
57
+ independent native work may continue with the limitation stated.
58
+
43
59
  ## Brief and bound the delegation
44
60
 
45
61
  Use a fresh context by default. Choose a supported fork only when the task needs
@@ -10,3 +10,5 @@ Sources for `void-verify` skill (see `docs/plans/skill-audits/void-verify.md` fo
10
10
  Strategy: distill. Slim skill. Adapted for void-machine's specific signal set (12 items, each mapped to a skill or hook).
11
11
 
12
12
  No new hooks (composes with all existing).
13
+
14
+ - GitHub Actions event, concurrency and merge-queue documentation: https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows ; https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency ; https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue
@@ -19,6 +19,25 @@ If you find yourself wanting to skip the checklist "because it's a small change,
19
19
 
20
20
  ---
21
21
 
22
+ ## Local development and integration
23
+
24
+ During development, run the smallest meaningful configured test command against the
25
+ changed behavior, plus affected types and local hooks. Keep the PR in draft; do not
26
+ wait for full remote CI after each edit or commit. Fresh local evidence still gates
27
+ claims about the behavior tested. `commands.testUnit` and `commands.typecheck` in
28
+ `.void/config.json` describe project commands; preserve their argv.
29
+
30
+ When the candidate is committed and independently reviewed, run the applicable final
31
+ checks below and mark the PR ready. Wait for real required CI on that head and, if
32
+ configured, the merge group before integration. Local success cannot replace a required
33
+ server check. Returning to draft cancels obsolete PR work without resetting reviews.
34
+
35
+ For an explicitly requested CI setup or optimization, use the installed
36
+ [executable admission guard and workflow template](references/ci-feedback.md).
37
+ They defer draft validation with an explicit non-success outcome, rerun on readiness,
38
+ and preserve merge queue checks. Never install them or change remote protection merely
39
+ because this skill was invoked.
40
+
22
41
  ## The checklist
23
42
 
24
43
  Read item by item. Do not run from memory. Each item is OBSERVED, not assumed.
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ // tdd-cover: e2e packages/cli/src/lib/ci-feedback.test.ts
3
+ // An admission refusal is not test evidence. Keep this step inside the required
4
+ // quality job: a skipped required job reports success in GitHub Actions.
5
+ import { readFileSync } from 'node:fs';
6
+
7
+ try {
8
+ const name = process.env.GITHUB_EVENT_NAME;
9
+ if (!['pull_request', 'merge_group', 'push', 'workflow_dispatch'].includes(name)) {
10
+ throw new Error('CI_INVALID_EVENT: unsupported or missing GitHub event.');
11
+ }
12
+ const event = JSON.parse(readFileSync(process.env.GITHUB_EVENT_PATH, 'utf8'));
13
+ if (name === 'pull_request') {
14
+ if (typeof event?.pull_request?.draft !== 'boolean') {
15
+ throw new Error('CI_INVALID_EVENT: pull request draft state is missing or malformed.');
16
+ }
17
+ if (event.pull_request.draft) {
18
+ throw new Error('CI_DEFERRED_DRAFT: preparation only; run focused tests locally, then mark ready for review to start integration validation. No tests were run.');
19
+ }
20
+ }
21
+ process.stdout.write('CI_ADMITTED: run the complete integration checks for this revision.\n');
22
+ } catch (error) {
23
+ process.stderr.write(`${error instanceof Error ? error.message : 'CI_INVALID_EVENT: unreadable event.'}\n`);
24
+ process.exitCode = 1;
25
+ }
@@ -0,0 +1,51 @@
1
+ # Fast local feedback, real integration checks
2
+
3
+ The sibling files are shipped with this skill and copied by `init` into the selected
4
+ runtime's skill directory. Resolve them relative to the SKILL.md you actually loaded,
5
+ not from a developer checkout or a global installation.
6
+
7
+ On an explicit CI configuration request:
8
+
9
+ 1. Inspect existing workflows, required check names, package manager, branch names,
10
+ review publication and release dependencies. Preserve their owners. Do not overwrite
11
+ existing workflows with this example or install a second quality workflow.
12
+ 2. Adopt the behavior in `quality.yml` into the existing quality workflow. Copy
13
+ `ci-admission.mjs` to `.github/scripts/ci-admission.mjs`. Keep the admission step
14
+ inside an existing **required** quality job, before dependency installation, without
15
+ `continue-on-error`, `always()` on later quality steps, or a job-level draft skip.
16
+ 3. Set up the project's actual package manager and immutable lockfile installation.
17
+ The example uses npm. For pnpm/Bun use their pinned setup and frozen install.
18
+ Define `ci:verify` in package.json to run the actual complete lint, typecheck, build,
19
+ and test commands appropriate to the project. Do not equate `testUnit` with the
20
+ whole integration suite; discover the project's existing CI contract. Missing
21
+ `ci:verify` fails rather than silently passing. Never use `--if-present` or `true`.
22
+ 4. Preserve remote protection and exact-head checks. Keep the required check names
23
+ stable. Review protection adoption separately if no quality check is required;
24
+ this template alone does not configure GitHub protection. Retain the separate
25
+ `void-enforce` floor and independent review. This template does not replace either.
26
+ 5. Test draft, ready without another commit, new head, return to draft, merge group,
27
+ and manual run. `CI_DEFERRED_DRAFT` is expected non-admission during preparation,
28
+ not a failed test: tests have not run. Readiness runs the full suite even at the
29
+ same SHA. Never treat a skipped required job as successful test evidence.
30
+
31
+ Development runs configured local tests for the changed behavior and affected types.
32
+ There is no network hook or mandatory remote wait per edit. Only obsolete PR runs are
33
+ cancelled. Distinct merge groups, manual runs and release runs must have distinct
34
+ concurrency keys: `cancel-in-progress: false` alone still replaces pending runs in a
35
+ shared group. Keep integration checks before entry to the protected branch; checking
36
+ only after merge permits broken integration.
37
+
38
+ GitHub couples required PR and merge queue checks. Preserve both. Remove a redundant
39
+ post-merge run only after checking that no release, promotion or artifact consumer
40
+ needs it, and that the protected integration path proves the merged result. The
41
+ example has no push trigger; add one where it provides distinct release evidence.
42
+
43
+ Rollback: restore the prior workflow triggers and admission step together. Restoring
44
+ full draft CI costs runner time but does not weaken the floor. Leave protection and
45
+ review evidence unchanged. Existing missions and receipts are not migrated.
46
+
47
+ Sources read for GitHub Actions (hosted service):
48
+ - https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request
49
+ - https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency
50
+ - https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue
51
+ - https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-jobs-with-conditions