From 46f15909d22c4dbefd4d2c9512dc4356936c1802 Mon Sep 17 00:00:00 2001 From: Sinabina Date: Thu, 23 Jul 2026 11:34:02 -0700 Subject: [PATCH 1/4] feat: session-start indexing offer gate (suggest) in code-intelligence shouldOfferIndexing() offers indexing at most once per machine: only for a large repo (tracked-file count >= 1000), never after a provider selection or an explicit decline. `select none` now persists the decline; the new `gstack-code-intelligence suggest [path] [--json]` command emits the verdict plus the provider options with reasons for the AskUserQuestion flow. Co-Authored-By: Claude Fable 5 --- bin/gstack-code-intelligence | 46 ++++++++++++++++++++++- lib/code-intelligence/index.ts | 7 ++++ lib/code-intelligence/selection.ts | 9 ++++- lib/code-intelligence/suggest.ts | 55 +++++++++++++++++++++++++++ test/code-intelligence.test.ts | 60 ++++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 lib/code-intelligence/suggest.ts diff --git a/bin/gstack-code-intelligence b/bin/gstack-code-intelligence index e9ea163f40..799ba671a3 100755 --- a/bin/gstack-code-intelligence +++ b/bin/gstack-code-intelligence @@ -5,6 +5,7 @@ * fine and callers use grep / the file-only decision store. * * Usage: + * gstack-code-intelligence suggest [repo] [--json] # should the one-time indexing offer be made here? * gstack-code-intelligence options # list providers (GBrain first) + availability * gstack-code-intelligence status # current selection + availability * gstack-code-intelligence select @@ -30,6 +31,7 @@ import { setConsent, setProvider, setRoot, + shouldOfferIndexing, type CodeProviderId, } from "../lib/code-intelligence"; @@ -69,10 +71,48 @@ async function cmdStatus(): Promise { for (const a of avail) out(` ${LABEL[a.id]}: ${a.available ? "available" : "unavailable"} (${a.detail})`); } +/** + * The one-time session-start offer gate. Prints (or emits as JSON) whether an + * agent should ask the user about indexing this repo, and when it should, the + * provider options with their reasons so the question is self-contained. + */ +async function cmdSuggest(rest: string[]): Promise { + const json = rest.includes("--json"); + const pathArg = rest.find((a) => !a.startsWith("--")); + const repoPath = resolve(pathArg ?? process.cwd()); + const suggestion = shouldOfferIndexing(repoPath); + if (!suggestion.offer) { + if (json) { + out(JSON.stringify({ ...suggestion, repoPath })); + } else { + out(`no offer (${suggestion.reason}${suggestion.fileCount != null ? `, ${suggestion.fileCount} tracked files` : ""})`); + } + return; + } + const avail = await detectAvailable(); + if (json) { + out(JSON.stringify({ + ...suggestion, + repoPath, + options: avail.map((a) => ({ + id: a.id, + label: LABEL[a.id], + reason: NOTE[a.id], + local: providerById(a.id).local, + available: a.available, + detail: a.detail, + })), + })); + return; + } + out(`offer indexing: ${suggestion.fileCount} tracked files (threshold ${suggestion.threshold}) and no prior decision`); + await cmdOptions(); +} + function cmdSelect(arg: string | undefined): void { if (arg === "none") { setProvider(null); - out("code-intelligence provider cleared; gstack uses grep / file-only fallback"); + out("code-intelligence declined; gstack uses grep / file-only fallback and will not ask again"); return; } if (!arg || !PROVIDER_IDS.has(arg as CodeProviderId)) { @@ -144,6 +184,8 @@ function handleProviderError(err: unknown, label: string): never { async function main(): Promise { const [action, ...rest] = process.argv.slice(2); switch (action) { + case "suggest": + return cmdSuggest(rest); case "options": return cmdOptions(); case "status": @@ -157,7 +199,7 @@ async function main(): Promise { case "search": return cmdSearch(rest); default: - fail("Usage: options | status | select | consent [path] | index [path] | search "); + fail("Usage: suggest [path] [--json] | options | status | select | consent [path] | index [path] | search "); } } diff --git a/lib/code-intelligence/index.ts b/lib/code-intelligence/index.ts index 6b387ff8c2..82a7ab8847 100644 --- a/lib/code-intelligence/index.ts +++ b/lib/code-intelligence/index.ts @@ -16,6 +16,13 @@ export { getRoot, type Selection, } from "./selection"; +export { + LARGE_REPO_FILE_THRESHOLD, + shouldOfferIndexing, + trackedFileCount, + type Suggestion, + type SuggestReason, +} from "./suggest"; export { RECOMMENDED_ORDER, providerById, diff --git a/lib/code-intelligence/selection.ts b/lib/code-intelligence/selection.ts index 22d98a69d6..12a617e66b 100644 --- a/lib/code-intelligence/selection.ts +++ b/lib/code-intelligence/selection.ts @@ -20,9 +20,11 @@ export interface Selection { consents: Record; /** Provider id → the absolute repo path it last indexed (so search finds it). */ roots: Record; + /** User explicitly chose no indexing — never offer again. */ + declined: boolean; } -const EMPTY: Selection = { provider: null, consents: {}, roots: {} }; +const EMPTY: Selection = { provider: null, consents: {}, roots: {}, declined: false }; function storePath(env: NodeJS.ProcessEnv = process.env): string { const home = env.GSTACK_HOME || join(env.HOME || homedir(), ".gstack"); @@ -38,6 +40,7 @@ export function readSelection(env: NodeJS.ProcessEnv = process.env): Selection { provider: raw.provider ?? null, consents: raw.consents && typeof raw.consents === "object" ? raw.consents : {}, roots: raw.roots && typeof raw.roots === "object" ? raw.roots : {}, + declined: raw.declined === true, }; } catch { return { ...EMPTY }; @@ -53,7 +56,9 @@ function write(selection: Selection, env: NodeJS.ProcessEnv = process.env): void } export function setProvider(provider: CodeProviderId | null, env: NodeJS.ProcessEnv = process.env): Selection { - const next = { ...readSelection(env), provider }; + // Choosing a provider clears a prior decline; clearing to null records one, + // so the session-start offer is never repeated after an explicit "none". + const next = { ...readSelection(env), provider, declined: provider === null }; write(next, env); return next; } diff --git a/lib/code-intelligence/suggest.ts b/lib/code-intelligence/suggest.ts new file mode 100644 index 0000000000..48bb6b736a --- /dev/null +++ b/lib/code-intelligence/suggest.ts @@ -0,0 +1,55 @@ +/** + * suggest — should the session-start indexing offer be made for this repo? + * + * The offer fires at most once per machine: never when a provider is already + * selected, never after an explicit decline (`select none`), and never for + * small repos where grep is already fast. Detection is cheap and local + * (`git ls-files` count); a non-repo directory never triggers the offer. + */ + +import { spawnSync } from "child_process"; +import { resolve } from "path"; +import { readSelection } from "./selection"; + +// ponytail: single tracked-file-count knob for "large"; add a LOC signal if it misfires +/** Tracked-file count at which indexing starts paying for itself. */ +export const LARGE_REPO_FILE_THRESHOLD = 1000; + +export type SuggestReason = + | "provider-selected" + | "declined" + | "not-a-repo" + | "small-repo" + | "large-repo"; + +export interface Suggestion { + offer: boolean; + reason: SuggestReason; + fileCount: number | null; + threshold: number; +} + +/** Count of git-tracked files, or null when the path is not a git repo. */ +export function trackedFileCount(repoPath: string): number | null { + const result = spawnSync("git", ["-C", resolve(repoPath), "ls-files"], { + encoding: "utf-8", + maxBuffer: 64 * 1024 * 1024, + }); + if (result.status !== 0 || typeof result.stdout !== "string") return null; + const out = result.stdout.trim(); + return out ? out.split("\n").length : 0; +} + +export function shouldOfferIndexing( + repoPath: string, + opts: { env?: NodeJS.ProcessEnv; threshold?: number } = {}, +): Suggestion { + const threshold = opts.threshold ?? LARGE_REPO_FILE_THRESHOLD; + const selection = readSelection(opts.env); + if (selection.provider) return { offer: false, reason: "provider-selected", fileCount: null, threshold }; + if (selection.declined) return { offer: false, reason: "declined", fileCount: null, threshold }; + const fileCount = trackedFileCount(repoPath); + if (fileCount === null) return { offer: false, reason: "not-a-repo", fileCount, threshold }; + if (fileCount < threshold) return { offer: false, reason: "small-repo", fileCount, threshold }; + return { offer: true, reason: "large-repo", fileCount, threshold }; +} diff --git a/test/code-intelligence.test.ts b/test/code-intelligence.test.ts index 62060e51e2..d8f63c01db 100644 --- a/test/code-intelligence.test.ts +++ b/test/code-intelligence.test.ts @@ -28,6 +28,8 @@ import { getRoot, resolveSelectedProvider, RECOMMENDED_ORDER, + shouldOfferIndexing, + trackedFileCount, } from "../lib/code-intelligence"; describe("capability matrix", () => { @@ -129,6 +131,64 @@ describe("selection store + provider-OFF", () => { setRoot("graphify", "/tmp/some/repo", env); expect(getRoot("graphify", env)).toBe(path.resolve("/tmp/some/repo")); }); + + test("select none records the decline; selecting a provider clears it", () => { + setProvider(null, env); + expect(readSelection(env).declined).toBe(true); + setProvider("graphify", env); + expect(readSelection(env).declined).toBe(false); + }); +}); + +describe("session-start indexing offer (suggest)", () => { + let home: string; + let repo: string; + let env: NodeJS.ProcessEnv; + beforeEach(() => { + home = fs.mkdtempSync(path.join(os.tmpdir(), "ci-home-")); + repo = fs.mkdtempSync(path.join(os.tmpdir(), "ci-repo-")); + env = { ...process.env, GSTACK_HOME: home }; + Bun.spawnSync(["git", "init", "-q", repo]); + for (const name of ["a.ts", "b.ts", "c.ts"]) fs.writeFileSync(path.join(repo, name), "x\n"); + Bun.spawnSync(["git", "-C", repo, "add", "-A"]); + }); + afterEach(() => { + fs.rmSync(home, { recursive: true, force: true }); + fs.rmSync(repo, { recursive: true, force: true }); + }); + + test("offers exactly once: large repo with no prior decision", () => { + const s = shouldOfferIndexing(repo, { env, threshold: 3 }); + expect(s).toEqual({ offer: true, reason: "large-repo", fileCount: 3, threshold: 3 }); + }); + + test("small repo → no offer", () => { + expect(shouldOfferIndexing(repo, { env, threshold: 4 }).reason).toBe("small-repo"); + }); + + test("not a git repo → no offer", () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ci-plain-")); + try { + expect(shouldOfferIndexing(dir, { env, threshold: 0 }).reason).toBe("not-a-repo"); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } + }); + + test("provider already selected → no offer", () => { + setProvider("graphify", env); + expect(shouldOfferIndexing(repo, { env, threshold: 3 }).reason).toBe("provider-selected"); + }); + + test("explicit decline → never asked again", () => { + setProvider(null, env); + expect(shouldOfferIndexing(repo, { env, threshold: 3 }).reason).toBe("declined"); + }); + + test("trackedFileCount counts git-tracked files only", () => { + fs.writeFileSync(path.join(repo, "untracked.ts"), "x\n"); + expect(trackedFileCount(repo)).toBe(3); + }); }); describe("egress consent gate", () => { From 578af24832f966d9fe1d46a33f9adc18f07f3384 Mon Sep 17 00:00:00 2001 From: Sinabina Date: Thu, 23 Jul 2026 11:34:13 -0700 Subject: [PATCH 2/4] feat: ship gstack-code-intelligence in the managed runtime helper surface Adds the launcher to DEFAULT_RUNTIME_HELPERS and lib/code-intelligence to the helper dependency closure, so standard installs can run the session-start indexing offer from $GSTACK_HOME/bin. Co-Authored-By: Claude Fable 5 --- runtime/install.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/install.js b/runtime/install.js index 925dd1e399..a59e02eaa9 100644 --- a/runtime/install.js +++ b/runtime/install.js @@ -98,6 +98,7 @@ export const DEFAULT_RUNTIME_HELPERS = Object.freeze({ "gstack-brain-cache": helper("bin/gstack-brain-cache"), "gstack-brain-sync": helper("bin/gstack-brain-sync"), "gstack-builder-profile": helper("bin/gstack-builder-profile"), + "gstack-code-intelligence": helper("bin/gstack-code-intelligence"), "gstack-codex-probe": helper("bin/gstack-codex-probe"), "gstack-config": helper("bin/gstack-config"), "gstack-decision-log": helper("bin/gstack-decision-log"), @@ -156,6 +157,7 @@ const RUNTIME_HELPER_DEPENDENCIES = Object.freeze([ "VERSION", "package.json", "lib/bin-context.ts", + "lib/code-intelligence", "lib/conductor-env-shim.ts", "lib/gbrain-exec.ts", "lib/gbrain-guards.ts", From 4f646a5cc366eba724b163e0b0554e9006dd8c8b Mon Sep 17 00:00:00 2001 From: Sinabina Date: Thu, 23 Jul 2026 11:34:13 -0700 Subject: [PATCH 3/4] feat: dispatchers offer optional code-intelligence indexing for large repos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every dispatcher now reads the generated references/CODE-INTELLIGENCE.md once per repository invocation: run `gstack-code-intelligence suggest` (silent skip when unavailable), and only when it reports a large repo with no prior decision, ask the user whether to index — GBrain (semantic, consent-gated), Sourcebot (self-hosted search), Graphify (local graph, never auto-installed), or No indexing (persisted, never re-asked). Parity pins the silent-degrade, decline, and no-auto-install behavior per tree (5027 -> 5045 checks); tree regenerated via gen:gstack2. Co-Authored-By: Claude Fable 5 --- docs/gstack-2/JUDGMENT-PARITY.md | 2 +- evals/parity/transcripts/policy-units.json | 18 +++++++-------- scripts/gstack2/generate-skill-tree.ts | 23 ++++++++++++++++++- scripts/gstack2/run-parity.ts | 14 ++++++++++- skills/debug/SKILL.md | 2 +- skills/debug/references/CODE-INTELLIGENCE.md | 15 ++++++++++++ skills/design/SKILL.md | 2 +- skills/design/references/CODE-INTELLIGENCE.md | 15 ++++++++++++ skills/plan/SKILL.md | 2 +- skills/plan/references/CODE-INTELLIGENCE.md | 15 ++++++++++++ skills/qa/SKILL.md | 2 +- skills/qa/references/CODE-INTELLIGENCE.md | 15 ++++++++++++ skills/review/SKILL.md | 2 +- skills/review/references/CODE-INTELLIGENCE.md | 15 ++++++++++++ skills/ship/SKILL.md | 2 +- skills/ship/references/CODE-INTELLIGENCE.md | 15 ++++++++++++ 16 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 skills/debug/references/CODE-INTELLIGENCE.md create mode 100644 skills/design/references/CODE-INTELLIGENCE.md create mode 100644 skills/plan/references/CODE-INTELLIGENCE.md create mode 100644 skills/qa/references/CODE-INTELLIGENCE.md create mode 100644 skills/review/references/CODE-INTELLIGENCE.md create mode 100644 skills/ship/references/CODE-INTELLIGENCE.md diff --git a/docs/gstack-2/JUDGMENT-PARITY.md b/docs/gstack-2/JUDGMENT-PARITY.md index 1bb2770297..614b718477 100644 --- a/docs/gstack-2/JUDGMENT-PARITY.md +++ b/docs/gstack-2/JUDGMENT-PARITY.md @@ -2,7 +2,7 @@ Parity is executable, not a prose claim. Run `bun run scripts/gstack2/run-parity.ts` or the dedicated Bun tests. -The pinned release inventory passes **5,027 checks** across 55 specialist sources, 16 carved sections, 25 routing scenarios, 28 regression ports, and **78 assets**. +The pinned release inventory passes **5,045 checks** across 55 specialist sources, 16 carved sections, 25 routing scenarios, 28 regression ports, and **78 assets**. The suite verifies: diff --git a/evals/parity/transcripts/policy-units.json b/evals/parity/transcripts/policy-units.json index b94d7a1daf..8f3bb03fe6 100644 --- a/evals/parity/transcripts/policy-units.json +++ b/evals/parity/transcripts/policy-units.json @@ -43,7 +43,7 @@ "prompt_sha256": "a0fcff9cad68f9305da861fa5a58990e1ef51d9d84298fe2df7ba8a2f56b1dba", "semantic_attempt_sha256": "7724c3d954f421753c597364c383bd76bc01ba9803f99fb14488287bb925aeb6" }, - "policy_sha256": "c7df25a16073d69da15243f258a2ef72a69c03ee3114eac2c19cf1c7e126532b", + "policy_sha256": "995b434e47a5355b2256544da09ccb796e299ad94dfa59ec33644e3cb76fb319", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -88,7 +88,7 @@ "prompt_sha256": "04d82a21358f188cb823dcceeecaebea0b4ed8b9c1f8d00220ef3b499c48b1c8", "semantic_attempt_sha256": "9639406995955284517acb30f56b37dedc42a6c08142163dfa8fe0295105cbbf" }, - "policy_sha256": "8dd78f6f8e01eb9cf1fe0f3f43d7fcd072a4f3f2f0dc14d9f1b5d3ff1250b972", + "policy_sha256": "c10eecd9af5dbb8e9fee6b6c03e7919ec990de8b5c73d71a80d79f076dd0702c", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -138,7 +138,7 @@ "prompt_sha256": "8ad639f708a2ccd5c7c438b1dedf6afacdfa4eac3883a7a046ea23f29314e1c4", "semantic_attempt_sha256": "4c450039e4c622fbeaa34b7f7dfc810d3b7369aaf7e5f4d240cd6cc18a31331a" }, - "policy_sha256": "7c7ccb7ff64ea6c73b668848ae5a663606798abc345d7e5c6bb0880732bb29c3", + "policy_sha256": "1d02974d45509033fcbaaab721afb9588f48efc6cc4e1ffcb3bc9c0d7d0440ba", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -188,7 +188,7 @@ "prompt_sha256": "d2aa9aee06a116bf04cb62772e8abdf8dbd606811b6d38565389c88e86c79ede", "semantic_attempt_sha256": "64885a66bdc6688b880cbb9a59babf314834c068eb040657501bf287bfcb0d2b" }, - "policy_sha256": "c7df25a16073d69da15243f258a2ef72a69c03ee3114eac2c19cf1c7e126532b", + "policy_sha256": "995b434e47a5355b2256544da09ccb796e299ad94dfa59ec33644e3cb76fb319", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -232,7 +232,7 @@ "prompt_sha256": "377e3a2dfc7b04272f857d27e77c9aa3c9f36c3feb63c03e5aee3ecd3dea8e2a", "semantic_attempt_sha256": "a49b1528091886749278dc22e7da4556c090800989b2bca9c0e1c09dd880fed7" }, - "policy_sha256": "7969ac784f398b09cec2ad44f623de95f1e326721043272b12aaec1c622e840c", + "policy_sha256": "da07b4bb14cb2ea3f3d2e9570a6dd7f268a549680a44926ad9dd069121d74d86", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -279,7 +279,7 @@ "prompt_sha256": "a01bb977de84e53d8ce3dfa427bcc93d73c6e449cd4e9c1ff63b436fd41fb0d1", "semantic_attempt_sha256": "ce5c64c62c3ff9b60949f34717dffbc908f62ce30f8a4a48ec182eba4363a206" }, - "policy_sha256": "4134088a9b22fd7d3d2d6492c812ecbc55650df25ab1101189dd24721fe1763d", + "policy_sha256": "50c01aa40fae8aed2182fc77ac94f2834c45e9fba63e81f765f66fa7bf1343cb", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -330,7 +330,7 @@ "prompt_sha256": "95e97e26268ad7e509527e0f54c943ed6c4105d919f250648a2ad59ce77cbdb9", "semantic_attempt_sha256": "dacd11a78e32aeb6c0065496bedd4a9770f7bbac1036e003d3768fac41eb84f0" }, - "policy_sha256": "c7df25a16073d69da15243f258a2ef72a69c03ee3114eac2c19cf1c7e126532b", + "policy_sha256": "995b434e47a5355b2256544da09ccb796e299ad94dfa59ec33644e3cb76fb319", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -381,7 +381,7 @@ "prompt_sha256": "bdd7e8adfa7c15cf8531f84c3adaaacc725075f1a78f7487225300750547b82d", "semantic_attempt_sha256": "32c11b63412c5d873ff29dcc87c45bef1b50daa218a5c6c1075864aa24d7c3b6" }, - "policy_sha256": "c7df25a16073d69da15243f258a2ef72a69c03ee3114eac2c19cf1c7e126532b", + "policy_sha256": "995b434e47a5355b2256544da09ccb796e299ad94dfa59ec33644e3cb76fb319", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" @@ -426,7 +426,7 @@ "prompt_sha256": "51b7d53bc342e8632e34ae31a167cbde568ab5ee2a6dd2ccc980583a30604164", "semantic_attempt_sha256": "06f77b27c9bd360562655b23ca00a0dd021bdb14ebaaf3d836845e4e0cb43d68" }, - "policy_sha256": "7436f2bd70592738eda54ae9666d52ae909a4d44c06297e6486afda124cdbf41", + "policy_sha256": "7d13f1fab5ab6efd1079784a904686799759de10610ee283a85dc0228e854fb6", "policy_present": true, "prompt_is_not_authority_input": true, "verdict": "PASS" diff --git a/scripts/gstack2/generate-skill-tree.ts b/scripts/gstack2/generate-skill-tree.ts index 95120458e7..f2a3f5582a 100644 --- a/scripts/gstack2/generate-skill-tree.ts +++ b/scripts/gstack2/generate-skill-tree.ts @@ -250,7 +250,7 @@ Web context: 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. -4. Read \`references/EXECUTION-PROFILES.md\`, \`references/SHARED-JUDGMENT.md\`, and \`references/AUTHORITY-POLICY.md\` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read \`references/RUNTIME.md\` before capability-dependent work and \`references/WEB-CONTEXT.md\` before public-web work. +4. Read \`references/EXECUTION-PROFILES.md\`, \`references/SHARED-JUDGMENT.md\`, and \`references/AUTHORITY-POLICY.md\` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read \`references/RUNTIME.md\` before capability-dependent work and \`references/WEB-CONTEXT.md\` before public-web work. When the target is a repository, read \`references/CODE-INTELLIGENCE.md\` once before substantive specialist work and follow its one-time indexing offer. 5. If an old asset path is unavailable, use \`references/ASSETS.md\`. If legacy prose invokes another retired skill, resolve it through \`references/COMPATIBILITY.md\` and stay inside these six dispatchers. 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. @@ -506,6 +506,26 @@ function webContextContract(): string { ].join('\n'); } +function codeIntelligenceContract(): string { + return [GENERATED, + '# Optional code-intelligence indexing', + '', + 'gstack works fully without an index: grep and the file-only decision store are the default and never depend on a provider. Indexing is an optional enhancement that pays off in large repositories.', + '', + 'Once per invocation, before substantive specialist work inside a repository, run `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence suggest --json 2>/dev/null || true`. If the helper is unavailable or the result says `offer: false`, continue silently; pure judgment never requires it and the user is never nagged. The helper offers only for a large repository (tracked-file count above its threshold) with no prior decision, and an explicit decline is persisted so the question is never repeated.', + '', + 'When the result says `offer: true`, pause and ask via AskUserQuestion whether to index the repository, presenting exactly these options with these reasons and each option\'s availability from the suggest output:', + '', + '- **GBrain** (recommended): semantic search over code plus federated memory across your repos; answers "where is X handled?" questions grep cannot. It sends repository content to your GBrain database, so it requires explicit per-repo consent before indexing.', + '- **Sourcebot**: self-hosted whole-repo regex and code search, fast on very large repos; local when the server runs on localhost, in which case nothing leaves the machine.', + '- **Graphify**: local tree-sitter code graph (definitions, references, structure); nothing ever leaves the machine and no consent is needed, but you install it yourself — it is never auto-installed.', + '- **No indexing**: gstack continues with grep and file-only state, fully supported. This choice is remembered and the question is not asked again.', + '', + 'Persist only the explicit choice: `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence select `. For a non-local provider, run `consent` for this repository only after the user explicitly approves sending its content off-machine, then `index`. Never infer a choice, never auto-install a provider, never treat an unavailable provider as forbidden (the user may set it up later), and never block or delay specialist work on indexing: if the user declines or the index is still building, proceed with grep.', + '', + ].join('\n'); +} + function runtimeContract(): string { return `${GENERATED} # Optional runtime capabilities @@ -593,6 +613,7 @@ function writeSharedContracts(): void { write(path.join(ROOT, 'skills', tree, 'references', 'SHARED-JUDGMENT.md'), sharedJudgmentContract()); write(path.join(ROOT, 'skills', tree, 'references', 'AUTHORITY-POLICY.md'), authorityPolicyContract()); write(path.join(ROOT, 'skills', tree, 'references', 'WEB-CONTEXT.md'), webContextContract()); + write(path.join(ROOT, 'skills', tree, 'references', 'CODE-INTELLIGENCE.md'), codeIntelligenceContract()); write(path.join(ROOT, 'skills', tree, 'references', 'RUNTIME.md'), runtimeContract()); write(path.join(ROOT, 'skills', tree, 'references', 'BROWSER-PROVIDERS.md'), `${GENERATED}\n${renderBrowserProviderContract()}`); write(path.join(ROOT, 'skills', tree, 'references', 'support', 'runtime-bootstrap.mjs'), bootstrap); diff --git a/scripts/gstack2/run-parity.ts b/scripts/gstack2/run-parity.ts index fe289dcfcf..51769efc2c 100644 --- a/scripts/gstack2/run-parity.ts +++ b/scripts/gstack2/run-parity.ts @@ -25,7 +25,7 @@ const ALLOWED_DISPOSITIONS = new Set(['VERBATIM_PORT', 'MECHANICAL_PORT', 'JUDGM // (27 -> 28, office-hours only) added 5 more. The self-contained-questions // overlay for issue #879 (28 -> 29, targets '*', all 55 modules) added 113 // more (2 per module + 3 regression checks). -export const EXPECTED_PARITY_CHECKS = 5027; +export const EXPECTED_PARITY_CHECKS = 5045; function sha256(value: string | Uint8Array): string { return createHash('sha256').update(value).digest('hex'); @@ -168,6 +168,18 @@ export function runParity(): ParityResult { const authority = path.join(ROOT, 'skills', tree, 'references', 'AUTHORITY-POLICY.md'); check(fs.existsSync(authority), `${tree} lacks the executable authority/evidence policy`); check(dispatcher.includes('references/AUTHORITY-POLICY.md'), `${tree} dispatcher does not load the authority/evidence policy`); + const codeIntel = path.join(ROOT, 'skills', tree, 'references', 'CODE-INTELLIGENCE.md'); + check(fs.existsSync(codeIntel), `${tree} lacks the optional code-intelligence offer contract`); + check(dispatcher.includes('references/CODE-INTELLIGENCE.md'), `${tree} dispatcher does not load the code-intelligence offer`); + if (fs.existsSync(codeIntel)) { + const offer = fs.readFileSync(codeIntel, 'utf8'); + check( + offer.includes('offer: false`, continue silently') + && offer.includes('No indexing') + && offer.includes('never auto-install a provider'), + `${tree} code-intelligence offer lost its silent-degrade, decline, or no-auto-install behavior`, + ); + } } const effectsPath = path.join(ROOT, 'skills', 'ship', 'references', 'EXTERNAL-EFFECTS.md'); check(fs.existsSync(effectsPath), 'Ship lacks the durable external-effect protocol'); diff --git a/skills/debug/SKILL.md b/skills/debug/SKILL.md index 7c8cf14db6..b23fb6baae 100644 --- a/skills/debug/SKILL.md +++ b/skills/debug/SKILL.md @@ -27,7 +27,7 @@ Web context: 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. -4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. +4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. When the target is a repository, read `references/CODE-INTELLIGENCE.md` once before substantive specialist work and follow its one-time indexing offer. 5. If an old asset path is unavailable, use `references/ASSETS.md`. If legacy prose invokes another retired skill, resolve it through `references/COMPATIBILITY.md` and stay inside these six dispatchers. 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. diff --git a/skills/debug/references/CODE-INTELLIGENCE.md b/skills/debug/references/CODE-INTELLIGENCE.md new file mode 100644 index 0000000000..0ab8b901f1 --- /dev/null +++ b/skills/debug/references/CODE-INTELLIGENCE.md @@ -0,0 +1,15 @@ + +# Optional code-intelligence indexing + +gstack works fully without an index: grep and the file-only decision store are the default and never depend on a provider. Indexing is an optional enhancement that pays off in large repositories. + +Once per invocation, before substantive specialist work inside a repository, run `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence suggest --json 2>/dev/null || true`. If the helper is unavailable or the result says `offer: false`, continue silently; pure judgment never requires it and the user is never nagged. The helper offers only for a large repository (tracked-file count above its threshold) with no prior decision, and an explicit decline is persisted so the question is never repeated. + +When the result says `offer: true`, pause and ask via AskUserQuestion whether to index the repository, presenting exactly these options with these reasons and each option's availability from the suggest output: + +- **GBrain** (recommended): semantic search over code plus federated memory across your repos; answers "where is X handled?" questions grep cannot. It sends repository content to your GBrain database, so it requires explicit per-repo consent before indexing. +- **Sourcebot**: self-hosted whole-repo regex and code search, fast on very large repos; local when the server runs on localhost, in which case nothing leaves the machine. +- **Graphify**: local tree-sitter code graph (definitions, references, structure); nothing ever leaves the machine and no consent is needed, but you install it yourself — it is never auto-installed. +- **No indexing**: gstack continues with grep and file-only state, fully supported. This choice is remembered and the question is not asked again. + +Persist only the explicit choice: `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence select `. For a non-local provider, run `consent` for this repository only after the user explicitly approves sending its content off-machine, then `index`. Never infer a choice, never auto-install a provider, never treat an unavailable provider as forbidden (the user may set it up later), and never block or delay specialist work on indexing: if the user declines or the index is still building, proceed with grep. diff --git a/skills/design/SKILL.md b/skills/design/SKILL.md index c1c8f83a13..94a4a53a72 100644 --- a/skills/design/SKILL.md +++ b/skills/design/SKILL.md @@ -27,7 +27,7 @@ Web context: 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. -4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. +4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. When the target is a repository, read `references/CODE-INTELLIGENCE.md` once before substantive specialist work and follow its one-time indexing offer. 5. If an old asset path is unavailable, use `references/ASSETS.md`. If legacy prose invokes another retired skill, resolve it through `references/COMPATIBILITY.md` and stay inside these six dispatchers. 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. diff --git a/skills/design/references/CODE-INTELLIGENCE.md b/skills/design/references/CODE-INTELLIGENCE.md new file mode 100644 index 0000000000..0ab8b901f1 --- /dev/null +++ b/skills/design/references/CODE-INTELLIGENCE.md @@ -0,0 +1,15 @@ + +# Optional code-intelligence indexing + +gstack works fully without an index: grep and the file-only decision store are the default and never depend on a provider. Indexing is an optional enhancement that pays off in large repositories. + +Once per invocation, before substantive specialist work inside a repository, run `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence suggest --json 2>/dev/null || true`. If the helper is unavailable or the result says `offer: false`, continue silently; pure judgment never requires it and the user is never nagged. The helper offers only for a large repository (tracked-file count above its threshold) with no prior decision, and an explicit decline is persisted so the question is never repeated. + +When the result says `offer: true`, pause and ask via AskUserQuestion whether to index the repository, presenting exactly these options with these reasons and each option's availability from the suggest output: + +- **GBrain** (recommended): semantic search over code plus federated memory across your repos; answers "where is X handled?" questions grep cannot. It sends repository content to your GBrain database, so it requires explicit per-repo consent before indexing. +- **Sourcebot**: self-hosted whole-repo regex and code search, fast on very large repos; local when the server runs on localhost, in which case nothing leaves the machine. +- **Graphify**: local tree-sitter code graph (definitions, references, structure); nothing ever leaves the machine and no consent is needed, but you install it yourself — it is never auto-installed. +- **No indexing**: gstack continues with grep and file-only state, fully supported. This choice is remembered and the question is not asked again. + +Persist only the explicit choice: `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence select `. For a non-local provider, run `consent` for this repository only after the user explicitly approves sending its content off-machine, then `index`. Never infer a choice, never auto-install a provider, never treat an unavailable provider as forbidden (the user may set it up later), and never block or delay specialist work on indexing: if the user declines or the index is still building, proceed with grep. diff --git a/skills/plan/SKILL.md b/skills/plan/SKILL.md index 36452e7f72..1ae3e8706a 100644 --- a/skills/plan/SKILL.md +++ b/skills/plan/SKILL.md @@ -28,7 +28,7 @@ Web context: 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. -4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. +4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. When the target is a repository, read `references/CODE-INTELLIGENCE.md` once before substantive specialist work and follow its one-time indexing offer. 5. If an old asset path is unavailable, use `references/ASSETS.md`. If legacy prose invokes another retired skill, resolve it through `references/COMPATIBILITY.md` and stay inside these six dispatchers. 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. diff --git a/skills/plan/references/CODE-INTELLIGENCE.md b/skills/plan/references/CODE-INTELLIGENCE.md new file mode 100644 index 0000000000..0ab8b901f1 --- /dev/null +++ b/skills/plan/references/CODE-INTELLIGENCE.md @@ -0,0 +1,15 @@ + +# Optional code-intelligence indexing + +gstack works fully without an index: grep and the file-only decision store are the default and never depend on a provider. Indexing is an optional enhancement that pays off in large repositories. + +Once per invocation, before substantive specialist work inside a repository, run `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence suggest --json 2>/dev/null || true`. If the helper is unavailable or the result says `offer: false`, continue silently; pure judgment never requires it and the user is never nagged. The helper offers only for a large repository (tracked-file count above its threshold) with no prior decision, and an explicit decline is persisted so the question is never repeated. + +When the result says `offer: true`, pause and ask via AskUserQuestion whether to index the repository, presenting exactly these options with these reasons and each option's availability from the suggest output: + +- **GBrain** (recommended): semantic search over code plus federated memory across your repos; answers "where is X handled?" questions grep cannot. It sends repository content to your GBrain database, so it requires explicit per-repo consent before indexing. +- **Sourcebot**: self-hosted whole-repo regex and code search, fast on very large repos; local when the server runs on localhost, in which case nothing leaves the machine. +- **Graphify**: local tree-sitter code graph (definitions, references, structure); nothing ever leaves the machine and no consent is needed, but you install it yourself — it is never auto-installed. +- **No indexing**: gstack continues with grep and file-only state, fully supported. This choice is remembered and the question is not asked again. + +Persist only the explicit choice: `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence select `. For a non-local provider, run `consent` for this repository only after the user explicitly approves sending its content off-machine, then `index`. Never infer a choice, never auto-install a provider, never treat an unavailable provider as forbidden (the user may set it up later), and never block or delay specialist work on indexing: if the user declines or the index is still building, proceed with grep. diff --git a/skills/qa/SKILL.md b/skills/qa/SKILL.md index a51f977467..eb823eebe7 100644 --- a/skills/qa/SKILL.md +++ b/skills/qa/SKILL.md @@ -27,7 +27,7 @@ Web context: 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. -4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. +4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. When the target is a repository, read `references/CODE-INTELLIGENCE.md` once before substantive specialist work and follow its one-time indexing offer. 5. If an old asset path is unavailable, use `references/ASSETS.md`. If legacy prose invokes another retired skill, resolve it through `references/COMPATIBILITY.md` and stay inside these six dispatchers. 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. diff --git a/skills/qa/references/CODE-INTELLIGENCE.md b/skills/qa/references/CODE-INTELLIGENCE.md new file mode 100644 index 0000000000..0ab8b901f1 --- /dev/null +++ b/skills/qa/references/CODE-INTELLIGENCE.md @@ -0,0 +1,15 @@ + +# Optional code-intelligence indexing + +gstack works fully without an index: grep and the file-only decision store are the default and never depend on a provider. Indexing is an optional enhancement that pays off in large repositories. + +Once per invocation, before substantive specialist work inside a repository, run `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence suggest --json 2>/dev/null || true`. If the helper is unavailable or the result says `offer: false`, continue silently; pure judgment never requires it and the user is never nagged. The helper offers only for a large repository (tracked-file count above its threshold) with no prior decision, and an explicit decline is persisted so the question is never repeated. + +When the result says `offer: true`, pause and ask via AskUserQuestion whether to index the repository, presenting exactly these options with these reasons and each option's availability from the suggest output: + +- **GBrain** (recommended): semantic search over code plus federated memory across your repos; answers "where is X handled?" questions grep cannot. It sends repository content to your GBrain database, so it requires explicit per-repo consent before indexing. +- **Sourcebot**: self-hosted whole-repo regex and code search, fast on very large repos; local when the server runs on localhost, in which case nothing leaves the machine. +- **Graphify**: local tree-sitter code graph (definitions, references, structure); nothing ever leaves the machine and no consent is needed, but you install it yourself — it is never auto-installed. +- **No indexing**: gstack continues with grep and file-only state, fully supported. This choice is remembered and the question is not asked again. + +Persist only the explicit choice: `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence select `. For a non-local provider, run `consent` for this repository only after the user explicitly approves sending its content off-machine, then `index`. Never infer a choice, never auto-install a provider, never treat an unavailable provider as forbidden (the user may set it up later), and never block or delay specialist work on indexing: if the user declines or the index is still building, proceed with grep. diff --git a/skills/review/SKILL.md b/skills/review/SKILL.md index 1f511d469b..7fde491c35 100644 --- a/skills/review/SKILL.md +++ b/skills/review/SKILL.md @@ -27,7 +27,7 @@ Web context: 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. -4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. +4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. When the target is a repository, read `references/CODE-INTELLIGENCE.md` once before substantive specialist work and follow its one-time indexing offer. 5. If an old asset path is unavailable, use `references/ASSETS.md`. If legacy prose invokes another retired skill, resolve it through `references/COMPATIBILITY.md` and stay inside these six dispatchers. 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. diff --git a/skills/review/references/CODE-INTELLIGENCE.md b/skills/review/references/CODE-INTELLIGENCE.md new file mode 100644 index 0000000000..0ab8b901f1 --- /dev/null +++ b/skills/review/references/CODE-INTELLIGENCE.md @@ -0,0 +1,15 @@ + +# Optional code-intelligence indexing + +gstack works fully without an index: grep and the file-only decision store are the default and never depend on a provider. Indexing is an optional enhancement that pays off in large repositories. + +Once per invocation, before substantive specialist work inside a repository, run `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence suggest --json 2>/dev/null || true`. If the helper is unavailable or the result says `offer: false`, continue silently; pure judgment never requires it and the user is never nagged. The helper offers only for a large repository (tracked-file count above its threshold) with no prior decision, and an explicit decline is persisted so the question is never repeated. + +When the result says `offer: true`, pause and ask via AskUserQuestion whether to index the repository, presenting exactly these options with these reasons and each option's availability from the suggest output: + +- **GBrain** (recommended): semantic search over code plus federated memory across your repos; answers "where is X handled?" questions grep cannot. It sends repository content to your GBrain database, so it requires explicit per-repo consent before indexing. +- **Sourcebot**: self-hosted whole-repo regex and code search, fast on very large repos; local when the server runs on localhost, in which case nothing leaves the machine. +- **Graphify**: local tree-sitter code graph (definitions, references, structure); nothing ever leaves the machine and no consent is needed, but you install it yourself — it is never auto-installed. +- **No indexing**: gstack continues with grep and file-only state, fully supported. This choice is remembered and the question is not asked again. + +Persist only the explicit choice: `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence select `. For a non-local provider, run `consent` for this repository only after the user explicitly approves sending its content off-machine, then `index`. Never infer a choice, never auto-install a provider, never treat an unavailable provider as forbidden (the user may set it up later), and never block or delay specialist work on indexing: if the user declines or the index is still building, proceed with grep. diff --git a/skills/ship/SKILL.md b/skills/ship/SKILL.md index 599c120f0d..c7a6b2fe09 100644 --- a/skills/ship/SKILL.md +++ b/skills/ship/SKILL.md @@ -27,7 +27,7 @@ Web context: 1. Infer the mode from product stage, surface, requested artifact, mutation authorization, evidence needs, and deployment state. Do not route by keyword alone. 2. Refine the public mode to the smallest applicable internal specialist set, then print the required execution header before any substantive output. 3. Read each active module in full from the path shown in the mode/alias tables. Its specialist body, behavioral contract, STOP gates, and appended upstream judgment ports are binding. Read a lazy specialist phase in full only when the workflow reaches its package-local reference. -4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. +4. Read `references/EXECUTION-PROFILES.md`, `references/SHARED-JUDGMENT.md`, and `references/AUTHORITY-POLICY.md` for every invocation. Infer Depth from structured operating conditions, then obey its mandatory modules, legal skips, artifacts, and claim limits. Read `references/RUNTIME.md` before capability-dependent work and `references/WEB-CONTEXT.md` before public-web work. When the target is a repository, read `references/CODE-INTELLIGENCE.md` once before substantive specialist work and follow its one-time indexing offer. 5. If an old asset path is unavailable, use `references/ASSETS.md`. If legacy prose invokes another retired skill, resolve it through `references/COMPATIBILITY.md` and stay inside these six dispatchers. 6. Preserve report-only versus mutation boundaries. Missing mutation authorization fails closed: do not edit merely because a specialist can fix. Commits, pushes, PRs, merges, deploys, messages, and other external mutations still require affirmative authority from the user. 7. Match the user's language. Keep code identifiers, commands, and source quotations original when translation would reduce accuracy. diff --git a/skills/ship/references/CODE-INTELLIGENCE.md b/skills/ship/references/CODE-INTELLIGENCE.md new file mode 100644 index 0000000000..0ab8b901f1 --- /dev/null +++ b/skills/ship/references/CODE-INTELLIGENCE.md @@ -0,0 +1,15 @@ + +# Optional code-intelligence indexing + +gstack works fully without an index: grep and the file-only decision store are the default and never depend on a provider. Indexing is an optional enhancement that pays off in large repositories. + +Once per invocation, before substantive specialist work inside a repository, run `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence suggest --json 2>/dev/null || true`. If the helper is unavailable or the result says `offer: false`, continue silently; pure judgment never requires it and the user is never nagged. The helper offers only for a large repository (tracked-file count above its threshold) with no prior decision, and an explicit decline is persisted so the question is never repeated. + +When the result says `offer: true`, pause and ask via AskUserQuestion whether to index the repository, presenting exactly these options with these reasons and each option's availability from the suggest output: + +- **GBrain** (recommended): semantic search over code plus federated memory across your repos; answers "where is X handled?" questions grep cannot. It sends repository content to your GBrain database, so it requires explicit per-repo consent before indexing. +- **Sourcebot**: self-hosted whole-repo regex and code search, fast on very large repos; local when the server runs on localhost, in which case nothing leaves the machine. +- **Graphify**: local tree-sitter code graph (definitions, references, structure); nothing ever leaves the machine and no consent is needed, but you install it yourself — it is never auto-installed. +- **No indexing**: gstack continues with grep and file-only state, fully supported. This choice is remembered and the question is not asked again. + +Persist only the explicit choice: `"${GSTACK_HOME:-$HOME/.gstack}"/bin/gstack-code-intelligence select `. For a non-local provider, run `consent` for this repository only after the user explicitly approves sending its content off-machine, then `index`. Never infer a choice, never auto-install a provider, never treat an unavailable provider as forbidden (the user may set it up later), and never block or delay specialist work on indexing: if the user declines or the index is still building, proceed with grep. From 4c2bfdde80bb0a4f8742c4775104e0e35387cfc7 Mon Sep 17 00:00:00 2001 From: Sinabina Date: Thu, 23 Jul 2026 11:40:53 -0700 Subject: [PATCH 4/4] chore: bump to v1.62.0.0 with release notes Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 37 +++++++++++++++++++++++++++++++++++++ VERSION | 2 +- package.json | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 023e7b7068..a7ec84387c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,43 @@ > completion state and remaining P0 gates. No version bump or release claim is > made here while that status holds. +## [1.62.0.0] - 2026-07-23 + +## **Open a large repo and gstack offers to index it.** +## **Once, with real choices, then never again.** + +Every gstack skill now checks the size of the repository it lands in before starting real work. Small repo, nothing happens, grep is already fast. Large repo (1,000+ tracked files) and you have never answered the question, the skill pauses once and asks whether you want code-intelligence indexing, with the actual trade-offs spelled out: GBrain gives semantic "where is X handled?" search but sends repo content to your GBrain database and asks consent per repo. Sourcebot gives fast whole-repo search, self-hosted, local when it runs on localhost. Graphify builds a local tree-sitter code graph and nothing ever leaves your machine, but you install it yourself. Or say no indexing, and gstack remembers that too. Decline once and no skill asks again, on any repo, until you change your mind with `gstack-code-intelligence select`. + +### The numbers that matter + +Source: `bun run scripts/gstack2/run-parity.ts` and `bun test test/code-intelligence.test.ts` on this release. + +| Metric | Before | After | +|---|---|---| +| Skills that surface the indexing option | 0 | all 6 dispatchers | +| Times the question is asked per machine | n/a | at most 1 | +| Large-repo threshold | n/a | 1,000 tracked files | +| Parity checks pinning the behavior | 5,027 | 5,045 | +| code-intelligence tests | 25 | 31 | + +The "at most 1" row is the one that matters. The offer gate (`gstack-code-intelligence suggest`) refuses to fire when a provider is already selected, when you declined before, when the repo is small, or when the directory is not a git repo. A missing helper is a silent skip, not an error. + +### What this means for builders + +On a 10-file toy, nothing changes. On your 5,000-file production monolith, the first `/plan` or `/review` run offers you semantic search over the whole codebase, you pick a provider (or none) in one question, and every later session benefits without ever being asked again. Grep and the file-only decision store remain the always-working default; indexing is an upgrade, never a dependency. + +### Itemized changes + +#### Added +- Session-start indexing offer: every dispatcher reads the new generated `references/CODE-INTELLIGENCE.md` once per repository invocation and runs `gstack-code-intelligence suggest` to decide whether to ask. The question presents GBrain (recommended, consent-gated), Sourcebot, Graphify (local, never auto-installed), and No indexing, each with its reason and live availability. +- `gstack-code-intelligence suggest [path] [--json]`: the offer gate as a command. Emits offer/no-offer with the reason (`provider-selected`, `declined`, `not-a-repo`, `small-repo`, `large-repo`) and, when offering, the provider options. +- `gstack-code-intelligence select none` now persists the decline so the question is never repeated. +- The `gstack-code-intelligence` helper ships in the managed runtime, so standard installs can run the offer from `$GSTACK_HOME/bin`. + +#### For contributors +- New `lib/code-intelligence/suggest.ts` (`shouldOfferIndexing`, `trackedFileCount`, threshold injectable for tests) and a `declined` flag in the selection store; 6 new tests in `test/code-intelligence.test.ts`. +- Parity pins the per-tree contract (existence, dispatcher wiring, silent-degrade, decline, no-auto-install): 5,027 to 5,045 checks. Runtime helper surface: `DEFAULT_RUNTIME_HELPERS` + `RUNTIME_HELPER_DEPENDENCIES` in `runtime/install.js`. + ## [1.61.1.0] - 2026-07-22 ## **Design docs now read like decision records.** diff --git a/VERSION b/VERSION index ad37b0f1be..1042f0adfa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.61.1.0 +1.62.0.0 diff --git a/package.json b/package.json index f206cd96e6..fba8165572 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.61.1.0", + "version": "1.62.0.0", "description": "GStack 2 — six portable Agent Skills with an optional host-neutral runtime.", "license": "MIT", "type": "module",