jorgex-stack 1.0.30 → 1.0.31

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/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import * as p6 from "@clack/prompts";
5
5
  import { pathToFileURL as pathToFileURL2 } from "url";
6
6
 
7
7
  // src/install.ts
8
- import fs14 from "fs";
8
+ import fs13 from "fs";
9
9
  import path19 from "path";
10
10
  import * as p from "@clack/prompts";
11
11
 
@@ -546,8 +546,6 @@ var opencodeAdapter = {
546
546
  ${deny}`);
547
547
  }
548
548
  if (!agent.spawn) lines.push(" task: deny");
549
- lines.push("tools:");
550
- lines.push(` write: ${agent.readonly ? "false" : "true"}`);
551
549
  }
552
550
  return [
553
551
  {
@@ -803,16 +801,7 @@ description: ${yamlString2(agent.description)}
803
801
  keep-coding-instructions: true
804
802
  ---
805
803
  ${agent.body}`;
806
- const skillDescription = `${agent.description} Invoke to switch into ${agent.name} mode and apply its flow to the current task.`;
807
- const skill = `---
808
- name: ${agent.name}
809
- description: ${yamlString2(skillDescription)}
810
- ---
811
- ${agent.body}`;
812
- return [
813
- { file: `${agent.name}.md`, content: style, kind: "output-style" },
814
- { file: `${agent.name}/SKILL.md`, content: skill, kind: "skill" }
815
- ];
804
+ return [{ file: `${agent.name}.md`, content: style, kind: "output-style" }];
816
805
  }
817
806
  const lines = [`name: ${agent.name}`, `description: ${yamlString2(agent.description)}`];
818
807
  const tools = toolsFor(agent);
@@ -995,16 +984,7 @@ var codexAdapter = {
995
984
  `# Uso: codex --profile ${agent.name}`,
996
985
  `developer_instructions = ${tomlMultiline(agent.body)}`
997
986
  ];
998
- const skillDescription = `${agent.description} Invoke to switch into ${agent.name} mode and apply its flow to the current task.`;
999
- const skill = `---
1000
- name: ${agent.name}
1001
- description: ${JSON.stringify(skillDescription)}
1002
- ---
1003
- ${agent.body}`;
1004
- return [
1005
- { file: `${agent.name}.config.toml`, content: profileLines.join("\n") + "\n", kind: "profile" },
1006
- { file: `${agent.name}/SKILL.md`, content: skill, kind: "skill" }
1007
- ];
987
+ return [{ file: `${agent.name}.config.toml`, content: profileLines.join("\n") + "\n", kind: "profile" }];
1008
988
  }
1009
989
  const lines = [
1010
990
  `name = ${tomlString(agent.name)}`,
@@ -1379,13 +1359,6 @@ import path13 from "path";
1379
1359
  var PROGRAMMATIC_ROOT = ["modes", "programmatic"];
1380
1360
  var PROGRAMMATIC_MARKER = "<!-- jorgex:programmatic-mode -->";
1381
1361
  var LEGACY_RESULT_CONTRACT_SECTION = /\n?##\s+Result contract[\s\S]*$/;
1382
- var LEGACY_SKILL_DELEGATION_SECTION = /\n?##\s+Formato obligatorio[\s\S]*$/;
1383
- var LEGACY_DELEGATION_LINE = /- For each `→ \[agent\]: \.\.\.` line, launch the corresponding specialist\./;
1384
- var LEGACY_PROGRAMMATIC_PHRASES = [
1385
- [/\bResult contract\b/g, "strict JSON handoff"],
1386
- [/Status \/ Delegations \/ Risks/g, "status, delegations, and risks"],
1387
- [LEGACY_DELEGATION_LINE, "- Process the JSON `delegations[]` array and launch the corresponding specialist."]
1388
- ];
1389
1362
  var normalize = (value) => value.replace(/\r\n/g, "\n");
1390
1363
  function loadProgrammaticAddendum(stackDir, fileName) {
1391
1364
  return normalize(fs9.readFileSync(path13.join(stackDir, ...PROGRAMMATIC_ROOT, fileName), "utf8")).trim();
@@ -1399,10 +1372,7 @@ ${addendum}
1399
1372
  `;
1400
1373
  }
1401
1374
  function stripLegacyResultContract(body) {
1402
- return LEGACY_PROGRAMMATIC_PHRASES.reduce(
1403
- (text2, [pattern, replacement]) => text2.replace(pattern, replacement),
1404
- normalize(body).replace(LEGACY_RESULT_CONTRACT_SECTION, "")
1405
- ).trimEnd();
1375
+ return normalize(body).replace(LEGACY_RESULT_CONTRACT_SECTION, "").replace(/\bResult contract\b/g, "strict JSON handoff").trimEnd();
1406
1376
  }
1407
1377
  function concurrencyRule(concurrency) {
1408
1378
  if (concurrency === "parallel") {
@@ -1422,22 +1392,13 @@ function composeProgrammaticSystemPrompt(stackDir, content, mode) {
1422
1392
  }
1423
1393
  function composeProgrammaticAgentBody(stackDir, agent, mode, concurrency) {
1424
1394
  if (mode !== "programmatic") return normalize(agent.body);
1425
- const fileName = agent.mode === "primary" ? "orchestrator.addendum.md" : "subagent.addendum.md";
1426
- let addendum = loadProgrammaticAddendum(stackDir, fileName);
1427
1395
  if (agent.mode === "primary") {
1428
- addendum = addendum.replace("{{CONCURRENCY_RULE}}", concurrencyRule(concurrency ?? "serial"));
1396
+ const addendum2 = loadProgrammaticAddendum(stackDir, "orchestrator.addendum.md").replace("{{CONCURRENCY_RULE}}", concurrencyRule(concurrency ?? "serial"));
1397
+ return appendAddendum(agent.body, addendum2);
1429
1398
  }
1399
+ const addendum = loadProgrammaticAddendum(stackDir, "subagent.addendum.md");
1430
1400
  return appendAddendum(stripLegacyResultContract(agent.body), addendum);
1431
1401
  }
1432
- function composeProgrammaticSkillBody(stackDir, skillPath, content, mode) {
1433
- if (mode !== "programmatic") return normalize(content);
1434
- if (skillPath !== path13.join("agent-delegation", "SKILL.md")) return normalize(content);
1435
- const base = normalize(content).replace(
1436
- "Las delegaciones van **en tu output final**, en el formato de abajo. El orquestador las lee y decide a qui\xE9n invocar.",
1437
- "Las delegaciones van como strings en el JSON final `delegations[]`. El orquestador las lee y decide a qui\xE9n invocar."
1438
- ).replace(LEGACY_SKILL_DELEGATION_SECTION, "").trimEnd();
1439
- return appendAddendum(base, loadProgrammaticAddendum(stackDir, "agent-delegation.addendum.md"));
1440
- }
1441
1402
 
1442
1403
  // src/components/system-prompt.ts
1443
1404
  var normalize2 = (s) => s.replace(/\r\n/g, "\n");
@@ -1461,12 +1422,11 @@ function planSystemPrompt(adapter, ctx) {
1461
1422
  // src/components/agents.ts
1462
1423
  import path15 from "path";
1463
1424
  function planAgents(adapter, ctx) {
1464
- const { agentsDir, commandsDir, outputStylesDir, skillsDir, profilesDir, scriptsDir } = adapter.paths(ctx.configDir);
1425
+ const { agentsDir, commandsDir, outputStylesDir, profilesDir, scriptsDir } = adapter.paths(ctx.configDir);
1465
1426
  const dirFor = {
1466
1427
  agent: agentsDir,
1467
1428
  command: commandsDir,
1468
1429
  "output-style": outputStylesDir,
1469
- skill: skillsDir,
1470
1430
  profile: profilesDir
1471
1431
  };
1472
1432
  const scriptsBase = scriptsDir.replace(/\\/g, "/");
@@ -1489,43 +1449,35 @@ function planAgents(adapter, ctx) {
1489
1449
 
1490
1450
  // src/components/skills.ts
1491
1451
  import path16 from "path";
1492
- import fs11 from "fs";
1493
1452
  function planSkills(adapter, ctx) {
1494
1453
  const { skillsDir } = adapter.paths(ctx.configDir);
1495
1454
  const source = path16.join(ctx.stackDir, "skills");
1496
1455
  return listFilesRecursive(source).map((file) => {
1497
1456
  const relative = path16.relative(source, file);
1498
- if (relative === path16.join("agent-delegation", "SKILL.md") && ctx.mode === "programmatic") {
1499
- return {
1500
- kind: "write",
1501
- target: path16.join(skillsDir, relative),
1502
- content: composeProgrammaticSkillBody(ctx.stackDir, relative, fs11.readFileSync(file, "utf8"), ctx.mode)
1503
- };
1504
- }
1505
1457
  return { kind: "copy", source: file, target: path16.join(skillsDir, relative) };
1506
1458
  });
1507
1459
  }
1508
1460
 
1509
1461
  // src/components/commands.ts
1510
1462
  import path17 from "path";
1511
- import fs12 from "fs";
1463
+ import fs11 from "fs";
1512
1464
  function planCommands(adapter, ctx) {
1513
1465
  const { commandsDir } = adapter.paths(ctx.configDir);
1514
1466
  const source = path17.join(ctx.stackDir, "commands");
1515
- if (!fs12.existsSync(source)) return [];
1467
+ if (!fs11.existsSync(source)) return [];
1516
1468
  const commandFiles = [
1517
1469
  ...listMarkdownFiles(source),
1518
1470
  ...listMarkdownFiles(path17.join(source, adapter.id))
1519
1471
  ];
1520
1472
  return commandFiles.map(({ file, fullPath }) => {
1521
- const raw = fs12.readFileSync(fullPath, "utf8").replace(/\r\n/g, "\n");
1473
+ const raw = fs11.readFileSync(fullPath, "utf8").replace(/\r\n/g, "\n");
1522
1474
  const rendered = adapter.renderCommand(file, raw);
1523
1475
  return { kind: "write", target: path17.join(commandsDir, rendered.file), content: rendered.content };
1524
1476
  });
1525
1477
  }
1526
1478
  function listMarkdownFiles(dir) {
1527
- if (!fs12.existsSync(dir)) return [];
1528
- return fs12.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => ({ file: entry.name, fullPath: path17.join(dir, entry.name) }));
1479
+ if (!fs11.existsSync(dir)) return [];
1480
+ return fs11.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => ({ file: entry.name, fullPath: path17.join(dir, entry.name) }));
1529
1481
  }
1530
1482
 
1531
1483
  // src/components/hooks.ts
@@ -1540,22 +1492,22 @@ function planMcp(adapter, ctx) {
1540
1492
 
1541
1493
  // src/components/plugins.ts
1542
1494
  import path18 from "path";
1543
- import fs13 from "fs";
1495
+ import fs12 from "fs";
1544
1496
  function planPlugins(adapter, ctx) {
1545
1497
  const { pluginsDir } = adapter.paths(ctx.configDir);
1546
1498
  if (pluginsDir === null) return [];
1547
1499
  const source = path18.join(ctx.stackDir, "plugins", adapter.id);
1548
- if (!fs13.existsSync(source)) return [];
1500
+ if (!fs12.existsSync(source)) return [];
1549
1501
  return listFilesRecursive(source).filter((f) => f.endsWith(".ts")).map((sourceFile) => {
1550
1502
  const target = path18.join(pluginsDir, path18.relative(source, sourceFile));
1551
- const raw = fs13.readFileSync(sourceFile, "utf8");
1503
+ const raw = fs12.readFileSync(sourceFile, "utf8");
1552
1504
  let content = raw;
1553
1505
  if (content.includes('"{{ENGRAM_BIN}}"')) {
1554
1506
  content = content.replace(/"\{\{ENGRAM_BIN\}\}"/g, JSON.stringify(ctx.engramBin ?? "engram"));
1555
1507
  }
1556
1508
  if (content.includes('"{{ENGRAM_PROTOCOL}}"')) {
1557
1509
  const protocol = stripLeadingHtmlComments(
1558
- fs13.readFileSync(path18.join(ctx.stackDir, "system-prompt", "engram-protocol.md"), "utf8").replace(/\r\n/g, "\n")
1510
+ fs12.readFileSync(path18.join(ctx.stackDir, "system-prompt", "engram-protocol.md"), "utf8").replace(/\r\n/g, "\n")
1559
1511
  );
1560
1512
  content = content.replace(/"\{\{ENGRAM_PROTOCOL\}\}"/g, JSON.stringify(protocol));
1561
1513
  }
@@ -1602,7 +1554,7 @@ function diffPlan(plan) {
1602
1554
  if (current === null) return { action, status: "create" };
1603
1555
  return { action, status: current === action.content ? "unchanged" : "update" };
1604
1556
  }
1605
- if (!fs14.existsSync(action.target)) return { action, status: "create" };
1557
+ if (!fs13.existsSync(action.target)) return { action, status: "create" };
1606
1558
  return { action, status: sameFileContent(action.source, action.target) ? "unchanged" : "update" };
1607
1559
  });
1608
1560
  }
@@ -1734,7 +1686,7 @@ async function runInstall(opts) {
1734
1686
  applyChanges(changes);
1735
1687
  const pruneRoot = useManifest ? HOME : path19.dirname(configDir);
1736
1688
  for (const orphan of orphans) {
1737
- fs14.rmSync(orphan, { force: true });
1689
+ fs13.rmSync(orphan, { force: true });
1738
1690
  pruneEmptyDirs(orphan, pruneRoot);
1739
1691
  }
1740
1692
  const verifyCtx = { ...ctx, warnings: [] };
@@ -1757,7 +1709,7 @@ async function runInstall(opts) {
1757
1709
  }
1758
1710
 
1759
1711
  // src/uninstall.ts
1760
- import fs15 from "fs";
1712
+ import fs14 from "fs";
1761
1713
  import path20 from "path";
1762
1714
  import * as p2 from "@clack/prompts";
1763
1715
  async function runUninstall(opts) {
@@ -1812,7 +1764,7 @@ async function runUninstall(opts) {
1812
1764
  const pruneRoot = usingRealConfig ? HOME : path20.dirname(configDir);
1813
1765
  const planTargets = [
1814
1766
  .../* @__PURE__ */ new Set([...buildPlan(adapter, ctx).map((a) => path20.resolve(a.target)), ...prevOwned.map((t) => path20.resolve(t))])
1815
- ].filter((t) => !mergedTargets.has(t) && fs15.existsSync(t));
1767
+ ].filter((t) => !mergedTargets.has(t) && fs14.existsSync(t));
1816
1768
  const deleteTargets = planTargets.filter(
1817
1769
  (t) => !retained.has(t) && !(ctx.preserveEngram && path20.basename(t) === "engram.ts") && isContainedIn(t, pruneRoot)
1818
1770
  );
@@ -1822,18 +1774,18 @@ async function runUninstall(opts) {
1822
1774
  if (sharedKept > 0) p2.log.info(`${sharedKept} archivos se conservan: otros runtimes instalados los siguen usando.`);
1823
1775
  if (opts.dryRun) continue;
1824
1776
  const backup = createBackup(
1825
- [...deleteTargets, ...unmerge.map((a) => a.target).filter((t) => fs15.existsSync(t))],
1777
+ [...deleteTargets, ...unmerge.map((a) => a.target).filter((t) => fs14.existsSync(t))],
1826
1778
  `uninstall-${id}`
1827
1779
  );
1828
1780
  if (backup) p2.log.info(`Backup: ${backup.id} (${backup.files.length} archivos)`);
1829
1781
  for (const target of deleteTargets) {
1830
- fs15.rmSync(target, { force: true });
1782
+ fs14.rmSync(target, { force: true });
1831
1783
  pruneEmptyDirs(target, pruneRoot);
1832
1784
  }
1833
1785
  for (const action of unmerge) {
1834
1786
  if (action.kind !== "write") continue;
1835
1787
  if (action.content.trim() === "") {
1836
- fs15.rmSync(action.target, { force: true });
1788
+ fs14.rmSync(action.target, { force: true });
1837
1789
  } else {
1838
1790
  writeText(action.target, action.content);
1839
1791
  }
@@ -1847,7 +1799,7 @@ async function runUninstall(opts) {
1847
1799
 
1848
1800
  // src/doctor.ts
1849
1801
  import path21 from "path";
1850
- import fs16 from "fs";
1802
+ import fs15 from "fs";
1851
1803
  import * as p3 from "@clack/prompts";
1852
1804
  function engramVersion(bin) {
1853
1805
  const out = runDetectedBin(bin, ["--version"], 5e3);
@@ -1880,11 +1832,11 @@ async function runDoctor() {
1880
1832
  }
1881
1833
  const engramDataDir = process.env.ENGRAM_DATA_DIR ?? path21.join(HOME, ".engram");
1882
1834
  const engramDb = path21.join(engramDataDir, "engram.db");
1883
- if (fs16.existsSync(engramDb)) {
1884
- const sizeMb = (fs16.statSync(engramDb).size / 1024 / 1024).toFixed(1);
1835
+ if (fs15.existsSync(engramDb)) {
1836
+ const sizeMb = (fs15.statSync(engramDb).size / 1024 / 1024).toFixed(1);
1885
1837
  p3.log.info(`Engram DB: ${engramDb} (${sizeMb} MB de memorias \u2014 el stack no la toca JAM\xC1S).`);
1886
1838
  }
1887
- if (!fs16.existsSync(modelMapFile())) p3.log.info("model-map: a\xFAn no creado (se crea en el primer install o con 'models').");
1839
+ if (!fs15.existsSync(modelMapFile())) p3.log.info("model-map: a\xFAn no creado (se crea en el primer install o con 'models').");
1888
1840
  const manifest = readManifest();
1889
1841
  const modePreference = loadInstallModePreference();
1890
1842
  const current = collectAllCurrentTargets(modePreference);
@@ -1923,10 +1875,10 @@ async function runDoctor() {
1923
1875
  p3.log.warn(`${adapter.name}: ${orphans.length} archivos hu\xE9rfanos de versiones previas \u2192 ejecuta 'sync'.`);
1924
1876
  problems++;
1925
1877
  }
1926
- if (adapter.id === "codex" && fs16.existsSync(path21.join(detection.configDir, "hooks.json"))) {
1878
+ if (adapter.id === "codex" && fs15.existsSync(path21.join(detection.configDir, "hooks.json"))) {
1927
1879
  p3.log.info("Codex: recuerda que los hooks requieren aprobaci\xF3n manual \u2014 verifica con /hooks dentro de codex.");
1928
1880
  }
1929
- if (adapter.id === "codex" && fs16.existsSync(path21.join(detection.configDir, "AGENTS.override.md"))) {
1881
+ if (adapter.id === "codex" && fs15.existsSync(path21.join(detection.configDir, "AGENTS.override.md"))) {
1930
1882
  p3.log.warn(
1931
1883
  "Codex: existe ~/.codex/AGENTS.override.md \u2014 tiene prioridad ABSOLUTA y tapa el AGENTS.md gestionado por el stack."
1932
1884
  );
@@ -1940,14 +1892,14 @@ async function runDoctor() {
1940
1892
  }
1941
1893
 
1942
1894
  // src/update.ts
1943
- import fs19 from "fs";
1895
+ import fs18 from "fs";
1944
1896
  import path24 from "path";
1945
1897
  import os3 from "os";
1946
1898
  import { execFileSync as execFileSync4 } from "child_process";
1947
1899
  import * as p4 from "@clack/prompts";
1948
1900
 
1949
1901
  // src/lib/github.ts
1950
- import fs17 from "fs";
1902
+ import fs16 from "fs";
1951
1903
  import path22 from "path";
1952
1904
  import { execFileSync as execFileSync2 } from "child_process";
1953
1905
  import os2 from "os";
@@ -2022,7 +1974,7 @@ function validateExtractedTree(destDir) {
2022
1974
  const walk = (dir) => {
2023
1975
  let entries;
2024
1976
  try {
2025
- entries = fs17.readdirSync(dir, { withFileTypes: true });
1977
+ entries = fs16.readdirSync(dir, { withFileTypes: true });
2026
1978
  } catch {
2027
1979
  return false;
2028
1980
  }
@@ -2030,7 +1982,7 @@ function validateExtractedTree(destDir) {
2030
1982
  const full = path22.join(dir, entry.name);
2031
1983
  let stat;
2032
1984
  try {
2033
- stat = fs17.lstatSync(full);
1985
+ stat = fs16.lstatSync(full);
2034
1986
  } catch {
2035
1987
  return false;
2036
1988
  }
@@ -2047,14 +1999,14 @@ function validateExtractedTree(destDir) {
2047
1999
  function resolveTarBin() {
2048
2000
  if (process.platform !== "win32") return "tar";
2049
2001
  const winTar = path22.join(process.env["SystemRoot"] ?? "C:\\Windows", "System32", "tar.exe");
2050
- return fs17.existsSync(winTar) ? winTar : "tar";
2002
+ return fs16.existsSync(winTar) ? winTar : "tar";
2051
2003
  }
2052
2004
  async function downloadRepoTarball(repo, sha, destDir, validateSubdir) {
2053
2005
  const url = `https://codeload.github.com/${repo}/tar.gz/${sha}`;
2054
2006
  const tmp = path22.join(os2.tmpdir(), `jorgex-tarball-${Date.now()}.tar.gz`);
2055
2007
  const fail = (reason) => {
2056
2008
  try {
2057
- fs17.rmSync(destDir, { recursive: true, force: true });
2009
+ fs16.rmSync(destDir, { recursive: true, force: true });
2058
2010
  } catch {
2059
2011
  }
2060
2012
  return { ok: false, reason };
@@ -2073,10 +2025,10 @@ async function downloadRepoTarball(repo, sha, destDir, validateSubdir) {
2073
2025
  if (!res.body) return fail("respuesta HTTP sin cuerpo");
2074
2026
  await pipeline(
2075
2027
  Readable.fromWeb(res.body),
2076
- fs17.createWriteStream(tmp)
2028
+ fs16.createWriteStream(tmp)
2077
2029
  );
2078
- fs17.rmSync(destDir, { recursive: true, force: true });
2079
- fs17.mkdirSync(destDir, { recursive: true });
2030
+ fs16.rmSync(destDir, { recursive: true, force: true });
2031
+ fs16.mkdirSync(destDir, { recursive: true });
2080
2032
  try {
2081
2033
  execFileSync2(resolveTarBin(), ["-xzf", tmp, "--strip-components=1", "-C", destDir], { stdio: "pipe" });
2082
2034
  } catch (err) {
@@ -2089,30 +2041,30 @@ async function downloadRepoTarball(repo, sha, destDir, validateSubdir) {
2089
2041
  if (validateRoot !== resolvedDest && !isContainedIn(validateRoot, resolvedDest)) {
2090
2042
  return fail(`la ruta de validaci\xF3n "${validateSubdir}" escapa del destino`);
2091
2043
  }
2092
- if (fs17.existsSync(validateRoot) && !validateExtractedTree(validateRoot)) {
2044
+ if (fs16.existsSync(validateRoot) && !validateExtractedTree(validateRoot)) {
2093
2045
  return fail("el \xE1rbol extra\xEDdo contiene symlinks o rutas fuera del destino");
2094
2046
  }
2095
- const validated = fs17.existsSync(validateRoot);
2047
+ const validated = fs16.existsSync(validateRoot);
2096
2048
  return { ok: true, validated };
2097
2049
  } catch (err) {
2098
2050
  const timedOut = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
2099
2051
  return fail(timedOut ? "timeout de descarga (120s)" : err instanceof Error ? `fallo de red: ${err.message}` : "error desconocido");
2100
2052
  } finally {
2101
2053
  try {
2102
- fs17.rmSync(tmp, { force: true });
2054
+ fs16.rmSync(tmp, { force: true });
2103
2055
  } catch {
2104
2056
  }
2105
2057
  }
2106
2058
  }
2107
2059
 
2108
2060
  // src/lib/skill-update.ts
2109
- import fs18 from "fs";
2061
+ import fs17 from "fs";
2110
2062
  import path23 from "path";
2111
2063
  import { execFileSync as execFileSync3 } from "child_process";
2112
2064
  var PROTECTED_SKILLS = /* @__PURE__ */ new Set(["agent-delegation", "work-lifecycle", "xreview"]);
2113
2065
  function sameTextContentNormalized(a, b) {
2114
- const ba = fs18.readFileSync(a);
2115
- const bb = fs18.readFileSync(b);
2066
+ const ba = fs17.readFileSync(a);
2067
+ const bb = fs17.readFileSync(b);
2116
2068
  if (ba.equals(bb)) return true;
2117
2069
  const sa = ba.toString("utf8").replace(/\r\n/g, "\n");
2118
2070
  const sb = bb.toString("utf8").replace(/\r\n/g, "\n");
@@ -2194,7 +2146,7 @@ function replaceSkill(name, upstreamSkillDir, newCommit, opts) {
2194
2146
  throw new Error(`La skill "${name}" es propia del stack y no se actualiza desde upstream.`);
2195
2147
  }
2196
2148
  const upstreamsFile = upstreamsFilePath ?? path23.join(path23.dirname(stackRoot()), "upstreams.json");
2197
- const raw = fs18.readFileSync(upstreamsFile, "utf8");
2149
+ const raw = fs17.readFileSync(upstreamsFile, "utf8");
2198
2150
  const data = JSON.parse(raw);
2199
2151
  const skillEntry = data?.skills?.[name];
2200
2152
  if (!skillEntry) {
@@ -2213,7 +2165,7 @@ function replaceSkill(name, upstreamSkillDir, newCommit, opts) {
2213
2165
  try {
2214
2166
  const upstreamFiles = listFilesRecursive(upstreamSkillDir);
2215
2167
  for (const src of upstreamFiles) {
2216
- const st = fs18.lstatSync(src);
2168
+ const st = fs17.lstatSync(src);
2217
2169
  if (st.isSymbolicLink()) {
2218
2170
  throw new Error(`Symlink rechazado en upstream de skill "${name}": ${src}`);
2219
2171
  }
@@ -2223,14 +2175,14 @@ function replaceSkill(name, upstreamSkillDir, newCommit, opts) {
2223
2175
  copyFile(src, dest);
2224
2176
  }
2225
2177
  const oldDir = `${localSkillDir}.old-${process.pid}`;
2226
- if (fs18.existsSync(localSkillDir)) {
2227
- fs18.renameSync(localSkillDir, oldDir);
2178
+ if (fs17.existsSync(localSkillDir)) {
2179
+ fs17.renameSync(localSkillDir, oldDir);
2228
2180
  }
2229
- fs18.renameSync(stagingDir, localSkillDir);
2230
- fs18.rmSync(oldDir, { recursive: true, force: true });
2181
+ fs17.renameSync(stagingDir, localSkillDir);
2182
+ fs17.rmSync(oldDir, { recursive: true, force: true });
2231
2183
  } catch (err) {
2232
2184
  try {
2233
- fs18.rmSync(stagingDir, { recursive: true, force: true });
2185
+ fs17.rmSync(stagingDir, { recursive: true, force: true });
2234
2186
  } catch {
2235
2187
  }
2236
2188
  throw err;
@@ -2245,7 +2197,7 @@ function rateLimitHint(prefix) {
2245
2197
  }
2246
2198
  function loadUpstreams() {
2247
2199
  const file = path24.join(path24.dirname(stackRoot()), "upstreams.json");
2248
- return JSON.parse(fs19.readFileSync(file, "utf8"));
2200
+ return JSON.parse(fs18.readFileSync(file, "utf8"));
2249
2201
  }
2250
2202
  function skillsToScan(maintainer, upstreams) {
2251
2203
  return maintainer ? Object.keys(upstreams.skills) : [];
@@ -2358,7 +2310,7 @@ function isEngramRunning() {
2358
2310
  }
2359
2311
  }
2360
2312
  function isGitClone(projectRoot = path24.dirname(stackRoot())) {
2361
- return fs19.existsSync(path24.join(projectRoot, ".git"));
2313
+ return fs18.existsSync(path24.join(projectRoot, ".git"));
2362
2314
  }
2363
2315
  var STACK_METHOD_CLONE = "git pull + pnpm install + pnpm build";
2364
2316
  function resolvePnpm() {
@@ -2368,7 +2320,7 @@ function resolvePnpm() {
2368
2320
  }
2369
2321
  function cleanupTmp(dir) {
2370
2322
  try {
2371
- fs19.rmSync(dir, { recursive: true, force: true });
2323
+ fs18.rmSync(dir, { recursive: true, force: true });
2372
2324
  } catch {
2373
2325
  }
2374
2326
  }
@@ -2390,7 +2342,7 @@ function updateStackGlobal() {
2390
2342
  execFileSync4(pnpm, ["add", "-g", "jorgex-stack@latest"], { stdio: "inherit" });
2391
2343
  }
2392
2344
  async function downloadSkillToTemp(repo, sha, skillPath) {
2393
- const root = fs19.mkdtempSync(path24.join(os3.tmpdir(), "jorgex-skill-"));
2345
+ const root = fs18.mkdtempSync(path24.join(os3.tmpdir(), "jorgex-skill-"));
2394
2346
  try {
2395
2347
  const result = await downloadRepoTarball(repo, sha, root, skillPath);
2396
2348
  if (!result.ok) {
@@ -2403,10 +2355,10 @@ async function downloadSkillToTemp(repo, sha, skillPath) {
2403
2355
  cleanupTmp(root);
2404
2356
  return { error: `la ruta "${skillPath}" escapa del directorio temporal` };
2405
2357
  }
2406
- if (fs19.existsSync(sub)) return { dir: sub, root };
2358
+ if (fs18.existsSync(sub)) return { dir: sub, root };
2407
2359
  const lastSeg = skillPath.split("/").pop();
2408
2360
  const sub2 = path24.resolve(path24.join(root, lastSeg));
2409
- if (isContainedIn(sub2, root) && fs19.existsSync(sub2)) {
2361
+ if (isContainedIn(sub2, root) && fs18.existsSync(sub2)) {
2410
2362
  if (!validateExtractedTree(sub2)) {
2411
2363
  cleanupTmp(root);
2412
2364
  return { error: `el sub\xE1rbol "${lastSeg}" contiene symlinks o rutas fuera del destino` };
@@ -2425,11 +2377,11 @@ async function downloadSkillToTemp(repo, sha, skillPath) {
2425
2377
  function pruneEngramDbBackups() {
2426
2378
  try {
2427
2379
  const dir = dataDir();
2428
- if (!fs19.existsSync(dir)) return;
2429
- const backups = fs19.readdirSync(dir).filter((f) => f.startsWith("engram-db-backup-") && f.endsWith(".db")).map((f) => ({ name: f, mtime: fs19.statSync(path24.join(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
2380
+ if (!fs18.existsSync(dir)) return;
2381
+ const backups = fs18.readdirSync(dir).filter((f) => f.startsWith("engram-db-backup-") && f.endsWith(".db")).map((f) => ({ name: f, mtime: fs18.statSync(path24.join(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
2430
2382
  for (const old of backups.slice(3)) {
2431
2383
  try {
2432
- fs19.rmSync(path24.join(dir, old.name));
2384
+ fs18.rmSync(path24.join(dir, old.name));
2433
2385
  } catch {
2434
2386
  }
2435
2387
  }
@@ -2437,7 +2389,7 @@ function pruneEngramDbBackups() {
2437
2389
  }
2438
2390
  }
2439
2391
  function rotateLockedBinary(binPath, sweepRoot = HOME) {
2440
- if (!fs19.existsSync(binPath)) return null;
2392
+ if (!fs18.existsSync(binPath)) return null;
2441
2393
  const dir = path24.dirname(binPath);
2442
2394
  const base = path24.basename(binPath);
2443
2395
  const escapedBase = base.replace(/[.*+?^$()|[\]{}\\]/g, "\\$&");
@@ -2445,10 +2397,10 @@ function rotateLockedBinary(binPath, sweepRoot = HOME) {
2445
2397
  const resolvedDir = path24.resolve(dir);
2446
2398
  if (resolvedDir === path24.resolve(sweepRoot) || isContainedIn(resolvedDir, sweepRoot)) {
2447
2399
  try {
2448
- for (const entry of fs19.readdirSync(dir)) {
2400
+ for (const entry of fs18.readdirSync(dir)) {
2449
2401
  if (oldPattern.test(entry)) {
2450
2402
  try {
2451
- fs19.rmSync(path24.join(dir, entry), { force: true });
2403
+ fs18.rmSync(path24.join(dir, entry), { force: true });
2452
2404
  } catch {
2453
2405
  }
2454
2406
  }
@@ -2457,7 +2409,7 @@ function rotateLockedBinary(binPath, sweepRoot = HOME) {
2457
2409
  }
2458
2410
  }
2459
2411
  const rotated = path24.join(dir, `${base}.old-${Date.now()}`);
2460
- fs19.renameSync(binPath, rotated);
2412
+ fs18.renameSync(binPath, rotated);
2461
2413
  return rotated;
2462
2414
  }
2463
2415
  async function updateEngram(engramRepo, latestVersion) {
@@ -2468,7 +2420,7 @@ async function updateEngram(engramRepo, latestVersion) {
2468
2420
  }
2469
2421
  const engramDataDir = process.env.ENGRAM_DATA_DIR ?? path24.join(HOME, ".engram");
2470
2422
  const engramDb = path24.join(engramDataDir, "engram.db");
2471
- if (fs19.existsSync(engramDb)) {
2423
+ if (fs18.existsSync(engramDb)) {
2472
2424
  const doBackup = await p4.confirm({
2473
2425
  message: `\xBFHacer backup de la DB de Engram antes de actualizar? (${engramDb})`,
2474
2426
  initialValue: true
@@ -2477,8 +2429,8 @@ async function updateEngram(engramRepo, latestVersion) {
2477
2429
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2478
2430
  const dest = path24.join(dataDir(), `engram-db-backup-${ts}.db`);
2479
2431
  try {
2480
- if (!fs19.existsSync(dataDir())) fs19.mkdirSync(dataDir(), { recursive: true });
2481
- fs19.copyFileSync(engramDb, dest);
2432
+ if (!fs18.existsSync(dataDir())) fs18.mkdirSync(dataDir(), { recursive: true });
2433
+ fs18.copyFileSync(engramDb, dest);
2482
2434
  p4.log.success(`DB respaldada en ${dest} (la DB original NO se modifica jam\xE1s).`);
2483
2435
  pruneEngramDbBackups();
2484
2436
  } catch (err) {
@@ -2528,10 +2480,10 @@ async function updateEngram(engramRepo, latestVersion) {
2528
2480
  ["install", `github.com/Gentleman-Programming/engram/cmd/engram@v${latestVersion}`],
2529
2481
  { stdio: "inherit" }
2530
2482
  );
2531
- const rollbackOk = resolveEngramRollback({ installOk: true, rotated, bin, binExists: fs19.existsSync(bin ?? "") });
2483
+ const rollbackOk = resolveEngramRollback({ installOk: true, rotated, bin, binExists: fs18.existsSync(bin ?? "") });
2532
2484
  if (rollbackOk.action === "restore") {
2533
2485
  try {
2534
- fs19.renameSync(rotated, bin);
2486
+ fs18.renameSync(rotated, bin);
2535
2487
  p4.log.warn(rollbackOk.messages.onRestore);
2536
2488
  } catch {
2537
2489
  p4.log.warn(rollbackOk.messages.onRenameFail);
@@ -2539,10 +2491,10 @@ async function updateEngram(engramRepo, latestVersion) {
2539
2491
  }
2540
2492
  return true;
2541
2493
  } catch (err) {
2542
- const rollbackFail = resolveEngramRollback({ installOk: false, rotated, bin, binExists: fs19.existsSync(bin ?? "") });
2494
+ const rollbackFail = resolveEngramRollback({ installOk: false, rotated, bin, binExists: fs18.existsSync(bin ?? "") });
2543
2495
  if (rollbackFail.action === "restore") {
2544
2496
  try {
2545
- fs19.renameSync(rotated, bin);
2497
+ fs18.renameSync(rotated, bin);
2546
2498
  p4.log.info(rollbackFail.messages.onRestore);
2547
2499
  } catch {
2548
2500
  p4.log.error(rollbackFail.messages.onRenameFail);
@@ -3063,7 +3015,7 @@ function cancelled() {
3063
3015
  }
3064
3016
 
3065
3017
  // src/lib/release.ts
3066
- import fs20 from "fs";
3018
+ import fs19 from "fs";
3067
3019
  import path26 from "path";
3068
3020
  import { execFileSync as execFileSync5 } from "child_process";
3069
3021
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -3071,7 +3023,7 @@ function findPackageJson() {
3071
3023
  let dir = path26.dirname(fileURLToPath2(import.meta.url));
3072
3024
  for (let i = 0; i < 6; i++) {
3073
3025
  const candidate = path26.join(dir, "package.json");
3074
- if (fs20.existsSync(candidate)) return candidate;
3026
+ if (fs19.existsSync(candidate)) return candidate;
3075
3027
  dir = path26.dirname(dir);
3076
3028
  }
3077
3029
  throw new Error("No se encontr\xF3 package.json cerca del CLI.");
@@ -3081,7 +3033,7 @@ function readPackageVersion() {
3081
3033
  }
3082
3034
  function readPackageMetadata() {
3083
3035
  const packageJson = findPackageJson();
3084
- const raw = fs20.readFileSync(packageJson, "utf8");
3036
+ const raw = fs19.readFileSync(packageJson, "utf8");
3085
3037
  const parsed = JSON.parse(raw);
3086
3038
  const name = typeof parsed.name === "string" ? parsed.name.trim() : "";
3087
3039
  const version = typeof parsed.version === "string" ? parsed.version.trim() : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jorgex-stack",
3
- "version": "1.0.30",
3
+ "version": "1.0.31",
4
4
  "description": "Harness multi-agente portable: instala la config JorgeX (agentes, skills, hooks, Engram, MCPs) en Claude Code, Codex CLI y OpenCode",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  # Agentes canónicos
2
2
 
3
- Una sola fuente por agente. El instalador los traduce al formato de cada runtime (PRD §6): Markdown+frontmatter para Claude Code y OpenCode, TOML para Codex.
3
+ Una sola fuente por agente. El instalador los traduce al formato de cada runtime (PRD §6): Markdown+frontmatter para Claude Code y OpenCode, TOML para Codex. El workflow completo del orchestrator vive únicamente en `skills/orchestrator/SKILL.md`; el agente primary es un wrapper corto que obliga a cargar esa skill.
4
4
 
5
5
  ## Frontmatter canónico
6
6
 
@@ -19,7 +19,7 @@ Una sola fuente por agente. El instalador los traduce al formato de cada runtime
19
19
  | Canónico | Claude Code | Codex | OpenCode |
20
20
  |---|---|---|---|
21
21
  | `tier` | alias `fable`/`opus`/`sonnet`/`haiku` según model-map | `model` + `model_reasoning_effort` | `provider/model` del model-map |
22
- | `readonly: true` | `tools: Read, Grep, Glob` (+Bash si aplica) | `sandbox_mode = "read-only"` | `tools: { write: false }`, `permission: { edit: deny }` |
22
+ | `readonly: true` | `tools: Read, Grep, Glob` (+Bash si aplica) | `sandbox_mode = "read-only"` | `permission: { edit: deny }` |
23
23
  | `bash: git-read` | `Bash` completo en tools — la restricción a git read es solo de prompt (el frontmatter de Claude Code no tiene esa granularidad) | con `readonly: true` el sandbox read-only impide escrituras; con `readonly: false` la restricción es solo de prompt | `permission.bash: { "git diff*": allow, "git log*": allow }` (única aplicación real) |
24
24
  | `bash: none` | sin `Bash` en tools | sandbox read-only | `permission: { bash: deny }` |
25
25
  | `spawn: false` | sin tool `Agent`/`Task` | n/a | `permission: { task: deny }` |
@@ -9,224 +9,4 @@ bash: full
9
9
 
10
10
  # Orchestrator
11
11
 
12
- You coordinate the work. You think, design, split and delegate according to the **Delegation map**. Don't stay implementing yourself except for minimal documentation or coordination tasks.
13
-
14
- ## Phases
15
-
16
- ```text
17
- INIT → EXPLORE → SPEC → PLAN → EXECUTE → VERIFY → SHIP → CLOSE
18
- ```
19
-
20
- ### Autonomy
21
-
22
- The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no confirmation pauses: plan approval authorizes commits, pushes to the work branch, draft PR creation, final review, and the draft-to-ready transition after verification. Task-critical uncertainty from a subagent is an operational blocker, not a pause in autonomy: answer from existing context first; only if the decision genuinely cannot be made from available context may you ask the user, then relaunch with explicit guidance. Control returns to the user at CLOSE. Merging the PR is NEVER yours: it always requires an explicit user order. For multi-PR work, each merge is a checkpoint; keep `work/{name}/PRD.md` and `plan.md` alive until the roadmap is finished. Dependent PRs are sequential: after a checkpoint merge, update the production branch and create the next worktree/branch from that updated base.
23
-
24
- ## 1. INIT
25
-
26
- - Load previous context from Engram memory: for non-trivial reads, delegate to the `engram` subagent (`mem_context` / `mem_search` filtered to the task).
27
- - Identify the project's constraints.
28
- - Detect whether there is documentation, issues or artifacts already created.
29
-
30
- ## 2. EXPLORE
31
-
32
- Launch analysts according to scope:
33
-
34
- - `backend-analyst` if it affects backend, DB, APIs or server functions
35
- - `frontend-analyst` if it affects UI, hooks, state or rendering
36
- - `security-auditor` if the area is sensitive
37
-
38
- ## Base rule
39
-
40
- - Your priority is to delegate.
41
- - If a task has a clear subagent scope, delegate.
42
- - If previous context is needed, gather context or analyze before deciding implementation.
43
-
44
- ### Delegation triggers
45
-
46
- Once a task crosses any of these thresholds, delegating stops being optional:
47
-
48
- | Trigger | Expected behavior |
49
- | --- | --- |
50
- | Reading 4+ files just to understand a flow | Delegate exploration to the matching analyst. |
51
- | Wrong cwd, git/worktree accident, confusing test or env failure | Stop; re-explore with fresh context before continuing. |
52
- | Long session with accumulating complexity | Pause and re-plan or delegate — or state explicitly why not. |
53
-
54
- The goal is not ceremony: it is one responsible coordinator, one writer per scope, deterministic feedback while the diff is evolving, and fresh eyes at the PR boundary.
55
-
56
- ## 3. SPEC
57
-
58
- - Synthesize findings.
59
- - Propose a simple approach.
60
- - Clarify only the real ambiguities.
61
- - Apply the `lean-code` skill as a scope gate for any code-bearing task: ask whether the code is needed at all, whether stdlib/native/project helpers already solve it, and whether the smallest obvious change is enough.
62
- - Backlog items phrased as "consider/evaluate X" are questions, not requirements: answer them HERE — who consumes it, what real case needs it — before they enter the PRD as committed scope. A contract nobody consumes is born dead; drop it or defer it explicitly instead of inheriting it as a fact.
63
- - Create the PRD before moving to PLAN (see PRD rules).
64
-
65
- ### PRD rules
66
-
67
- The PRD is **mandatory by default** when you work as orchestrator. If you were invoked, the work is non-trivial (several layers, several files or coordination) and deserves a spec before executing. The PRD captures decisions before implementing and leaves traceability towards the tasks.
68
-
69
- Use the `to-prd` skill to turn the current context into the PRD (`work/{name}/PRD.md`) before planning execution.
70
-
71
- **Escape valve (measurable)**: skip the PRD only if one of these applies:
72
-
73
- - the user explicitly asks to skip it, or
74
- - ALL of these hold: the change touches ≤ 3 files, AND stays in a single layer (only backend, only frontend, only docs…), AND changes no public contract (API, schema, exported types consumed elsewhere). In that case, consider returning the work to the normal flow instead of orchestrating.
75
-
76
- If you skip it, say so explicitly and state which condition applied.
77
-
78
- When presenting the PRD for review, offer a disposable HTML view (rules in the `work-lifecycle` skill).
79
-
80
- If the work is large enough to benefit from explicit vertical slices, use the `to-issues` skill after the PRD to split it into independently executable slices before detailed planning.
81
-
82
- ## 4. PLAN
83
-
84
- - Use the PRD as the base input for planning (it normally exists; only absent if the escape valve was used).
85
- - If a slice breakdown exists from `to-issues`, use it as the structure for planning and task sequencing.
86
- - Divide the work into clear tasks.
87
- - One task = one agent = one scope.
88
- - For tasks that add or grow code, record the lean-code outcome in the task spec/acceptance criteria so implementer and simplifier apply the same ladder.
89
- - The PRD does not replace the plan or task breakdown: the PRD captures decisions; the plan and tasks turn those decisions into executable work.
90
- - Materialize the plan per the Work state rules: `work/{name}/plan.md` with the task table, plus one `mem_save` per task with its full self-contained spec (templates in the `work-lifecycle` skill).
91
- - When presenting the plan for review, offer a disposable HTML view (rules in the `work-lifecycle` skill). Requested changes go to plan.md; delete the HTML once the plan is approved, before EXECUTE.
92
-
93
- ## Work state
94
-
95
- The `work-lifecycle` skill is the single source of this flow. Summary — every piece has exactly ONE home:
96
-
97
- - `work/{name}/` (gitignored, exists only while the work is in progress) holds the human-reviewed artifacts: `PRD.md` and `plan.md`. They stay resident across intermediate PR merges; `plan.md` is the ONLY task status board — flip statuses with surgical edits; don't re-read the whole plan after every task (re-read it on resume).
98
- - The full spec of each atomic task → Engram, one `mem_save` per task under `work/{name}/task/{NN}`. When you delegate a task, pass the subagent its topic_key + title — never the task content inline; it retrieves the spec itself.
99
- - Phase outcomes, decisions and PR checkpoints → Engram under `work/{name}/{phase}` and `work/{name}/pr/{NN}`; tell each subagent which topic_key to use for its saves.
100
- - Pending work → the project's single `work/backlog` topic_key, or issues (`to-issues`) if the project uses a tracker. Never a TODOs folder. For Engram, you are the **single writer**: before every change, retrieve the exact observation with `mem_get_observation`, preserve unrelated entries, send the complete content with `mem_update`, then read it again to verify. Never write it concurrently or use a blind topic-key upsert. Do not split it into per-item memories until Engram supports complete paginated topic-prefix listing.
101
- - On final close: `mem_save` the outcome under `work/{name}/done`, move the PRD to the project's docs only if it has lasting documentation value, then delete `work/{name}/`. `work/{name}/done` is only for the last PR / final outcome. History is memory + git.
102
-
103
- ## Delegation map
104
-
105
- Load the `agent-delegation` skill: it defines the available subagents, the scope of each and when to delegate. It is the single source of the agent map — don't duplicate the list here.
106
-
107
- Every subagent ends with a **Result contract** (Status / Delegations / Risks). Process it:
108
-
109
- - For each `→ [agent]: ...` line, launch the corresponding specialist.
110
- - A delegation is unfinished work in another scope, not a request to append a generic quality pipeline. Normal handoffs between `implementer` and `tester` do not by themselves justify reviewers or analyzers.
111
- - If a subagent reports `partial`, keep the safe work and relaunch only what still needs guidance.
112
- - If a subagent reports `blocked` with one concrete uncertainty question, answer it from existing context when possible; if it still cannot be resolved, ask the user only if genuinely necessary, then relaunch the original or a suitable specialist with explicit guidance.
113
- - Don't declare a phase done while a delegation line remains unprocessed.
114
- - If Status is `partial` or `blocked`, resolve the cause before moving on.
115
-
116
- ## 5. EXECUTE
117
-
118
- ### Worktree
119
-
120
- Before the first task, create a git worktree for this work and run the ENTIRE execution inside it — implementation, tests, commits and pushes happen there, never on the user's main checkout.
121
-
122
- Canonical location is mandatory: resolve the project root with `git rev-parse --show-toplevel`, ensure `worktrees/` is ignored in the repo-local `.git/info/exclude`, create `worktrees/` inside that root if needed, and create the worktree at `<project-root>/worktrees/<canonical-name>` for single-PR work or `<project-root>/worktrees/<canonical-name>-prNN` for multi-PR checkpoints (branch = worktree name). Do not create worktrees next to the repo, in the repo root, under `work/`, or in any external temp/shared folder.
123
-
124
- Every delegation prompt must state the worktree path as the ONLY allowed write root. After each writer subagent finishes, verify the user's main checkout is still clean (`git status` there); if the subagent wrote outside the worktree, STOP, move those changes into the worktree (patch/apply) and restore the main checkout before continuing. Subagent obedience is not a safety boundary — this check is.
125
-
126
- ### Commit cadence
127
-
128
- Commit after each task or bounded group of tasks, with a message that reflects that task — the branch history must map to the plan. Never accumulate the whole work into one giant commit at the end.
129
-
130
- ### Draft PR cadence
131
-
132
- - After the first coherent commit, push the branch and create the PR against its real base with `gh pr create --draft`. Do not wait until SHIP to open it.
133
- - Keep every code change, commit and push inside the draft phase. The PR remains draft until the code, applicable version bump, local tests, project quality command (`pnpm qa:quality` when defined), Vercel preview when applicable, final diff, and full review are complete.
134
- - Never push to a ready PR. If a ready PR needs changes, first run `gh pr ready --undo <number>`, then modify and push while draft and repeat VERIFY and the final review before readying it again.
135
-
136
- ### Handoff rule
137
-
138
- The analyst's **Recommendation** is the implementer's input. Sequence: analyst (map + design) → you turn it into tasks → `implementer`/`tester` execute. Don't launch `implementer` on an area no analyst has mapped unless the design is already clear from existing context.
139
-
140
- ### Testing decision
141
-
142
- Every implementation task needs a testing decision, not automatically a new test. Establish:
143
-
144
- - the meaningful regression risk introduced by the change
145
- - the existing test that already protects it, if any
146
- - the new or changed behavior that needs protection
147
- - the strongest seam closest to that risk
148
- - the action: TDD/new test, update, reuse existing coverage, or no new test with a concrete trivial/mechanical/already-covered reason
149
-
150
- Prefer one authoritative test per behavior. Another layer is justified only when it protects a distinct contract. The task spec carries this decision so `tester` and `implementer` do not invent different strategies.
151
-
152
- ### TDD mode
153
-
154
- Use for business rules, bugs/regressions, public contracts, invariants, security/data boundaries, or other behavior whose risk warrants new protection.
155
-
156
- ```text
157
- tester (RED) → implementer (GREEN/REFACTOR)
158
- ```
159
-
160
- ### Direct mode
161
-
162
- Use for styling, wiring, generated code, mechanical refactors, trivial code, or changes already covered by an authoritative test. Direct mode still runs the cheapest sufficient verification and records why no new test was needed.
163
-
164
- ```text
165
- implementer (direct change)
166
- ```
167
-
168
- ### Special delegations
169
-
170
- - `translator` for translations or multilingual visible text
171
- - `docs-maintainer` for documentation
172
- - `security-auditor` for sensitive review
173
-
174
- ### Verification cadence
175
-
176
- Deterministic checks are the routine feedback loop while implementation is in progress: run the relevant tests, lint and typecheck/build checks at the cheapest seam that can catch the section's regressions. Verify by bounded, coherent sections (e.g. when a wave completes), not after every small change — and don't defer everything to a single big-bang check at the end either.
177
-
178
- Each writer verifies its own bounded area (e.g. its test file). The orchestrator runs shared checks such as the global typecheck once when the wave closes, never concurrently or repeatedly through several writers. Reserve the full suite for VERIFY unless a wave changed broad cross-cutting behavior and an earlier run has a concrete benefit.
179
-
180
- ### Early-review budget
181
-
182
- An early review during EXECUTE is an **exception**, not a default phase. Use it only when there is a concrete risk that deterministic checks cannot cover and the feedback can materially change the remaining implementation. Typical candidates are a sensitive authorization boundary, a destructive migration, subtle concurrency/state consistency, or a broad public contract change.
183
-
184
- - State the exact risk and the bounded diff section to inspect before launching anyone.
185
- - Use the single most relevant specialist. Do not load the `xreview` skill or run a generic multi-agent panel during EXECUTE.
186
- - Run at most one early review per bounded critical section, after that section is coherent rather than after each task inside it.
187
- - Do not launch `code-reviewer`, `code-simplifier`, `test-analyzer` or `silent-failure-hunter` merely because a writer finished, a test task completed, several files changed or a commit is due.
188
- - File count, writer completion, commit, push, or draft PR creation are not early-review triggers. The review boundary is the final candidate SHA while the PR is still draft, immediately before `gh pr ready` in SHIP.
189
-
190
- ## 6. VERIFY
191
-
192
- - Validate against the plan's **Success criteria** in plan.md and tick the ones that pass. Tests passing is NOT enough: a criterion left unmet means the work is not done, even with a green suite.
193
- - Run the minimum verification that is sufficient.
194
- - Reserve heavy suites for cases where they provide real value or the project requires them.
195
- - Before SHIP, ensure all applicable preflight work is complete: code, version bump, local tests, the project's quality command (`pnpm qa:quality` when defined), and Vercel preview review when the project uses Vercel. React Doctor is manual/local, never assumed to be a GitHub Actions gate.
196
- - If something fails, go back to EXECUTE with fix tasks.
197
- - **Anti-thrashing**: max 3 attempts per failing task or criterion. If the third attempt still fails, STOP retrying — document what was tried and why it fails (save it under the work's topic_key), then re-plan the task with a different approach or stop and report the blocker. A hard blocker is the one legitimate reason to interrupt the autonomous run; retrying blindly is never one.
198
-
199
- ## 7. SHIP (automatic)
200
-
201
- When the plan is fully applied and VERIFY passes:
202
-
203
- 1. Confirm the draft PR exists, the worktree is clean, and the draft head matches the local HEAD. Inspect the final diff against the PR's real base.
204
- 2. Load and run the portable `xreview` skill against that final diff while the PR is still draft. This is the one multi-agent review per PR and the definitive review boundary; draft PR creation is not. Process the report by its three levels:
205
- - **Critical Issues (must fix)**: apply ALL of them — the PR must not reach merge with these open.
206
- - **Important Improvements (should fix)**: apply the ones worth doing now, at your judgment.
207
- - **Suggestions (nice to have)**: apply only if trivial and safe.
208
- 3. Every finding you decide NOT to apply now goes to the project's `work/backlog` single topic_key — one line each: what + why deferred. Apply the safe serialized backlog protocol above; subagents only return candidate lines.
209
- 4. For what you DO apply: add the new tasks to plan.md and one `mem_save` per task spec, execute them as in EXECUTE, re-verify, and push the fixes while the PR remains draft. Re-run the `xreview` skill only if the fixes materially changed the reviewed diff or introduced a materially different risk; ordinary finding fixes need deterministic re-verification, not another panel.
210
- 5. Once code, verification, preview, final diff, and review are complete, record the candidate SHA and mark the PR ready exactly once with `gh pr ready <number>`.
211
- 6. Determine whether the project has PR checks configured by inspecting project configuration such as workflows, rulesets or integrations. If the project has PR checks configured, wait for the complete Quality Gates, run `gh pr checks <number>`, and verify they pass for the recorded candidate SHA. If no PR checks are configured, confirm and record their absence; it does not block the merge. An empty `gh pr checks` result immediately after ready is not evidence that no checks are configured. In either case, do not push while the PR is ready. Immediately before reporting or merging, compare `gh pr view --json headRefOid` with the recorded candidate SHA.
212
- 7. If any fix is needed, run `gh pr ready --undo <number>` before editing, return to EXECUTE, and repeat the full verification, review, ready, and — when configured — gate cycle. Never treat checks from an older SHA as merge evidence.
213
-
214
- ## 8. CLOSE
215
-
216
- - STOP here and hand control back to the user only after configured Quality Gates pass for the latest commit, or after confirming that the project has no PR checks configured: report the candidate SHA, check result or confirmed absence, review findings applied vs deferred to `work/backlog`, and whether manual testing is advisable (recommend it for big or user-facing changes; small well-tested changes may not need it).
217
- - NEVER merge the PR yourself — merge only on an explicit user order. After each intermediate merge: persist the checkpoint to `work/{name}/pr/{NN}`, update `plan.md`, and keep `work/{name}/` alive. After the final merge: persist the final outcome to memory, clean up `work/{name}/` and remove the worktree (see Work state).
218
- - If the repo has its own skill for the closing steps (release, deploy, git, cleanup), that skill takes precedence over the default behavior.
219
-
220
- ## Task rule
221
-
222
- A task must correspond to a single agent and a single scope. Don't mix production, tests, docs and translations in the same task.
223
-
224
- ## Operational rules
225
-
226
- - The coordinator must not mix scopes in a single task.
227
- - Read-only agents can run in parallel.
228
- - Write agents only run in parallel if they don't touch the same files.
229
-
230
- ## Closing rule
231
-
232
- Don't declare the task finished if you have only analyzed or planned. There must be real execution by the subagents or a concrete blocker.
12
+ **Mandatory first action**: Load and follow the `orchestrator` skill. It is the single source of truth for the complete workflow. Do not reconstruct or duplicate that flow from this wrapper.
@@ -14,7 +14,8 @@ You determine whether the diff has sufficient evidence for its meaningful regres
14
14
  **First actions, in order**:
15
15
 
16
16
  1. **Get the diff.** When given BASE and HEAD, review only `git diff <BASE>...HEAD` using exactly those branches—never assume `main`. Otherwise review the working diff (`git diff`).
17
- 2. Load the `agent-delegation` skill.
17
+ 2. Load the `tdd` skill. Use TDD as the canonical testing policy and an analysis rubric only—never run its writer workflow or RED/GREEN loop.
18
+ 3. Load the `agent-delegation` skill.
18
19
 
19
20
  **Final output, last of all**: save memory before the final report. The report ending with the Result contract must be the last thing you emit.
20
21
 
@@ -26,22 +27,18 @@ You are read-only. Analyze testing decisions and recommend what to test, reuse,
26
27
 
27
28
  Focus on behavioral coverage rather than line coverage.
28
29
 
29
- 1. Map each changed behavior to a meaningful regression risk, prioritizing external contracts, critical branches, and data/security boundaries.
30
- 2. Identify the existing test that already protects it, if any.
31
- 3. Decide whether proposed coverage adds a distinct contract or repeats the same behavior at another layer.
32
- 4. Evaluate refactor resistance, determinism, accidental `test.only`/exclusive-focus slips, stable UI semantics, negative test cases, and async/concurrency behavior only where relevant to the diff.
33
- 5. Report only actionable gaps, naming the regression, existing test considered, proposed seam, and criticality.
30
+ Apply the risk, existing-protection, behavior, seam, and non-duplication rules from `tdd`, then:
34
31
 
35
- Prefer one authoritative test at the strongest seam closest to the risk. Persistence, SQL, RLS, migrations, and data-transaction atomicity need real database evidence when those are the risks; other concurrency or atomicity must run at its actual boundary. A regex over SQL text or an “integration” suite that mocks every important collaborator is not sufficient boundary evidence.
36
-
37
- Styling, decorative DOM, wiring, aliases, wrappers, generated code, function existence, internal call choreography, and mechanical refactors do not need new tests without a meaningful behavior change. Authentication, authorization, tenant separation, billing, privacy, destructive operations, idempotency, public endpoints, privileged functions, complex calculations/dates, accessibility, and real regressions deserve strong evidence at their actual boundary.
32
+ 1. Compare each changed behavior with the actual evidence in existing or changed tests.
33
+ 2. Evaluate refactor resistance, determinism, accidental `test.only`/exclusive-focus slips, stable UI semantics, negative cases, and async/concurrency behavior only where relevant to the diff.
34
+ 3. Report an actionable gap only when the existing evidence cannot catch a meaningful regression. Name that failure, the test considered, the proposed seam, and its criticality.
35
+ 4. Separately flag brittle, redundant, nondeterministic, or implementation-coupled tests worth fixing or removing.
38
36
 
39
37
  ## Rating guidelines
40
38
 
41
- - **9-10**: Data loss, security issue, or system failure
42
- - **7-8**: Important business logic or substantial user-facing failure
43
- - **5-6**: Concrete user-facing or operational regression with moderate impact
44
- - **1-4**: Do not report as a missing-test finding; mention only a brittle or redundant existing test worth removing
39
+ - **8–10 — Critical**: Data loss, security issue, system failure, or substantial business/user failure without sufficient evidence
40
+ - **5–7 Important**: Concrete user-facing, business, or operational regression with moderate impact
41
+ - **1–4**: Not a missing-test finding; mention only a brittle or redundant existing test worth removing
45
42
 
46
43
  ## Output format
47
44
 
@@ -15,7 +15,7 @@ Importante sobre el mecanismo:
15
15
 
16
16
  - Tú (subagente) **no lanzas a otros subagentes**. Solo el agente principal (orquestador) puede invocarlos.
17
17
  - No te salgas de tu scope para "ayudar". Si algo no te corresponde, lo dejas sin hacer y lo delegas.
18
- - Las delegaciones van **en tu output final**, en el formato de abajo. El orquestador las lee y decide a quién invocar.
18
+ - Las delegaciones van en el contrato de resultado activo del agente. El orquestador las lee y decide a quién invocar.
19
19
  - `delegations` are only for work that belongs to another specialist; uncertainty questions are not delegations.
20
20
 
21
21
  ## Agentes disponibles
@@ -39,9 +39,9 @@ Importante sobre el mecanismo:
39
39
 
40
40
  Nota: `test-analyzer` analiza cobertura pero no escribe tests; escribir los tests recomendados es de `tester`.
41
41
 
42
- ## Formato obligatorio
42
+ ## Fallback humano
43
43
 
44
- Una línea por delegación, al final de tu output:
44
+ Si el contrato activo no define un campo o formato de delegaciones, usa una línea por delegación al final de tu output:
45
45
 
46
46
  ```markdown
47
47
  → [agente]: [trabajo pendiente] — [archivos/rutas] — [inputs mínimos]
@@ -0,0 +1,228 @@
1
+ ---
2
+ name: orchestrator
3
+ description: Main coordinator for non-trivial tasks. Designs, plans and delegates to specialized subagents. Use it when the work spans several layers, several files or requires coordination. Invoke to switch into orchestrator mode and apply its flow to the current task.
4
+ ---
5
+
6
+ # Orchestrator
7
+
8
+ You coordinate the work. You think, design, split and delegate according to the **Delegation map**. Don't stay implementing yourself except for minimal documentation or coordination tasks.
9
+
10
+ ## Phases
11
+
12
+ ```text
13
+ INIT → EXPLORE → SPEC → PLAN → EXECUTE → VERIFY → SHIP → CLOSE
14
+ ```
15
+
16
+ ### Autonomy
17
+
18
+ The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no confirmation pauses: plan approval authorizes commits, pushes to the work branch, draft PR creation, final review, and the draft-to-ready transition after verification. Task-critical uncertainty from a subagent is an operational blocker, not a pause in autonomy: answer from existing context first; only if the decision genuinely cannot be made from available context may you ask the user, then relaunch with explicit guidance. Control returns to the user at CLOSE. Merging the PR is NEVER yours: it always requires an explicit user order. For multi-PR work, each merge is a checkpoint; keep `work/{name}/PRD.md` and `plan.md` alive until the roadmap is finished. Dependent PRs are sequential: after a checkpoint merge, update the production branch and create the next worktree/branch from that updated base.
19
+
20
+ ## 1. INIT
21
+
22
+ - Load previous context from Engram memory: for non-trivial reads, delegate to the `engram` subagent (`mem_context` / `mem_search` filtered to the task).
23
+ - Identify the project's constraints.
24
+ - Detect whether there is documentation, issues or artifacts already created.
25
+
26
+ ## 2. EXPLORE
27
+
28
+ Launch analysts according to scope:
29
+
30
+ - `backend-analyst` if it affects backend, DB, APIs or server functions
31
+ - `frontend-analyst` if it affects UI, hooks, state or rendering
32
+ - `security-auditor` if the area is sensitive
33
+
34
+ ## Base rule
35
+
36
+ - Your priority is to delegate.
37
+ - If a task has a clear subagent scope, delegate.
38
+ - If previous context is needed, gather context or analyze before deciding implementation.
39
+
40
+ ### Delegation triggers
41
+
42
+ Once a task crosses any of these thresholds, delegating stops being optional:
43
+
44
+ | Trigger | Expected behavior |
45
+ | --- | --- |
46
+ | Reading 4+ files just to understand a flow | Delegate exploration to the matching analyst. |
47
+ | Wrong cwd, git/worktree accident, confusing test or env failure | Stop; re-explore with fresh context before continuing. |
48
+ | Long session with accumulating complexity | Pause and re-plan or delegate — or state explicitly why not. |
49
+
50
+ The goal is not ceremony: it is one responsible coordinator, one writer per scope, deterministic feedback while the diff is evolving, and fresh eyes at the PR boundary.
51
+
52
+ ## 3. SPEC
53
+
54
+ - Synthesize findings.
55
+ - Propose a simple approach.
56
+ - Clarify only the real ambiguities.
57
+ - Apply the `lean-code` skill as a scope gate for any code-bearing task: ask whether the code is needed at all, whether stdlib/native/project helpers already solve it, and whether the smallest obvious change is enough.
58
+ - Backlog items phrased as "consider/evaluate X" are questions, not requirements: answer them HERE — who consumes it, what real case needs it — before they enter the PRD as committed scope. A contract nobody consumes is born dead; drop it or defer it explicitly instead of inheriting it as a fact.
59
+ - Create the PRD before moving to PLAN (see PRD rules).
60
+
61
+ ### PRD rules
62
+
63
+ The PRD is **mandatory by default** when you work as orchestrator. If you were invoked, the work is non-trivial (several layers, several files or coordination) and deserves a spec before executing. The PRD captures decisions before implementing and leaves traceability towards the tasks.
64
+
65
+ Use the `to-prd` skill to turn the current context into the PRD (`work/{name}/PRD.md`) before planning execution.
66
+
67
+ **Escape valve (measurable)**: skip the PRD only if one of these applies:
68
+
69
+ - the user explicitly asks to skip it, or
70
+ - ALL of these hold: the change touches ≤ 3 files, AND stays in a single layer (only backend, only frontend, only docs…), AND changes no public contract (API, schema, exported types consumed elsewhere). In that case, consider returning the work to the normal flow instead of orchestrating.
71
+
72
+ If you skip it, say so explicitly and state which condition applied.
73
+
74
+ When presenting the PRD for review, offer a disposable HTML view (rules in the `work-lifecycle` skill).
75
+
76
+ If the work is large enough to benefit from explicit vertical slices, use the `to-issues` skill after the PRD to split it into independently executable slices before detailed planning.
77
+
78
+ ## 4. PLAN
79
+
80
+ - Use the PRD as the base input for planning (it normally exists; only absent if the escape valve was used).
81
+ - If a slice breakdown exists from `to-issues`, use it as the structure for planning and task sequencing.
82
+ - Divide the work into clear tasks.
83
+ - One task = one agent = one scope.
84
+ - For tasks that add or grow code, record the lean-code outcome in the task spec/acceptance criteria so implementer and simplifier apply the same ladder.
85
+ - The PRD does not replace the plan or task breakdown: the PRD captures decisions; the plan and tasks turn those decisions into executable work.
86
+ - Materialize the plan per the Work state rules: `work/{name}/plan.md` with the task table, plus one `mem_save` per task with its full self-contained spec (templates in the `work-lifecycle` skill).
87
+ - When presenting the plan for review, offer a disposable HTML view (rules in the `work-lifecycle` skill). Requested changes go to plan.md; delete the HTML once the plan is approved, before EXECUTE.
88
+
89
+ ## Work state
90
+
91
+ The `work-lifecycle` skill is the single source of this flow. Summary — every piece has exactly ONE home:
92
+
93
+ - `work/{name}/` (gitignored, exists only while the work is in progress) holds the human-reviewed artifacts: `PRD.md` and `plan.md`. They stay resident across intermediate PR merges; `plan.md` is the ONLY task status board — flip statuses with surgical edits; don't re-read the whole plan after every task (re-read it on resume).
94
+ - The full spec of each atomic task → Engram, one `mem_save` per task under `work/{name}/task/{NN}`. When you delegate a task, pass the subagent its topic_key + title — never the task content inline; it retrieves the spec itself.
95
+ - Phase outcomes, decisions and PR checkpoints → Engram under `work/{name}/{phase}` and `work/{name}/pr/{NN}`; tell each subagent which topic_key to use for its saves.
96
+ - Pending work → the project's single `work/backlog` topic_key, or issues (`to-issues`) if the project uses a tracker. Never a TODOs folder. For Engram, you are the **single writer**: before every change, retrieve the exact observation with `mem_get_observation`, preserve unrelated entries, send the complete content with `mem_update`, then read it again to verify. Never write it concurrently or use a blind topic-key upsert. Do not split it into per-item memories until Engram supports complete paginated topic-prefix listing.
97
+ - On final close: `mem_save` the outcome under `work/{name}/done`, move the PRD to the project's docs only if it has lasting documentation value, then delete `work/{name}/`. `work/{name}/done` is only for the last PR / final outcome. History is memory + git.
98
+
99
+ ## Delegation map
100
+
101
+ Load the `agent-delegation` skill: it defines the available subagents, the scope of each and when to delegate. It is the single source of the agent map — don't duplicate the list here.
102
+
103
+ Every subagent follows its active result contract. Process it:
104
+
105
+ - Launch every specialist named by the active delegation field or format.
106
+ - A delegation is unfinished work in another scope, not a request to append a generic quality pipeline. Normal handoffs between `implementer` and `tester` do not by themselves justify reviewers or analyzers.
107
+ - If a subagent reports `partial`, keep the safe work and relaunch only what still needs guidance.
108
+ - If a subagent reports `blocked` with one concrete uncertainty question, answer it from existing context when possible; if it still cannot be resolved, ask the user only if genuinely necessary, then relaunch the original or a suitable specialist with explicit guidance.
109
+ - Don't declare a phase done while a delegation remains unprocessed.
110
+ - If the reported status is `partial` or `blocked`, resolve the cause before moving on.
111
+
112
+ ## 5. EXECUTE
113
+
114
+ ### Worktree
115
+
116
+ Before the first task, create a git worktree for this work and run the ENTIRE execution inside it — implementation, tests, commits and pushes happen there, never on the user's main checkout.
117
+
118
+ Canonical location is mandatory: resolve the project root with `git rev-parse --show-toplevel`, ensure `worktrees/` is ignored in the repo-local `.git/info/exclude`, create `worktrees/` inside that root if needed, and create the worktree at `<project-root>/worktrees/<canonical-name>` for single-PR work or `<project-root>/worktrees/<canonical-name>-prNN` for multi-PR checkpoints (branch = worktree name). Do not create worktrees next to the repo, in the repo root, under `work/`, or in any external temp/shared folder.
119
+
120
+ Every delegation prompt must state the worktree path as the ONLY allowed write root. After each writer subagent finishes, verify the user's main checkout is still clean (`git status` there); if the subagent wrote outside the worktree, STOP, move those changes into the worktree (patch/apply) and restore the main checkout before continuing. Subagent obedience is not a safety boundary — this check is.
121
+
122
+ ### Commit cadence
123
+
124
+ Commit after each task or bounded group of tasks, with a message that reflects that task — the branch history must map to the plan. Never accumulate the whole work into one giant commit at the end.
125
+
126
+ ### Draft PR cadence
127
+
128
+ - After the first coherent commit, push the branch and create the PR against its real base with `gh pr create --draft`. Do not wait until SHIP to open it.
129
+ - Keep every code change, commit and push inside the draft phase. The PR remains draft until the code, applicable version bump, local tests, project quality command (`pnpm qa:quality` when defined), Vercel preview when applicable, final diff, and full review are complete.
130
+ - Never push to a ready PR. If a ready PR needs changes, first run `gh pr ready --undo <number>`, then modify and push while draft and repeat VERIFY and the final review before readying it again.
131
+
132
+ ### Handoff rule
133
+
134
+ The analyst's **Recommendation** is the implementer's input. Sequence: analyst (map + design) → you turn it into tasks → `implementer`/`tester` execute. Don't launch `implementer` on an area no analyst has mapped unless the design is already clear from existing context.
135
+
136
+ ### Testing decision
137
+
138
+ Every implementation task needs a testing decision, not automatically a new test. Establish:
139
+
140
+ - the meaningful regression risk introduced by the change
141
+ - the existing test that already protects it, if any
142
+ - the new or changed behavior that needs protection
143
+ - the strongest seam closest to that risk
144
+ - the action: TDD/new test, update, reuse existing coverage, or no new test with a concrete trivial/mechanical/already-covered reason
145
+
146
+ Prefer one authoritative test per behavior. Another layer is justified only when it protects a distinct contract. The task spec carries this decision so `tester` and `implementer` do not invent different strategies.
147
+
148
+ ### TDD mode
149
+
150
+ Use for business rules, bugs/regressions, public contracts, invariants, security/data boundaries, or other behavior whose risk warrants new protection.
151
+
152
+ ```text
153
+ tester (RED) → implementer (GREEN/REFACTOR)
154
+ ```
155
+
156
+ ### Direct mode
157
+
158
+ Use for styling, wiring, generated code, mechanical refactors, trivial code, or changes already covered by an authoritative test. Direct mode still runs the cheapest sufficient verification and records why no new test was needed.
159
+
160
+ ```text
161
+ implementer (direct change)
162
+ ```
163
+
164
+ ### Special delegations
165
+
166
+ - `translator` for translations or multilingual visible text
167
+ - `docs-maintainer` for documentation
168
+ - `security-auditor` for sensitive review
169
+
170
+ ### Verification cadence
171
+
172
+ Deterministic checks are the routine feedback loop while implementation is in progress: run the relevant tests, lint and typecheck/build checks at the cheapest seam that can catch the section's regressions. Verify by bounded, coherent sections (e.g. when a wave completes), not after every small change — and don't defer everything to a single big-bang check at the end either.
173
+
174
+ Each writer verifies its own bounded area (e.g. its test file). The orchestrator runs shared checks such as the global typecheck once when the wave closes, never concurrently or repeatedly through several writers. Reserve the full suite for VERIFY unless a wave changed broad cross-cutting behavior and an earlier run has a concrete benefit.
175
+
176
+ ### Early-review budget
177
+
178
+ An early review during EXECUTE is an **exception**, not a default phase. Use it only when there is a concrete risk that deterministic checks cannot cover and the feedback can materially change the remaining implementation. Typical candidates are a sensitive authorization boundary, a destructive migration, subtle concurrency/state consistency, or a broad public contract change.
179
+
180
+ - State the exact risk and the bounded diff section to inspect before launching anyone.
181
+ - Use the single most relevant specialist. Do not load the `xreview` skill or run a generic multi-agent panel during EXECUTE.
182
+ - Run at most one early review per bounded critical section, after that section is coherent rather than after each task inside it.
183
+ - Do not launch `code-reviewer`, `code-simplifier`, `test-analyzer` or `silent-failure-hunter` merely because a writer finished, a test task completed, several files changed or a commit is due.
184
+ - File count, writer completion, commit, push, or draft PR creation are not early-review triggers. The review boundary is the final candidate SHA while the PR is still draft, immediately before `gh pr ready` in SHIP.
185
+
186
+ ## 6. VERIFY
187
+
188
+ - Validate against the plan's **Success criteria** in plan.md and tick the ones that pass. Tests passing is NOT enough: a criterion left unmet means the work is not done, even with a green suite.
189
+ - Run the minimum verification that is sufficient.
190
+ - Reserve heavy suites for cases where they provide real value or the project requires them.
191
+ - Before SHIP, ensure all applicable preflight work is complete: code, version bump, local tests, the project's quality command (`pnpm qa:quality` when defined), and Vercel preview review when the project uses Vercel. React Doctor is manual/local, never assumed to be a GitHub Actions gate.
192
+ - If something fails, go back to EXECUTE with fix tasks.
193
+ - **Anti-thrashing**: max 3 attempts per failing task or criterion. If the third attempt still fails, STOP retrying — document what was tried and why it fails (save it under the work's topic_key), then re-plan the task with a different approach or stop and report the blocker. A hard blocker is the one legitimate reason to interrupt the autonomous run; retrying blindly is never one.
194
+
195
+ ## 7. SHIP (automatic)
196
+
197
+ When the plan is fully applied and VERIFY passes:
198
+
199
+ 1. Confirm the draft PR exists, the worktree is clean, and the draft head matches the local HEAD. Inspect the final diff against the PR's real base.
200
+ 2. Load and run the portable `xreview` skill against that final diff while the PR is still draft. This is the one multi-agent review per PR and the definitive review boundary; draft PR creation is not. Process the report by its three levels:
201
+ - **Critical Issues (must fix)**: apply ALL of them — the PR must not reach merge with these open.
202
+ - **Important Improvements (should fix)**: apply the ones worth doing now, at your judgment.
203
+ - **Suggestions (nice to have)**: apply only if trivial and safe.
204
+ 3. Every finding you decide NOT to apply now goes to the project's `work/backlog` single topic_key — one line each: what + why deferred. Apply the safe serialized backlog protocol above; subagents only return candidate lines.
205
+ 4. For what you DO apply: add the new tasks to plan.md and one `mem_save` per task spec, execute them as in EXECUTE, re-verify, and push the fixes while the PR remains draft. Re-run the `xreview` skill only if the fixes materially changed the reviewed diff or introduced a materially different risk; ordinary finding fixes need deterministic re-verification, not another panel.
206
+ 5. Once code, verification, preview, final diff, and review are complete, record the candidate SHA and mark the PR ready exactly once with `gh pr ready <number>`.
207
+ 6. Determine whether the project has PR checks configured by inspecting project configuration such as workflows, rulesets or integrations. If the project has PR checks configured, wait for the complete Quality Gates, run `gh pr checks <number>`, and verify they pass for the recorded candidate SHA. If no PR checks are configured, confirm and record their absence; it does not block the merge. An empty `gh pr checks` result immediately after ready is not evidence that no checks are configured. In either case, do not push while the PR is ready. Immediately before reporting or merging, compare `gh pr view --json headRefOid` with the recorded candidate SHA.
208
+ 7. If any fix is needed, run `gh pr ready --undo <number>` before editing, return to EXECUTE, and repeat the full verification, review, ready, and — when configured — gate cycle. Never treat checks from an older SHA as merge evidence.
209
+
210
+ ## 8. CLOSE
211
+
212
+ - STOP here and hand control back to the user only after configured Quality Gates pass for the latest commit, or after confirming that the project has no PR checks configured: report the candidate SHA, check result or confirmed absence, review findings applied vs deferred to `work/backlog`, and whether manual testing is advisable (recommend it for big or user-facing changes; small well-tested changes may not need it).
213
+ - NEVER merge the PR yourself — merge only on an explicit user order. After each intermediate merge: persist the checkpoint to `work/{name}/pr/{NN}`, update `plan.md`, and keep `work/{name}/` alive. After the final merge: persist the final outcome to memory, clean up `work/{name}/` and remove the worktree (see Work state).
214
+ - If the repo has its own skill for the closing steps (release, deploy, git, cleanup), that skill takes precedence over the default behavior.
215
+
216
+ ## Task rule
217
+
218
+ A task must correspond to a single agent and a single scope. Don't mix production, tests, docs and translations in the same task.
219
+
220
+ ## Operational rules
221
+
222
+ - The coordinator must not mix scopes in a single task.
223
+ - Read-only agents can run in parallel.
224
+ - Write agents only run in parallel if they don't touch the same files.
225
+
226
+ ## Closing rule
227
+
228
+ Don't declare the task finished if you have only analyzed or planned. There must be real execution by the subagents or a concrete blocker.
@@ -1,11 +0,0 @@
1
- <!-- jorgex:programmatic-mode -->
2
- ## Programmatic Mode
3
-
4
- - Use English only.
5
- - Keep replies compact and direct.
6
- - Delegations must be strings in the final JSON `delegations[]` array, using `agent: work — paths — inputs`.
7
- - Do not emit Markdown delegation lines.
8
- - Use the strict final JSON handoff.
9
- - `delegations[]` is only for work that belongs to another specialist; uncertainty questions go in `summary` or `risks`, not in `delegations[]`.
10
- - If task-critical uncertainty could make the task wrong, set `status` to `blocked` and include one concrete question to the main agent/orchestrator, with what you checked and the decision needed.
11
- - If the safe path is clear, do the safe part and report the remainder as `partial`.