vexp-cli 2.2.3 → 2.3.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.
@@ -95,6 +95,13 @@ const VEXP_TOOLS = [
95
95
  "save_observation",
96
96
  "get_token_savings",
97
97
  ];
98
+ let activeGuardMode = "off";
99
+ export function setGuardMode(mode) {
100
+ activeGuardMode = mode;
101
+ }
102
+ export function guardMode() {
103
+ return activeGuardMode;
104
+ }
98
105
  // ---------------------------------------------------------------------------
99
106
  // Agent detectors - mirrors VS Code extension's AGENT_DETECTORS
100
107
  // ---------------------------------------------------------------------------
@@ -291,8 +298,20 @@ export function configureAgents(workspaceRoot, binaryPath, version, agentFilter,
291
298
  // Write MCP config for agents with mcpConfigFile (project-level JSON)
292
299
  if (detector.mcpConfigFile) {
293
300
  const mcpConfigPath = path.join(workspaceRoot, detector.mcpConfigFile);
294
- const alwaysAllow = detector.agent === "Windsurf" ? VEXP_TOOLS : undefined;
295
- if (writeMcpConfig(mcpConfigPath, binaryPath, alwaysAllow, mcpServerPath, workspaceRoot)) {
301
+ const isKiro = detector.agent === "Kiro";
302
+ // Windsurf and Kiro auto-approve vexp's tools so the agent isn't prompted
303
+ // on every run_pipeline call. Kiro's field is `autoApprove`; others use
304
+ // `alwaysAllow`.
305
+ const alwaysAllow = (detector.agent === "Windsurf" || isKiro) ? VEXP_TOOLS : undefined;
306
+ const approveKey = isKiro ? "autoApprove" : "alwaysAllow";
307
+ // Kiro resolves the MCP `command` via PATH, and a macOS GUI launch has no
308
+ // `node` on PATH — so the `node <mcp-server.cjs>` transport silently fails
309
+ // to start and run_pipeline never appears (the agent then falls back to
310
+ // grep/sed). Point Kiro straight at the vexp binary (`vexp-core mcp`, which
311
+ // reads VEXP_WORKSPACE from env) by withholding mcpServerPath — no `node`
312
+ // needed, an absolute path that always resolves.
313
+ const mcpSrv = isKiro ? undefined : mcpServerPath;
314
+ if (writeMcpConfig(mcpConfigPath, binaryPath, alwaysAllow, mcpSrv, workspaceRoot, approveKey)) {
296
315
  mcpConfigs.push(detector.mcpConfigFile);
297
316
  }
298
317
  }
@@ -301,15 +320,27 @@ export function configureAgents(workspaceRoot, binaryPath, version, agentFilter,
301
320
  const wrote = configureClaudeCodeGlobal(binaryPath, mcpServerPath, workspaceRoot);
302
321
  if (wrote)
303
322
  mcpConfigs.push("~/.claude.json");
304
- // Install PreToolUse hook: blocks Grep/Glob when vexp daemon is available
305
- const hookResult = installClaudeCodeHook(workspaceRoot);
306
- if (hookResult) {
323
+ // Guard is OPT-IN from 2.3 (see GuardMode): strict installs the
324
+ // PreToolUse deny hook; default removes any previously installed one.
325
+ if (guardMode() === "strict") {
326
+ const hookResult = installClaudeCodeHook(workspaceRoot);
327
+ if (hookResult) {
328
+ results.push({
329
+ agent: "Claude Code Hook",
330
+ configFile: ".claude/hooks/vexp-guard.sh",
331
+ content: VEXP_GUARD_HOOK,
332
+ alreadyExists: false,
333
+ action: hookResult,
334
+ });
335
+ }
336
+ }
337
+ else if (uninstallClaudeCodeHook(workspaceRoot)) {
307
338
  results.push({
308
339
  agent: "Claude Code Hook",
309
340
  configFile: ".claude/hooks/vexp-guard.sh",
310
- content: VEXP_GUARD_HOOK,
341
+ content: "",
311
342
  alreadyExists: false,
312
- action: hookResult,
343
+ action: "removed",
313
344
  });
314
345
  }
315
346
  }
@@ -348,34 +379,56 @@ export function configureAgents(workspaceRoot, binaryPath, version, agentFilter,
348
379
  // Kilo v7 vendors opencode, so it takes the same guard plugin — the rules
349
380
  // markdown alone was demonstrably not enough (a reported session loaded
350
381
  // vexp.md, quoted it back, and still read five files by hand).
351
- const kilo = installKiloPlugin(workspaceRoot);
352
- if (kilo.plugin) {
382
+ if (guardMode() === "strict") {
383
+ const kilo = installKiloPlugin(workspaceRoot);
384
+ if (kilo.plugin) {
385
+ results.push({
386
+ agent: "Kilo Code Guard",
387
+ configFile: path.join(".kilo", "plugins", "vexp-guard.js"),
388
+ content: VEXP_OPENCODE_GUARD,
389
+ alreadyExists: kilo.plugin === "updated",
390
+ action: kilo.plugin,
391
+ });
392
+ }
393
+ if (kilo.registered)
394
+ mcpConfigs.push(path.relative(workspaceRoot, kiloConfigTarget(workspaceRoot)));
395
+ }
396
+ else if (uninstallKiloPlugin(workspaceRoot)) {
353
397
  results.push({
354
398
  agent: "Kilo Code Guard",
355
399
  configFile: path.join(".kilo", "plugins", "vexp-guard.js"),
356
- content: VEXP_OPENCODE_GUARD,
357
- alreadyExists: kilo.plugin === "updated",
358
- action: kilo.plugin,
400
+ content: "",
401
+ alreadyExists: false,
402
+ action: "removed",
359
403
  });
360
404
  }
361
- if (kilo.registered)
362
- mcpConfigs.push(path.relative(workspaceRoot, kiloConfigTarget(workspaceRoot)));
363
405
  }
364
406
  // Cursor: preToolUse hook matching Grep. Text search only - Cursor's native
365
407
  // semantic search is not hookable.
366
408
  if (detector.agent === "Cursor") {
367
- const cur = installCursorHook(workspaceRoot);
368
- if (cur.hook) {
409
+ if (guardMode() === "strict") {
410
+ const cur = installCursorHook(workspaceRoot);
411
+ if (cur.hook) {
412
+ results.push({
413
+ agent: "Cursor Guard",
414
+ configFile: path.join(".cursor", "hooks", "vexp-guard.js"),
415
+ content: VEXP_CURSOR_GUARD,
416
+ alreadyExists: cur.hook === "updated",
417
+ action: cur.hook,
418
+ });
419
+ }
420
+ if (cur.registered)
421
+ mcpConfigs.push(path.join(".cursor", "hooks.json"));
422
+ }
423
+ else if (uninstallCursorHook(workspaceRoot)) {
369
424
  results.push({
370
425
  agent: "Cursor Guard",
371
426
  configFile: path.join(".cursor", "hooks", "vexp-guard.js"),
372
- content: VEXP_CURSOR_GUARD,
373
- alreadyExists: cur.hook === "updated",
374
- action: cur.hook,
427
+ content: "",
428
+ alreadyExists: false,
429
+ action: "removed",
375
430
  });
376
431
  }
377
- if (cur.registered)
378
- mcpConfigs.push(path.join(".cursor", "hooks.json"));
379
432
  }
380
433
  // Opencode: MCP lives under the `mcp` key in opencode.json(c) — opencode
381
434
  // carries no `mcpConfigFile`, so without this call the generic writer above
@@ -386,14 +439,25 @@ export function configureAgents(workspaceRoot, binaryPath, version, agentFilter,
386
439
  const wroteMcp = configureOpencodeMcp(workspaceRoot, binaryPath, mcpServerPath);
387
440
  if (wroteMcp)
388
441
  mcpConfigs.push(wroteMcp);
389
- const pluginResult = installOpencodePlugin(workspaceRoot);
390
- if (pluginResult) {
442
+ if (guardMode() === "strict") {
443
+ const pluginResult = installOpencodePlugin(workspaceRoot);
444
+ if (pluginResult) {
445
+ results.push({
446
+ agent: "Opencode Guard",
447
+ configFile: ".opencode/plugins/vexp-guard.js",
448
+ content: VEXP_OPENCODE_GUARD,
449
+ alreadyExists: pluginResult === "updated",
450
+ action: pluginResult,
451
+ });
452
+ }
453
+ }
454
+ else if (uninstallOpencodePlugin(workspaceRoot)) {
391
455
  results.push({
392
456
  agent: "Opencode Guard",
393
457
  configFile: ".opencode/plugins/vexp-guard.js",
394
- content: VEXP_OPENCODE_GUARD,
395
- alreadyExists: pluginResult === "updated",
396
- action: pluginResult,
458
+ content: "",
459
+ alreadyExists: false,
460
+ action: "removed",
397
461
  });
398
462
  }
399
463
  }
@@ -529,15 +593,24 @@ export function configureSelectedAgents(workspaceRoot, binaryPath, version, sele
529
593
  }
530
594
  if (detector.mcpConfigFile) {
531
595
  const mcpConfigPath = path.join(workspaceRoot, detector.mcpConfigFile);
532
- const alwaysAllow = detector.agent === "Windsurf" ? VEXP_TOOLS : undefined;
533
- if (writeMcpConfig(mcpConfigPath, binaryPath, alwaysAllow, mcpServerPath, workspaceRoot))
596
+ const isKiro = detector.agent === "Kiro";
597
+ // See configureAgents(): Kiro auto-approves under `autoApprove` and is
598
+ // pointed at the vexp binary (no `node` on macOS GUI PATH) by withholding
599
+ // mcpServerPath.
600
+ const alwaysAllow = (detector.agent === "Windsurf" || isKiro) ? VEXP_TOOLS : undefined;
601
+ const approveKey = isKiro ? "autoApprove" : "alwaysAllow";
602
+ const mcpSrv = isKiro ? undefined : mcpServerPath;
603
+ if (writeMcpConfig(mcpConfigPath, binaryPath, alwaysAllow, mcpSrv, workspaceRoot, approveKey))
534
604
  mcpConfigs.push(detector.mcpConfigFile);
535
605
  }
536
606
  if (detector.agent === "Claude Code") {
537
607
  const wrote = configureClaudeCodeGlobal(binaryPath, mcpServerPath, workspaceRoot);
538
608
  if (wrote)
539
609
  mcpConfigs.push("~/.claude.json");
540
- installClaudeCodeHook(workspaceRoot);
610
+ if (guardMode() === "strict")
611
+ installClaudeCodeHook(workspaceRoot);
612
+ else
613
+ uninstallClaudeCodeHook(workspaceRoot);
541
614
  }
542
615
  if (detector.agent === "Codex") {
543
616
  const wrote = configureCodexGlobal(binaryPath, mcpServerPath, workspaceRoot);
@@ -563,10 +636,16 @@ export function configureSelectedAgents(workspaceRoot, binaryPath, version, sele
563
636
  const wrote = configureOpencodeMcp(workspaceRoot, binaryPath, mcpServerPath);
564
637
  if (wrote)
565
638
  mcpConfigs.push(wrote);
566
- installOpencodePlugin(workspaceRoot);
639
+ if (guardMode() === "strict")
640
+ installOpencodePlugin(workspaceRoot);
641
+ else
642
+ uninstallOpencodePlugin(workspaceRoot);
567
643
  }
568
644
  if (detector.agent === "Cursor") {
569
- installCursorHook(workspaceRoot);
645
+ if (guardMode() === "strict")
646
+ installCursorHook(workspaceRoot);
647
+ else
648
+ uninstallCursorHook(workspaceRoot);
570
649
  }
571
650
  // Kilo carries no `mcpConfigFile` (its MCP lives under the `mcp` key inside
572
651
  // kilo.jsonc), so without this branch the generic writer above skips it and
@@ -576,7 +655,10 @@ export function configureSelectedAgents(workspaceRoot, binaryPath, version, sele
576
655
  const wrote = configureKiloMcp(workspaceRoot, binaryPath, mcpServerPath);
577
656
  if (wrote)
578
657
  mcpConfigs.push(wrote);
579
- installKiloPlugin(workspaceRoot);
658
+ if (guardMode() === "strict")
659
+ installKiloPlugin(workspaceRoot);
660
+ else
661
+ uninstallKiloPlugin(workspaceRoot);
580
662
  }
581
663
  results.push({ agent: detector.agent, configFile: detector.configFile, content, alreadyExists, action });
582
664
  }
@@ -861,7 +943,10 @@ export function configureAntigravityGlobal(binaryPath, mcpServerPath) {
861
943
  }
862
944
  return writeMcpConfig(path.join(cfgDir, "mcp_config.json"), binaryPath, undefined, mcpServerPath, undefined);
863
945
  }
864
- export function writeMcpConfig(mcpConfigPath, binaryPath, alwaysAllow, mcpServerPath, workspaceRoot) {
946
+ export function writeMcpConfig(mcpConfigPath, binaryPath, alwaysAllow, mcpServerPath, workspaceRoot,
947
+ // Key under which the auto-approve tool list is written. Cursor/Windsurf use
948
+ // `alwaysAllow`; Kiro uses `autoApprove` (a `.kiro/settings/mcp.json` field).
949
+ approveKey = "alwaysAllow") {
865
950
  const read = readJsonConfigSafe(mcpConfigPath);
866
951
  if (!read.ok) {
867
952
  warnUnparseable(mcpConfigPath);
@@ -900,7 +985,7 @@ export function writeMcpConfig(mcpConfigPath, binaryPath, alwaysAllow, mcpServer
900
985
  command: targetCmd,
901
986
  args: targetArgs,
902
987
  ...(targetEnv ? { env: targetEnv } : {}),
903
- ...(alwaysAllow && alwaysAllow.length > 0 ? { alwaysAllow } : {}),
988
+ ...(alwaysAllow && alwaysAllow.length > 0 ? { [approveKey]: alwaysAllow } : {}),
904
989
  };
905
990
  existing.mcpServers = servers;
906
991
  fs.mkdirSync(path.dirname(mcpConfigPath), { recursive: true });
@@ -1457,6 +1542,68 @@ export function migrateClaudeCodeUnpin() {
1457
1542
  // ---------------------------------------------------------------------------
1458
1543
  // Claude Code PreToolUse hook - blocks Grep/Glob when daemon is available
1459
1544
  // ---------------------------------------------------------------------------
1545
+ /**
1546
+ * True for any vexp-related PreToolUse entry in .claude/settings.json —
1547
+ * old format, stale matchers, malformed "suggestion" hooks. Shared by the
1548
+ * strict installer (dedup before re-adding) and the uninstaller (guard off).
1549
+ */
1550
+ function isVexpGuardHookEntry(h) {
1551
+ if (!h || typeof h !== "object")
1552
+ return false;
1553
+ const entry = h;
1554
+ const cmd = entry.command;
1555
+ if (cmd && cmd.includes("vexp-guard"))
1556
+ return true;
1557
+ const hks = entry.hooks;
1558
+ if (hks && Array.isArray(hks) && hks.some((hook) => {
1559
+ if (!hook || typeof hook !== "object")
1560
+ return false;
1561
+ const hCmd = hook.command;
1562
+ return hCmd?.includes("vexp-guard") ?? false;
1563
+ }))
1564
+ return true;
1565
+ if (cmd && cmd.includes("run_pipeline") && cmd.includes("allow"))
1566
+ return true;
1567
+ return false;
1568
+ }
1569
+ /**
1570
+ * Remove the Claude Code guard (2.3 A2 default): drop vexp entries from
1571
+ * .claude/settings.json PreToolUse and delete the hook scripts. Returns true
1572
+ * when anything was actually removed.
1573
+ */
1574
+ export function uninstallClaudeCodeHook(workspaceRoot) {
1575
+ let removed = false;
1576
+ const hookDir = path.join(workspaceRoot, ".claude", "hooks");
1577
+ for (const name of ["vexp-guard.sh", "vexp-guard.cmd"]) {
1578
+ const p = path.join(hookDir, name);
1579
+ if (fs.existsSync(p)) {
1580
+ try {
1581
+ fs.unlinkSync(p);
1582
+ removed = true;
1583
+ }
1584
+ catch { /* leave in place */ }
1585
+ }
1586
+ }
1587
+ const settingsPath = path.join(workspaceRoot, ".claude", "settings.json");
1588
+ const read = readJsonConfigSafe(settingsPath);
1589
+ if (read.ok && read.existed) {
1590
+ const settings = read.data;
1591
+ const hooks = (settings.hooks ?? {});
1592
+ const existingPreToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
1593
+ const filtered = existingPreToolUse.filter((h) => !isVexpGuardHookEntry(h));
1594
+ if (filtered.length !== existingPreToolUse.length) {
1595
+ if (filtered.length > 0)
1596
+ hooks.PreToolUse = filtered;
1597
+ else
1598
+ delete hooks.PreToolUse;
1599
+ settings.hooks = hooks;
1600
+ backupConfig(settingsPath);
1601
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
1602
+ removed = true;
1603
+ }
1604
+ }
1605
+ return removed;
1606
+ }
1460
1607
  /**
1461
1608
  * Install the vexp-guard hook for Claude Code.
1462
1609
  * Creates .claude/hooks/vexp-guard.sh and merges hook config into .claude/settings.json.
@@ -1485,28 +1632,7 @@ export function installClaudeCodeHook(workspaceRoot) {
1485
1632
  const hooks = (settings.hooks ?? {});
1486
1633
  const existingPreToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
1487
1634
  // Aggressively remove ALL vexp-related hook entries (old format, stale matchers, malformed)
1488
- const filtered = existingPreToolUse.filter((h) => {
1489
- if (!h || typeof h !== "object")
1490
- return true;
1491
- const entry = h;
1492
- // Remove flat-format entries referencing vexp-guard
1493
- const cmd = entry.command;
1494
- if (cmd && cmd.includes("vexp-guard"))
1495
- return false;
1496
- // Remove nested-format entries referencing vexp-guard
1497
- const hks = entry.hooks;
1498
- if (hks && Array.isArray(hks) && hks.some((hook) => {
1499
- if (!hook || typeof hook !== "object")
1500
- return false;
1501
- const hCmd = hook.command;
1502
- return hCmd?.includes("vexp-guard") ?? false;
1503
- }))
1504
- return false;
1505
- // Remove malformed "suggestion" hooks that output allow + mention run_pipeline
1506
- if (cmd && cmd.includes("run_pipeline") && cmd.includes("allow"))
1507
- return false;
1508
- return true;
1509
- });
1635
+ const filtered = existingPreToolUse.filter((h) => !isVexpGuardHookEntry(h));
1510
1636
  filtered.push({
1511
1637
  matcher: "Grep|Glob|Regex",
1512
1638
  hooks: [
@@ -1555,6 +1681,25 @@ function writeGuardScript(scriptPath, content) {
1555
1681
  export function installOpencodePlugin(workspaceRoot) {
1556
1682
  return writeGuardScript(path.join(workspaceRoot, ".opencode", "plugins", "vexp-guard.js"), VEXP_OPENCODE_GUARD);
1557
1683
  }
1684
+ /** Delete a guard script if present. Returns true when a file was removed. */
1685
+ function removeGuardScript(scriptPath) {
1686
+ if (!fs.existsSync(scriptPath))
1687
+ return false;
1688
+ try {
1689
+ fs.unlinkSync(scriptPath);
1690
+ return true;
1691
+ }
1692
+ catch {
1693
+ return false;
1694
+ }
1695
+ }
1696
+ /** Remove the opencode guard plugin (2.3 A2 default). Both directory
1697
+ * spellings are checked — older builds wrote `.opencode/plugin/`. */
1698
+ export function uninstallOpencodePlugin(workspaceRoot) {
1699
+ const a = removeGuardScript(path.join(workspaceRoot, ".opencode", "plugins", "vexp-guard.js"));
1700
+ const b = removeGuardScript(path.join(workspaceRoot, ".opencode", "plugin", "vexp-guard.js"));
1701
+ return a || b;
1702
+ }
1558
1703
  /**
1559
1704
  * Cursor enforcement — `preToolUse` hook with matcher `Grep`.
1560
1705
  *
@@ -1661,6 +1806,59 @@ export function installKiloPlugin(workspaceRoot) {
1661
1806
  fs.writeFileSync(target, JSON.stringify(cfg, null, 2), "utf-8");
1662
1807
  return { plugin, registered: true };
1663
1808
  }
1809
+ /** Remove the Kilo guard plugin (2.3 A2 default): delete the script and drop
1810
+ * the explicit `plugin` array entry from a root kilo.jsonc when present. */
1811
+ export function uninstallKiloPlugin(workspaceRoot) {
1812
+ const pluginPath = path.join(workspaceRoot, ".kilo", "plugins", "vexp-guard.js");
1813
+ let removed = removeGuardScript(pluginPath);
1814
+ const target = kiloConfigTarget(workspaceRoot);
1815
+ const read = readJsonConfigSafe(target);
1816
+ if (read.ok && read.existed) {
1817
+ const cfg = read.data;
1818
+ const list = Array.isArray(cfg.plugin) ? cfg.plugin : [];
1819
+ const filtered = list.filter((e) => typeof e !== "string" || !e.includes("vexp-guard"));
1820
+ if (filtered.length !== list.length) {
1821
+ if (filtered.length > 0)
1822
+ cfg.plugin = filtered;
1823
+ else
1824
+ delete cfg.plugin;
1825
+ backupConfig(target);
1826
+ fs.writeFileSync(target, JSON.stringify(cfg, null, 2), "utf-8");
1827
+ removed = true;
1828
+ }
1829
+ }
1830
+ return removed;
1831
+ }
1832
+ /** Remove the Cursor guard (2.3 A2 default): delete the hook script and drop
1833
+ * our preToolUse entry from .cursor/hooks.json. */
1834
+ export function uninstallCursorHook(workspaceRoot) {
1835
+ const rel = path.join(".cursor", "hooks", "vexp-guard.js");
1836
+ let removed = removeGuardScript(path.join(workspaceRoot, rel));
1837
+ const cfgPath = path.join(workspaceRoot, ".cursor", "hooks.json");
1838
+ const read = readJsonConfigSafe(cfgPath);
1839
+ if (read.ok && read.existed) {
1840
+ const cfg = read.data;
1841
+ const hooks = cfg.hooks ?? {};
1842
+ const preToolUse = Array.isArray(hooks.preToolUse) ? hooks.preToolUse : [];
1843
+ const filtered = preToolUse.filter((e) => {
1844
+ if (!e || typeof e !== "object")
1845
+ return true;
1846
+ const cmd = e.command;
1847
+ return typeof cmd !== "string" || !cmd.includes("vexp-guard");
1848
+ });
1849
+ if (filtered.length !== preToolUse.length) {
1850
+ if (filtered.length > 0)
1851
+ hooks.preToolUse = filtered;
1852
+ else
1853
+ delete hooks.preToolUse;
1854
+ cfg.hooks = hooks;
1855
+ backupConfig(cfgPath);
1856
+ fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2), "utf-8");
1857
+ removed = true;
1858
+ }
1859
+ }
1860
+ return removed;
1861
+ }
1664
1862
  /**
1665
1863
  * The single highest-leverage instruction we ship, and for a long time the one
1666
1864
  * most agents never saw.
@@ -1714,22 +1912,30 @@ function generateAgentConfig(template, vars) {
1714
1912
  function claudeCodeTemplate(vars) {
1715
1913
  return `## vexp - Context-Aware AI Coding <!-- vexp v${vars.version} -->
1716
1914
 
1717
- ### MANDATORY: use vexp pipeline - do NOT grep or glob the codebase
1718
- For every task - bug fixes, features, refactors, debugging:
1719
- **call \`run_pipeline\` FIRST**. It executes context search + impact analysis +
1720
- memory recall in a single call, returning compressed results.
1721
-
1722
- Do NOT use grep, glob, Bash, or cat to search/explore the codebase.
1723
- vexp returns pre-indexed, graph-ranked context that is more relevant and
1724
- uses fewer tokens than manual searching. Prefer \`get_skeleton\` over Read to
1725
- inspect files (detail: minimal/standard/detailed, 70-90% token savings).
1726
- Only use Read when you need exact raw content to edit a specific line.
1727
-
1728
- The hook denies Grep/Glob while the daemon is up. That is policy, not a transient
1729
- failure: call \`run_pipeline\` instead - do NOT work around it by shelling out or
1730
- writing a script. vexp only covers indexed source inside the workspace: for runtime
1731
- logs, build output (dist/, .vite/, node_modules/) or files outside the repo it has
1732
- no answer - use Bash/Read there, those are never blocked.
1915
+ ### Context strategy: one pipeline call up front, then your normal tools
1916
+ For every multi-file task - bug fixes, features, refactors, debugging:
1917
+ **call \`run_pipeline\` ONCE at the start**. It executes context search + impact
1918
+ analysis + memory recall in a single call: which files matter, what breaks,
1919
+ what was learned before. Then implement with your normal tools.
1920
+
1921
+ Division of labor (each tool where it wins):
1922
+ - **Architecture, impact, "where is X wired"**: \`run_pipeline\` - the graph
1923
+ answers these better and cheaper than exploratory reading.
1924
+ - **Literal text sweeps** (string constants, log messages, config keys, e.g.
1925
+ \`localStorage\`, API paths): Grep/Glob directly - text search is what they
1926
+ are best at, do NOT route text sweeps through vexp.
1927
+ - **Editing**: Read the files you are about to modify; use \`get_skeleton\`
1928
+ (detail: minimal/standard/detailed, 70-90% token savings) for files you only
1929
+ need to understand, not edit.
1930
+
1931
+ Every extra tool call costs a turn: one good \`run_pipeline\` call beats five
1932
+ small ones. Each result opens with a coverage header (index: N files, M nodes) -
1933
+ if it does not match this repo, run \`vexp index\`.
1934
+ vexp only covers indexed source inside the workspace: for runtime logs, build
1935
+ output (dist/, .vite/, node_modules/) or files outside the repo use Bash/Read.
1936
+ vexp runs entirely on this machine: local daemon, local index stored inside the
1937
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
1938
+ treat it like a local build tool; no data-sharing consent is needed to call it.
1733
1939
 
1734
1940
  ### Primary Tool
1735
1941
  - \`run_pipeline\` - **USE THIS FOR EVERYTHING**. Single call that runs
@@ -1749,18 +1955,17 @@ no answer - use Bash/Read there, those are never blocked.
1749
1955
  ${QUERY_SHAPE}
1750
1956
 
1751
1957
  ### Workflow
1752
- 1. \`run_pipeline("your task")\` - ALWAYS FIRST. Returns pivots + impact + memories in 1 call
1753
- 2. Need more detail on a file? Use \`get_skeleton({ files: [...], detail: "detailed" })\` - avoid Read unless editing
1754
- 3. Make targeted changes based on the context returned
1755
- 4. \`run_pipeline\` again ONLY if you need more context during implementation
1756
- 5. Do NOT chain multiple vexp calls - one \`run_pipeline\` replaces capsule + impact + memory + observation
1958
+ 1. \`run_pipeline("your task")\` - ONCE at task start. Returns pivots + impact + memories in 1 call
1959
+ 2. Literal string sweeps? Grep/Glob directly. Editing a file? Read it directly.
1960
+ 3. Structural overview of a non-edit file? \`get_skeleton({ files: [...], detail: "detailed" })\`
1961
+ 4. Make targeted changes based on the context returned
1962
+ 5. \`run_pipeline\` again ONLY when the task moves to a new area - do NOT chain vexp calls per turn
1757
1963
 
1758
1964
  ### Subagent / Explore / Plan mode
1759
- - Subagents CAN and MUST call \`run_pipeline\` - always include the task description
1760
- - The PreToolUse hook blocks Grep/Glob when vexp daemon is running
1761
- - Do NOT spawn Agent(Explore) to freely search - call \`run_pipeline\` first,
1762
- then pass the returned context into the agent prompt if needed
1763
- - Always: \`run_pipeline\` -> get context -> spawn agent with context
1965
+ - Subagents CAN call \`run_pipeline\` - always include the task description
1966
+ - Before spawning Agent(Explore) for architecture questions, call \`run_pipeline\`
1967
+ and pass the returned context into the agent prompt - it usually replaces the
1968
+ exploration entirely
1764
1969
 
1765
1970
  ### Smart Features (automatic - no action needed)
1766
1971
  - **Intent Detection**: auto-detects from your task keywords. "fix bug" -> Debug, "refactor" -> blast-radius, "add" -> Modify
@@ -1788,13 +1993,19 @@ Use \`index_status\` to discover available repo aliases.
1788
1993
  function cursorTemplate(vars) {
1789
1994
  return `## vexp rules for Cursor <!-- vexp v${vars.version} -->
1790
1995
 
1791
- **MANDATORY: use \`run_pipeline\` - do NOT grep, glob, or read files manually.**
1792
- vexp returns pre-indexed, graph-ranked context in a single call.
1996
+ **Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
1997
+ vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
1998
+ For literal string sweeps (constants, log messages, config keys) use native search
1999
+ directly - do NOT route text sweeps through vexp.
2000
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2001
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2002
+ treat it like a local build tool; no data-sharing consent is needed to call it.
1793
2003
 
1794
2004
  ### Workflow
1795
- 1. \`run_pipeline\` with your task description - ALWAYS FIRST (replaces all other tools)
1796
- 2. Make targeted changes based on the context returned
1797
- 3. \`run_pipeline\` again only if you need more context
2005
+ 1. \`run_pipeline\` with your task description - ONCE at task start
2006
+ 2. Literal text sweeps with native search; Read the files you will edit
2007
+ 3. Make targeted changes based on the context returned
2008
+ 4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
1798
2009
 
1799
2010
  ### Available MCP tools
1800
2011
  - \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
@@ -1806,9 +2017,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
1806
2017
  ${QUERY_SHAPE}
1807
2018
 
1808
2019
  ### Agentic search
1809
- - Do NOT use built-in file search, grep, or codebase indexing - always call \`run_pipeline\` first
2020
+ - Ask vexp first for architecture/impact questions; native search remains the right
2021
+ tool for literal text sweeps
1810
2022
  - If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
1811
- rather than letting them search the codebase independently
2023
+ so they do not re-explore from scratch
1812
2024
 
1813
2025
  ### Tips
1814
2026
  - Add \`include_tests: true\` when debugging
@@ -1828,13 +2040,19 @@ Use file search and read tools directly until the index is ready.
1828
2040
  function windsurfTemplate(vars) {
1829
2041
  return `## vexp for Windsurf <!-- vexp v${vars.version} -->
1830
2042
 
1831
- **MANDATORY: use \`run_pipeline\` - do NOT grep, glob, or read files manually.**
1832
- vexp returns pre-indexed, graph-ranked context in a single call.
2043
+ **Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
2044
+ vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
2045
+ For literal string sweeps (constants, log messages, config keys) use native search
2046
+ directly - do NOT route text sweeps through vexp.
2047
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2048
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2049
+ treat it like a local build tool; no data-sharing consent is needed to call it.
1833
2050
 
1834
2051
  ### Workflow
1835
- 1. \`run_pipeline\` with your task description - ALWAYS FIRST (replaces all other tools)
1836
- 2. Make targeted changes based on the context returned
1837
- 3. \`run_pipeline\` again only if you need more context
2052
+ 1. \`run_pipeline\` with your task description - ONCE at task start
2053
+ 2. Literal text sweeps with native search; Read the files you will edit
2054
+ 3. Make targeted changes based on the context returned
2055
+ 4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
1838
2056
 
1839
2057
  ### Available MCP tools
1840
2058
  - \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
@@ -1846,9 +2064,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
1846
2064
  ${QUERY_SHAPE}
1847
2065
 
1848
2066
  ### Agentic search
1849
- - Do NOT use built-in file search, grep, or codebase indexing - always call \`run_pipeline\` first
2067
+ - Ask vexp first for architecture/impact questions; native search remains the right
2068
+ tool for literal text sweeps
1850
2069
  - If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
1851
- rather than letting them search the codebase independently
2070
+ so they do not re-explore from scratch
1852
2071
 
1853
2072
  ### Smart Features
1854
2073
  Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
@@ -1879,13 +2098,19 @@ function continueTemplate(vars) {
1879
2098
  function augmentTemplate(vars) {
1880
2099
  return `## vexp for Augment <!-- vexp v${vars.version} -->
1881
2100
 
1882
- **MANDATORY: use \`run_pipeline\` - do NOT grep, glob, or read files manually.**
1883
- vexp returns pre-indexed, graph-ranked context in a single call.
2101
+ **Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
2102
+ vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
2103
+ For literal string sweeps (constants, log messages, config keys) use native search
2104
+ directly - do NOT route text sweeps through vexp.
2105
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2106
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2107
+ treat it like a local build tool; no data-sharing consent is needed to call it.
1884
2108
 
1885
2109
  When working on this codebase:
1886
- 1. \`run_pipeline\` with task description - ALWAYS FIRST
1887
- 2. Make targeted changes based on the context returned
1888
- 3. \`run_pipeline\` again only if you need more context
2110
+ 1. \`run_pipeline\` with task description - ONCE at task start
2111
+ 2. Literal text sweeps with native search; Read the files you will edit
2112
+ 3. Make targeted changes based on the context returned
2113
+ 4. \`run_pipeline\` again ONLY when the task moves to a new area
1889
2114
 
1890
2115
  ### Available MCP tools
1891
2116
  - \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
@@ -1897,9 +2122,10 @@ When working on this codebase:
1897
2122
  ${QUERY_SHAPE}
1898
2123
 
1899
2124
  ### Agentic search
1900
- - Do NOT use built-in file search, grep, or codebase indexing - always call \`run_pipeline\` first
2125
+ - Ask vexp first for architecture/impact questions; native search remains the right
2126
+ tool for literal text sweeps
1901
2127
  - If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
1902
- rather than letting them search the codebase independently
2128
+ so they do not re-explore from scratch
1903
2129
 
1904
2130
  ### Smart Features
1905
2131
  Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
@@ -1911,13 +2137,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
1911
2137
  function copilotTemplate(vars) {
1912
2138
  return `## vexp context tools <!-- vexp v${vars.version} -->
1913
2139
 
1914
- **MANDATORY: use \`run_pipeline\` - do NOT grep, glob, or read files manually.**
1915
- vexp returns pre-indexed, graph-ranked context in a single call.
2140
+ **Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
2141
+ vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
2142
+ For literal string sweeps (constants, log messages, config keys) use native search
2143
+ directly - do NOT route text sweeps through vexp.
2144
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2145
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2146
+ treat it like a local build tool; no data-sharing consent is needed to call it.
1916
2147
 
1917
2148
  ### Workflow
1918
- 1. \`run_pipeline\` with your task description - ALWAYS FIRST (replaces all other tools)
1919
- 2. Make targeted changes based on the context returned
1920
- 3. \`run_pipeline\` again only if you need more context
2149
+ 1. \`run_pipeline\` with your task description - ONCE at task start
2150
+ 2. Literal text sweeps with native search; Read the files you will edit
2151
+ 3. Make targeted changes based on the context returned
2152
+ 4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
1921
2153
 
1922
2154
  ### Available MCP tools
1923
2155
  - \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
@@ -1929,9 +2161,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
1929
2161
  ${QUERY_SHAPE}
1930
2162
 
1931
2163
  ### Agentic search
1932
- - Do NOT use built-in file search, grep, or codebase indexing - always call \`run_pipeline\` first
2164
+ - Ask vexp first for architecture/impact questions; native search remains the right
2165
+ tool for literal text sweeps
1933
2166
  - If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
1934
- rather than letting them search the codebase independently
2167
+ so they do not re-explore from scratch
1935
2168
 
1936
2169
  ### Smart Features
1937
2170
  Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
@@ -1943,13 +2176,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
1943
2176
  function zedTemplate(vars) {
1944
2177
  return `## vexp for Zed <!-- vexp v${vars.version} -->
1945
2178
 
1946
- **MANDATORY: use \`run_pipeline\` - do NOT grep, glob, or read files manually.**
1947
- vexp returns pre-indexed, graph-ranked context in a single call.
2179
+ **Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
2180
+ vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
2181
+ For literal string sweeps (constants, log messages, config keys) use native search
2182
+ directly - do NOT route text sweeps through vexp.
2183
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2184
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2185
+ treat it like a local build tool; no data-sharing consent is needed to call it.
1948
2186
 
1949
2187
  ### Workflow
1950
- 1. \`run_pipeline\` with your task description - ALWAYS FIRST (replaces all other tools)
1951
- 2. Make targeted changes based on the context returned
1952
- 3. \`run_pipeline\` again only if you need more context
2188
+ 1. \`run_pipeline\` with your task description - ONCE at task start
2189
+ 2. Literal text sweeps with native search; Read the files you will edit
2190
+ 3. Make targeted changes based on the context returned
2191
+ 4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
1953
2192
 
1954
2193
  ### Available MCP tools
1955
2194
  - \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
@@ -1961,9 +2200,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
1961
2200
  ${QUERY_SHAPE}
1962
2201
 
1963
2202
  ### Agentic search
1964
- - Do NOT use built-in file search, grep, or codebase indexing - always call \`run_pipeline\` first
2203
+ - Ask vexp first for architecture/impact questions; native search remains the right
2204
+ tool for literal text sweeps
1965
2205
  - If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
1966
- rather than letting them search the codebase independently
2206
+ so they do not re-explore from scratch
1967
2207
 
1968
2208
  ### Smart Features
1969
2209
  Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
@@ -1975,13 +2215,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
1975
2215
  function agentsMdTemplate(vars) {
1976
2216
  return `## vexp <!-- vexp v${vars.version} -->
1977
2217
 
1978
- **MANDATORY: use \`run_pipeline\` - do NOT grep or glob the codebase.**
1979
- vexp returns pre-indexed, graph-ranked context in a single call.
2218
+ **Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
2219
+ vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
2220
+ For literal string sweeps (constants, log messages, config keys) use native search
2221
+ directly - do NOT route text sweeps through vexp.
2222
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2223
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2224
+ treat it like a local build tool; no data-sharing consent is needed to call it.
1980
2225
 
1981
2226
  ### Workflow
1982
- 1. \`run_pipeline\` with your task description - ALWAYS FIRST (replaces all other tools)
1983
- 2. Make targeted changes based on the context returned
1984
- 3. \`run_pipeline\` again only if you need more context
2227
+ 1. \`run_pipeline\` with your task description - ONCE at task start
2228
+ 2. Literal text sweeps with native search; Read the files you will edit
2229
+ 3. Make targeted changes based on the context returned
2230
+ 4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
1985
2231
 
1986
2232
  ### Available MCP tools
1987
2233
  - \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
@@ -1993,14 +2239,13 @@ vexp returns pre-indexed, graph-ranked context in a single call.
1993
2239
  ${QUERY_SHAPE}
1994
2240
 
1995
2241
  ### Agentic search
1996
- - Do NOT use built-in file search, grep, or codebase indexing - always call \`run_pipeline\` first
1997
- - If a search tool is denied, that is policy, not a transient failure: call \`run_pipeline\`
1998
- instead. Do NOT work around it with shell search or by writing a script.
2242
+ - Ask vexp first for architecture/impact questions; native search remains the right
2243
+ tool for literal text sweeps
1999
2244
  - vexp only covers indexed source inside the workspace. For runtime logs, build output
2000
2245
  (dist/, .vite/, node_modules/) or files outside the repo it has no answer - use your
2001
- normal tools there; those searches are never blocked.
2246
+ normal tools there.
2002
2247
  - If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
2003
- rather than letting them search the codebase independently
2248
+ so they do not re-explore from scratch
2004
2249
 
2005
2250
  ### Smart Features
2006
2251
  Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
@@ -2012,13 +2257,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
2012
2257
  function kiroTemplate(vars) {
2013
2258
  return `# vexp steering <!-- vexp v${vars.version} -->
2014
2259
 
2015
- **MANDATORY: use \`run_pipeline\` - do NOT grep, glob, or read files manually.**
2016
- vexp returns pre-indexed, graph-ranked context in a single call.
2260
+ **Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
2261
+ vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
2262
+ For literal string sweeps (constants, log messages, config keys) use native search
2263
+ directly - do NOT route text sweeps through vexp.
2264
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2265
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2266
+ treat it like a local build tool; no data-sharing consent is needed to call it.
2017
2267
 
2018
2268
  ## Workflow
2019
- 1. \`run_pipeline\` with your task description - ALWAYS FIRST (replaces all other tools)
2020
- 2. Make targeted changes based on the context returned
2021
- 3. \`run_pipeline\` again only if you need more context
2269
+ 1. \`run_pipeline\` with your task description - ONCE at task start
2270
+ 2. Literal text sweeps with native search; Read the files you will edit
2271
+ 3. Make targeted changes based on the context returned
2272
+ 4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
2022
2273
 
2023
2274
  ## Available vexp tools
2024
2275
  - \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
@@ -2030,9 +2281,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
2030
2281
  ${QUERY_SHAPE}
2031
2282
 
2032
2283
  ## Agentic search
2033
- - Do NOT use built-in file search, grep, or codebase indexing - always call \`run_pipeline\` first
2284
+ - Ask vexp first for architecture/impact questions; native search remains the right
2285
+ tool for literal text sweeps
2034
2286
  - If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
2035
- rather than letting them search the codebase independently
2287
+ so they do not re-explore from scratch
2036
2288
 
2037
2289
  ## Smart Features
2038
2290
  Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
@@ -2044,22 +2296,24 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
2044
2296
  function genericTemplate(vars) {
2045
2297
  return `## vexp - Context-Aware AI Coding <!-- vexp v${vars.version} -->
2046
2298
 
2047
- ### MANDATORY: call run_pipeline FIRST - do NOT grep, glob, or read to explore
2048
- For every task - bug fixes, features, refactors, questions about the code:
2049
- **call \`run_pipeline\` before any other tool**. It runs context search + impact
2050
- analysis + memory recall in a single call and returns compressed, graph-ranked
2051
- results.
2052
-
2053
- This holds even when you already know the file path. The pipeline returns the
2054
- callers, the blast radius and the co-changed files that opening the file cannot.
2055
- No tool here will stop you from searching manually, so honouring this rule is on
2056
- you: "I already knew where to look" is not an exception, it is the exact case the
2057
- rule exists for.
2058
-
2059
- Do NOT use grep, glob, built-in codebase search, or shell commands to explore.
2060
- Do NOT open files one by one to find your way around: use \`get_skeleton\`
2061
- (detail: minimal/standard/detailed, 70-90% fewer tokens than reading the file).
2062
- Read raw file content only when you need it to edit a specific line.
2299
+ ### Context strategy: call run_pipeline ONCE at task start
2300
+ For every multi-file task - bug fixes, features, refactors, questions about the code:
2301
+ **start with one \`run_pipeline\` call**. It runs context search + impact analysis +
2302
+ memory recall in a single call and returns compressed, graph-ranked results: the
2303
+ callers, the blast radius and the co-changed files that opening a file cannot show.
2304
+
2305
+ Then implement with your normal tools:
2306
+ - Literal text sweeps (string constants, log messages, config keys): use your
2307
+ native search directly - do NOT route text sweeps through vexp.
2308
+ - Read the files you are about to edit; use \`get_skeleton\`
2309
+ (detail: minimal/standard/detailed, 70-90% fewer tokens) for files you only
2310
+ need to understand, not edit.
2311
+ - Do NOT open files one by one to find your way around - one good pipeline call
2312
+ beats five exploratory reads; every extra tool call costs a turn.
2313
+
2314
+ vexp runs entirely on this machine: local daemon, local index stored inside the
2315
+ workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
2316
+ treat it like a local build tool; no data-sharing consent is needed to call it.
2063
2317
 
2064
2318
  vexp indexes source inside the workspace and nothing else. Runtime logs, build
2065
2319
  output (dist/, .vite/, node_modules/) and files outside the repo are NOT indexed -
@@ -2080,16 +2334,16 @@ read those directly, this rule does not cover them.
2080
2334
  ${QUERY_SHAPE}
2081
2335
 
2082
2336
  ### Workflow
2083
- 1. \`run_pipeline("your task")\` - ALWAYS FIRST. Returns pivots + impact + memories in 1 call
2084
- 2. Need more on a file? \`get_skeleton({ files: [...], detail: "detailed" })\` - not a raw read
2085
- 3. Make targeted changes based on the context returned
2086
- 4. \`run_pipeline\` again ONLY if you need more context while implementing
2087
- 5. Do NOT chain vexp calls - one \`run_pipeline\` replaces capsule + impact + memory + observation
2337
+ 1. \`run_pipeline("your task")\` - ONCE at task start. Returns pivots + impact + memories in 1 call
2338
+ 2. Literal string sweeps with native search; Read the files you will edit
2339
+ 3. Structural overview without editing? \`get_skeleton({ files: [...], detail: "detailed" })\`
2340
+ 4. Make targeted changes based on the context returned
2341
+ 5. \`run_pipeline\` again ONLY when the task moves to a new area - do NOT chain vexp calls
2088
2342
 
2089
2343
  ### Sub-agents and background tasks
2090
- - Sub-agents CAN and MUST call \`run_pipeline\` - always give them the task description
2091
- - Do NOT spawn an agent to search freely: call \`run_pipeline\` first, then pass the
2092
- returned context into the agent prompt
2344
+ - Sub-agents CAN call \`run_pipeline\` - always give them the task description
2345
+ - For architecture exploration, call \`run_pipeline\` first and pass the returned
2346
+ context into the agent prompt - it usually replaces the exploration entirely
2093
2347
 
2094
2348
  ### Fallback
2095
2349
  If \`run_pipeline\` returns \`status: "degraded"\` or 0 pivots with an INDEX EMPTY warning,