Skip to content

gstack-brain-context-load shells out to gbrain list_pages, which is an MCP tool name and not a CLI verb — brain context is always 0 bytes #2883

Closed

Description

@hmalinski

Summary

bin/gstack-brain-context-load.ts builds its argv as ["list_pages", "--limit", ...] and calls spawnSync("gbrain", cliArgs). list_pages is the MCP tool name; the CLI verb is list. Every invocation exits non-zero with Unknown command: list_pages, the dispatch returns { ok: false, bytes: 0 }, and no brain context is ever loaded into any skill.

It fails silently: the caller degrades to Grep with no user-visible error.

Reproduction

$ gbrain list_pages --limit 3
Unknown command: list_pages
Run gbrain --help for available commands.

$ gbrain list --limit 3
<3 rows>

Measured end-to-end with the loader's own --explain:

$ gstack-brain-context-load --skill investigate --repo <slug> --explain
[brain-context-load] mode=manifest queries=3
  SKIP  prior-investigations   kind=list  bytes=0  (gbrain list_pages exited 1)
  SKIP  project-learnings      kind=filesystem  bytes=0  (no matches)
  SKIP  recent-eureka          kind=filesystem  bytes=0  (no matches)
[brain-context-load] total bytes=0

$ gstack-brain-context-load --skill review --repo <slug> --explain
[brain-context-load] mode=default queries=3
  SKIP  recent-transcripts   kind=list  bytes=0  (gbrain list_pages exited 1)
  SKIP  recent-curated       kind=list  bytes=0  (gbrain list_pages exited 1)
  SKIP  skill-name-events    kind=list  bytes=0  (gbrain list_pages exited 1)
[brain-context-load] total bytes=0

Note the second case: a skill with no gbrain: manifest falls back to Layer 1, and that fallback is also all-kind: list, so it fails identically.

Source

bin/gstack-brain-context-load.ts, line 263 on current origin/main:

const cliArgs: string[] = ["list_pages", "--limit", String(limit)];
if (q.sort) cliArgs.push("--sort", q.sort);
if (q.filter) {
  for (const [k, v] of Object.entries(q.filter)) {
    cliArgs.push("--filter", `${k}=${rv}`);
  }
}
const result = spawnSync("gbrain", cliArgs, ...);

Impact

Every brain-backed query in the shipped skills is kind: list -- there are zero kind: vector queries -- and the Layer-1 fallback is all-list too. Net effect is 0 bytes of brain context in every skill, for every user with gbrain installed.

Verified independently on two machines

Machine A Machine B
gbrain 0.42.67.0 0.50.2.0
gstack 1.84.1.0 1.84.x
gbrain list_pages Unknown command Unknown command
loader --explain total bytes=0 total bytes=0

So it is not a gbrain-version artifact. On both machines the local gstack copy was unmodified (git diff origin/main -- bin/gstack-brain-context-load.ts empty) and within a few commits of origin/main.

Likely root cause, and a docs half

gbrain list --help itself says "use list_pages with sort=updated_desc" -- gbrain's CLI help refers to its own MCP tool name. Anyone writing a CLI caller from that help text lands exactly here. Worth fixing on the gbrain side too, or having the CLI accept list_pages as an alias.

Secondary mismatches (CONFIRMED on 0.50.2.0)

Initially filed as unverified leads; both are now confirmed directly:

$ gbrain list --limit 5 --filter type=timeline
gbrain list: unknown flag --filter for 'gbrain list'
Run: gbrain list --help
  • --filter does not exist. The real flags are --type and --tag. The string --filter appears nowhere in gbrain 0.50's src/cli.ts.
  • --sort value is wrong. The loader sends updated_at_desc; the CLI accepts updated_desc, updated_asc, created_desc, slug.

So fixing the verb alone is not sufficient -- the sort value and the filter flags need translating too.

Worth noting for anyone fixing this: on gbrain <=0.42 unknown flags were silently ignored, and 0.50 made them a hard error (a deliberate upstream break, per its release notes). A verb-only fix would therefore surface these two immediately on 0.50+ rather than degrading quietly.

Related but distinct

#1687 covers filter: blocks being dropped by parseSkillManifest, so kind: list queries ran unfiltered (reported fixed in #2264). That bug assumes the query executes. This one is upstream of it: with the wrong verb the command never runs at all, so correct filter parsing still yields 0 bytes.

Activity

  1. hmalinski commented on Sep 16, 2026

    @hmalinski
    Author

    Update: the two "secondary mismatches" were filed as unverified leads; both are now confirmed on gbrain 0.50.2.0 and the body has been updated accordingly.

    $ gbrain list --limit 5 --filter type=timeline
    gbrain list: unknown flag --filter for 'gbrain list'
    Run: gbrain list --help
    

    --filter does not exist (--type / --tag are the real flags) and --sort takes updated_desc, not updated_at_desc — so a verb-only fix is not sufficient.

    Relevant nuance for whoever picks this up: on gbrain <=0.42 unknown flags were silently ignored; 0.50 turned them into a hard error (deliberate upstream break, per its release notes). So a verb-only fix degrades quietly on old gbrain but fails loudly on 0.50+.

  2. capy-ai commented on Oct 2, 2026

    @capy-ai
    Contributor

    Fixed in v1.91.13.0 (#3013, merged as f30b7b7): brain context uses gbrain list with gbrain's real flags and reports failed queries. Run /gstack-upgrade, then start a new Claude Code session. Thanks for the report. Reopen if you still see it after upgrading.

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