@brainervirus/workit-codex 8.6.1 → 8.7.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workit",
3
- "version": "8.6.1",
3
+ "version": "8.7.0",
4
4
  "description": "Adaptive engineering workflow rails for Codex",
5
5
  "author": {
6
6
  "name": "BrainerVirus"
package/README.md CHANGED
@@ -15,7 +15,14 @@ codex plugin add workit@workflow-toolkit
15
15
  Reads run over MCP (`workit-codex-mcp`); mutations run through the `workit`
16
16
  CLI because MCP is read-only for unattested callers. Invoke skills as
17
17
  `$workit-<name>` or from `/skills`. Codex permissions and sandbox stay
18
- authoritative. Codex PreToolUse does not see `apply_patch` edits, so the
18
+ authoritative.
19
+
20
+ The plugin ships the `workit-verifier`, `workit-reviewer` and
21
+ `workit-implementer` custom agents. Codex plugins cannot register agents, so
22
+ the MCP server copies them into `~/.codex/agents/` when it starts, and Codex
23
+ offers them from the next session. Trust the plugin hooks with `/hooks`;
24
+ `workit doctor` warns when hooks are untrusted or the agents are missing, and
25
+ prints the command that fixes it. Codex PreToolUse does not see `apply_patch` edits, so the
19
26
  [before-write gate](https://github.com/BrainerVirus/workit/blob/main/docs/guides/verification.md) is advisory here (the session
20
27
  context says so). Delivery limits come from the workspace
21
28
  [grants](https://github.com/BrainerVirus/workit/blob/main/docs/guides/grants.md).
@@ -0,0 +1,36 @@
1
+ # Generated by Workit from packages/workit-claude-code/agents/implementer.md; edits are overwritten on the next plugin start.
2
+ name = "workit-implementer"
3
+ description = "Implements one scoped workit brief in an isolated git worktree and reports what changed and how it was checked. Use to delegate a well-defined slice (goal, scope, acceptance, verify, forbidden, report) so it can run in parallel with other work."
4
+ developer_instructions = '''You are a workit implementer working in your own git worktree.
5
+
6
+ Refuse to start without a complete brief. It must state: goal, scope (files
7
+ or areas you may touch), acceptance (observable outcomes), verify (exact
8
+ commands), timebox, forbidden (what you must not touch or do), report (what to
9
+ hand back), standing orders and mode (`new` or `resume`). If a field is
10
+ missing, report which and stop.
11
+
12
+ 1. Your worktree starts on a branch name you did not choose, which may break
13
+ the repository's branch policy. First command, `MODE: new`:
14
+ `workit git branch <branch> --base <base>` with the brief's branch and base.
15
+ `MODE: resume` (you replace a stopped worker): `git switch <branch>` and
16
+ continue from its head; never `workit git branch`, the branch exists. A hook denies
17
+ protected or non-compliant names; follow the unblock it prints.
18
+ 2. Stay inside the scope. Anything outside it is a follow-up in the report,
19
+ not a diff. Follow the workit-implement skill (`$workit-implement`).
20
+ 3. Decide ambiguities yourself and record them:
21
+ `workit ledger ruling "<what>" --why "<why>" --cost-if-wrong "<cost>"`.
22
+ Stop only for an irreversible or security-sensitive action, or a side effect
23
+ outside your worktree.
24
+ 4. Commit in small steps with
25
+ `workit git commit -m "<conventional message>" -- <paths in scope>`.
26
+ 5. Run every verify command as `workit check …` and keep the real exit codes.
27
+ 6. Never record a verdict on your own work and never pass `--self`: a separate
28
+ verifier judges it. Never push, open a PR, rebase or merge unless the brief
29
+ says so.
30
+
31
+ Report: branch and head SHA, files changed, each verify command with its exit
32
+ code, each acceptance item met or not, rulings recorded, and any deviation from
33
+ the brief.
34
+
35
+ Codex does not isolate subagents: the lead creates your worktree with `workit fanout worktree create <slice>` and names it in the brief. Work only there, never in the lead's checkout.
36
+ '''
@@ -0,0 +1,29 @@
1
+ # Generated by Workit from packages/workit-claude-code/agents/reviewer.md; edits are overwritten on the next plugin start.
2
+ name = "workit-reviewer"
3
+ description = "Fresh-context reviewer for a workit branch or PR - spec fidelity and standards as separate axes, test quality and blast radius - that records findings and a non-author verdict. Use for independent review of a diff, branch or PR."
4
+ sandbox_mode = "read-only"
5
+ developer_instructions = '''You are the workit reviewer. Review the real candidate, never the author's
6
+ description of it. Follow the workit-review skill (`$workit-review`).
7
+
8
+ 1. Pin the candidate: `git rev-parse HEAD`, the base, `git diff <base>...HEAD`;
9
+ for a PR, `workit pr status --json` for checks and unresolved threads.
10
+ 2. Read the intent: brief or acceptance criteria, spec, PR body, and
11
+ `workit ledger list --type decision`.
12
+ 3. Judge two axes separately: spec fidelity (missing, creep, wrong; quote the
13
+ line) and standards (repo rules first, then smells). Then test quality
14
+ (`workit test-audit --diff`) and blast radius: one fact plus one proof per
15
+ touched contract or caller, run with `workit check -- <cmd>`; label anything
16
+ unproven UNPROVEN.
17
+ 4. Each finding: file:line, severity (blocker, major, minor, nit), evidence
18
+ (hunk, test or command output), concrete fix.
19
+ 5. Record the verdict:
20
+ `workit ledger verdict verified|failed|blocked --kind review --branch <b> --session <id> --how "<what you read and ran>"`,
21
+ with the session the SubagentStart hook gave you
22
+ (`verified` with `--kind review`: no blocker or major finding left).
23
+ Record a design choice you had to make as `workit ledger ruling`.
24
+
25
+ Stay read-only: read and test commands only, never commits, pushes, merges or
26
+ edits. If the ledger refuses you as an author, report that instead of a verdict.
27
+
28
+ Codex runs you in a read-only sandbox. `workit check` and `workit ledger verdict` write outside it: run them with escalated permissions (Codex asks the user). If escalation is refused or unavailable, record nothing and report the verdict you would record as blocked.
29
+ '''
@@ -0,0 +1,35 @@
1
+ # Generated by Workit from packages/workit-claude-code/agents/verifier.md; edits are overwritten on the next plugin start.
2
+ name = "workit-verifier"
3
+ description = "Independently verifies a workit candidate (branch, commit or PR) on its real surface and records a SHA-keyed verdict in the ledger. Use after an implementer finishes and before shipping, never on work this session authored."
4
+ sandbox_mode = "read-only"
5
+ developer_instructions = '''You are the workit verifier. You did not write the candidate and you never
6
+ change it: you observe, judge and record. Start from the goal and work
7
+ backward: what must be true, what must exist, what must be wired. The author's
8
+ summary is a claim, not evidence; assume the goal is not met until you observe
9
+ it.
10
+
11
+ 1. Pin the candidate in its own checkout (`cd` into the worker's worktree, or
12
+ pass `--cwd`): `git rev-parse HEAD` and `git status --short`. A dirty tree
13
+ or a moving HEAD is itself a finding, and the ledger refuses a verdict on it.
14
+ 2. Read the brief: goal, acceptance (Given/When/Then), verify commands.
15
+ 3. Run every verify command through the CLI so the result is observed:
16
+ `workit check <name>` for configured checks, `workit check -- <cmd>` for the
17
+ rest. Never substitute an easier command.
18
+ 4. Drive the real surface with the project's `verify-<app>` skill when it
19
+ exists (`$workit-verify-app` generates one). Tests alone are unit evidence.
20
+ 5. Judge each acceptance line as met, not met, or not verifiable, citing what
21
+ you observed. Label every claim measured, inferred or guess.
22
+ 6. Record the verdict, then report it:
23
+ `workit ledger verdict verified|tests-verified|type-check-only|failed|blocked --branch <b> --kind live|unit --session <id> --how "<what you ran and saw>"`,
24
+ with the session the SubagentStart hook gave you (you share the lead's
25
+ `WORKIT_SESSION_ID`, which authored the work).
26
+ `verified` means the change was observed working on its real surface
27
+ (verify-<app>, `--kind live`); `tests-verified` means only tests ran. If the ledger refuses you as an author, report that;
28
+ never pass `--self` to get around it.
29
+
30
+ Report: candidate SHA, each check with its exit code, each acceptance line,
31
+ the verdict row you recorded. Do not fix anything you find: a failing check is
32
+ a verdict, not a task.
33
+
34
+ Codex runs you in a read-only sandbox. `workit check` and `workit ledger verdict` write outside it: run them with escalated permissions (Codex asks the user). If escalation is refused or unavailable, record nothing and report the verdict you would record as blocked.
35
+ '''
@@ -6621,8 +6621,9 @@ var require_dist = __commonJS(function(exports, module) {
6621
6621
  });
6622
6622
 
6623
6623
  // packages/workit-codex/scripts/launch-mcp.ts
6624
- import { existsSync as existsSync9, realpathSync as realpathSync7, statSync as statSync3 } from "node:fs";
6625
- import path21 from "node:path";
6624
+ import { existsSync as existsSync10, realpathSync as realpathSync7, statSync as statSync3 } from "node:fs";
6625
+ import path22 from "node:path";
6626
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
6626
6627
 
6627
6628
  // packages/workit-core/src/core.ts
6628
6629
  import { spawnSync as spawnSync14 } from "node:child_process";
@@ -28197,6 +28198,110 @@ var codexCapabilities = (host, availability = {}) => capabilitiesFor(codexDescri
28197
28198
  if (false)
28198
28199
  ;
28199
28200
 
28201
+ // packages/workit-codex/scripts/agents.ts
28202
+ import {
28203
+ existsSync as existsSync9,
28204
+ lstatSync as lstatSync3,
28205
+ mkdirSync as mkdirSync3,
28206
+ readdirSync as readdirSync5,
28207
+ readFileSync as readFileSync7,
28208
+ renameSync as renameSync2,
28209
+ rmSync as rmSync2,
28210
+ writeFileSync as writeFileSync3
28211
+ } from "node:fs";
28212
+ import os5 from "node:os";
28213
+ import path21 from "node:path";
28214
+ var CODEX_AGENT_MARKER = "# Generated by Workit";
28215
+ var codexHomeOfInstall = (pluginRoot) => {
28216
+ const parts = path21.resolve(pluginRoot).split(path21.sep);
28217
+ const cache = parts.length - 4;
28218
+ return cache >= 2 && parts[cache] === "cache" && parts[cache - 1] === "plugins" ? parts.slice(0, cache - 1).join(path21.sep) || path21.sep : null;
28219
+ };
28220
+ var codexHomeFor = (pluginRoot, env) => codexHomeOfInstall(pluginRoot) ?? (env.CODEX_HOME || path21.join(env.HOME || os5.homedir(), ".codex"));
28221
+ var MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
28222
+ var agentMarkerVersion = (text) => MARKER_VERSION.exec(text)?.[1] ?? null;
28223
+ var stampCodexAgent = (content, version) => version && content.startsWith(CODEX_AGENT_MARKER) && !agentMarkerVersion(content) ? `${CODEX_AGENT_MARKER} ${version}${content.slice(CODEX_AGENT_MARKER.length)}` : content;
28224
+ var versionAtLeast = (version, min) => {
28225
+ const a = version.split(".").map(Number);
28226
+ const b = min.split(".").map(Number);
28227
+ for (let i = 0;i < 3; i++)
28228
+ if (a[i] !== b[i])
28229
+ return a[i] > b[i];
28230
+ return true;
28231
+ };
28232
+ var pluginVersion = (pluginRoot) => {
28233
+ try {
28234
+ const version = JSON.parse(readFileSync7(path21.join(pluginRoot, "package.json"), "utf8")).version;
28235
+ return typeof version === "string" && /^\d+\.\d+\.\d+/.test(version) ? version.match(/^\d+\.\d+\.\d+/)[0] : null;
28236
+ } catch {
28237
+ return null;
28238
+ }
28239
+ };
28240
+ var lstatOrNull = (file) => {
28241
+ try {
28242
+ return lstatSync3(file);
28243
+ } catch {
28244
+ return null;
28245
+ }
28246
+ };
28247
+ var installCodexAgents = (pluginRoot, codexHome) => {
28248
+ const source = path21.join(pluginRoot, "agents");
28249
+ if (!existsSync9(source))
28250
+ return [];
28251
+ const version = pluginVersion(pluginRoot);
28252
+ const target = path21.join(codexHome, "agents");
28253
+ const results = [];
28254
+ for (const file of readdirSync5(source).filter((name) => name.endsWith(".toml")).toSorted()) {
28255
+ const content = stampCodexAgent(readFileSync7(path21.join(source, file), "utf8"), version);
28256
+ const dest = path21.join(target, file);
28257
+ const stat = lstatOrNull(dest);
28258
+ if (stat?.isSymbolicLink()) {
28259
+ results.push({ file: dest, action: "skipped-symlink" });
28260
+ continue;
28261
+ }
28262
+ if (!stat) {
28263
+ mkdirSync3(target, { recursive: true });
28264
+ try {
28265
+ writeFileSync3(dest, content, { flag: "wx" });
28266
+ results.push({ file: dest, action: "installed" });
28267
+ } catch (error) {
28268
+ if (error.code !== "EEXIST")
28269
+ throw error;
28270
+ results.push({ file: dest, action: "kept-user-file" });
28271
+ }
28272
+ continue;
28273
+ }
28274
+ if (!stat.isFile()) {
28275
+ results.push({ file: dest, action: "kept-user-file" });
28276
+ continue;
28277
+ }
28278
+ const current = readFileSync7(dest, "utf8");
28279
+ if (current === content) {
28280
+ results.push({ file: dest, action: "current" });
28281
+ continue;
28282
+ }
28283
+ if (!current.startsWith(CODEX_AGENT_MARKER)) {
28284
+ results.push({ file: dest, action: "kept-user-file" });
28285
+ continue;
28286
+ }
28287
+ const written = agentMarkerVersion(current);
28288
+ if (written && (!version || !versionAtLeast(version, written))) {
28289
+ results.push({ file: dest, action: "kept-newer-version" });
28290
+ continue;
28291
+ }
28292
+ const temp = path21.join(target, `.${file}.${process.pid}.${Date.now()}.tmp`);
28293
+ writeFileSync3(temp, content, { flag: "wx" });
28294
+ try {
28295
+ renameSync2(temp, dest);
28296
+ } catch (error) {
28297
+ rmSync2(temp, { force: true });
28298
+ throw error;
28299
+ }
28300
+ results.push({ file: dest, action: "updated" });
28301
+ }
28302
+ return results;
28303
+ };
28304
+
28200
28305
  // packages/workit-codex/scripts/launch-mcp.ts
28201
28306
  var codexQualification = (host) => host === "codex_cli" ? { surface: host, cli: SUPPORT_MATRIX.codex.cli } : {
28202
28307
  surface: host,
@@ -28206,8 +28311,8 @@ var codexQualification = (host) => host === "codex_cli" ? { surface: host, cli:
28206
28311
  var resolveCodexWorkspaceRoot = (pluginRoot, env) => {
28207
28312
  const explicit = env.WORKFLOW_WORKSPACE_ROOT;
28208
28313
  const inherited = env.PWD;
28209
- const candidate = explicit ?? (inherited && path21.resolve(inherited) !== path21.resolve(pluginRoot) ? inherited : undefined);
28210
- if (!candidate || !path21.isAbsolute(candidate) || !existsSync9(candidate))
28314
+ const candidate = explicit ?? (inherited && path22.resolve(inherited) !== path22.resolve(pluginRoot) ? inherited : undefined);
28315
+ if (!candidate || !path22.isAbsolute(candidate) || !existsSync10(candidate))
28211
28316
  return null;
28212
28317
  try {
28213
28318
  if (!statSync3(candidate).isDirectory())
@@ -28246,10 +28351,33 @@ var codexContextProvider = (host = detectCodexSurface(process.env), root) => ({
28246
28351
  };
28247
28352
  }
28248
28353
  });
28249
- if (__require.main == __require.module)
28354
+ var pluginRoot = () => path22.resolve(path22.dirname(fileURLToPath3(import.meta.url)), "..");
28355
+ var syncCodexAgents = (root) => {
28356
+ const codexHome = codexHomeOfInstall(root);
28357
+ if (!codexHome)
28358
+ return;
28359
+ try {
28360
+ installCodexAgents(root, codexHome);
28361
+ } catch {}
28362
+ };
28363
+ if (__require.main == __require.module) {
28364
+ if (process.argv.includes("--install-agents")) {
28365
+ const root = pluginRoot();
28366
+ const results = installCodexAgents(root, codexHomeFor(root, process.env));
28367
+ for (const r of results)
28368
+ process.stdout.write(`${r.action} ${r.file}
28369
+ `);
28370
+ if (results.length === 0)
28371
+ process.stdout.write(`no agents bundled in ${root}
28372
+ `);
28373
+ process.exit(0);
28374
+ }
28375
+ syncCodexAgents(pluginRoot());
28250
28376
  await runStdioServer(detectCodexSurface(process.env), codexContextProvider());
28377
+ }
28251
28378
  export {
28252
28379
  codexContextProvider,
28253
28380
  codexQualification,
28254
- resolveCodexWorkspaceRoot
28381
+ resolveCodexWorkspaceRoot,
28382
+ syncCodexAgents
28255
28383
  };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-codex",
3
- "version": "8.6.1",
3
+ "version": "8.7.0",
4
4
  "private": false,
5
- "description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, and sixteen method skills",
5
+ "description": "Workit Codex CLI/desktop plugin — shared MCP transport, hooks, method skills, and verifier/reviewer/implementer agents",
6
6
  "keywords": [
7
7
  "agentic-coding",
8
8
  "ai-agents",
@@ -27,7 +27,8 @@
27
27
  ".codex-plugin/",
28
28
  ".mcp.json",
29
29
  "hooks/hooks.json",
30
- "skills/"
30
+ "skills/",
31
+ "agents/"
31
32
  ],
32
33
  "type": "module",
33
34
  "main": "./dist/launch-mcp.js",
@@ -38,8 +39,8 @@
38
39
  "build": "bun scripts/build.ts"
39
40
  },
40
41
  "dependencies": {
41
- "@brainervirus/workit-core": "^8.6.1",
42
- "@brainervirus/workit-mcp": "^8.6.1"
42
+ "@brainervirus/workit-core": "^8.7.0",
43
+ "@brainervirus/workit-mcp": "^8.7.0"
43
44
  },
44
45
  "engines": {
45
46
  "node": ">=24"