Skip to content

Two zero-config gaps: code-* should signal "graph not built" vs silent empty, and gbrain init should validate the embedding key #1780

Closed

Description

@garrytan-agents

Context

A downstream tool (gstack /sync-gbrain + /setup-gbrain) is building a zero-config
"freshness" contract on top of gbrain: after one setup, every gbrain query
(semantic, symbol, call-graph) should be correct and fresh with no flags,
self-healing across crashes and reboots. Reading gbrain 0.41.38.0 source, two
things already work great and are NOT being asked to change: file-change detection
(SHA-256 content hash, src/core/import-file.ts:405-449) and the cross-platform
auto-restarting daemon (gbrain autopilot --install writing launchd KeepAlive /
systemd Restart / cron, src/commands/autopilot.ts:810-1015). Thank you for both.

Three gaps remain that make a brain silently fail to build its call graph for an
unattended/zero-config consumer. Two are real; the third is optional.

Gap 1 (real): code-* return a silent empty result, indistinguishable from "still indexing"

code-callers / code-callees / code-def / code-refs return count: 0, results: []
in three situations a caller cannot tell apart: (1) symbol graph not built yet for
the source, (2) source never synced, (3) graph complete and the symbol genuinely
has no callers. Evidence: src/commands/code-def.ts:29-84 (empty row set when
content_chunks has no match) and :120-143 (prints "No definitions found" / emits
{count:0,results:[]}, exits 0 regardless); callers/callees/refs share the pattern.

Impact: an agent queries code-callers foo, gets count:0, concludes "no callers"
when the graph is still building or never built. No signal to wait vs trust.

Request: add a typed readiness field, e.g. ready: false (or
status: "indexing"|"not_built"|"ready") when the source has no built symbol graph.
Then count:0 + ready:true means "genuinely none"; ready:false means "ask later."

Gap 2 (real): gbrain init does not validate the embedding key, so a brain can silently yield embedded=0

gbrain init persists --embedding-model to ~/.gbrain/config.json but never checks
the provider key is present/working. Evidence: src/commands/init.ts:181-240
(resolveAIOptions saves the model string; no key check, no test embed). It fails
only at first sync (embedBatch throws EMBEDDING_NO_CREDS, page imports but
embedded=0), and combined with Gap 1 the call graph silently never builds.

Request: validate the embedding provider/key at init (ideally a tiny test-embed so
a missing/invalid key fails fast at setup), or at minimum a loud warning. The
existing --no-embedding escape preserves the deferred-setup path.

Gap 3 (optional, low): cycle-lock takeover is TTL-only; a crashed holder blocks cycles for up to the full TTL

gbrain_cycle_locks is taken over only when ttl_expires_at < NOW() (~30 min).
Evidence: src/core/db-lock.ts:51-95. A crashed holder blocks new cycles for up to
the TTL. gbrain sync --break-lock already does the liveness check
(process.kill(pid,0) + age gate, src/commands/sync.ts:831-867); it just is not
automatic. Request (optional): same-host + provably-dead pid + small grace window
-> automatic takeover; cross-host stays TTL-only.

Why this matters

With Gaps 1 + 2 fixed, a consumer sets up a brain, gets a fast loud failure if the
key is missing, and can distinguish "graph still building" from "no such symbol"
while the (already excellent) daemon keeps everything fresh. That's the whole
zero-config story.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions