Design: a launcher adapter so grandma can drive CLIs other than Claude Code #13
Replies: 2 comments
-
|
Goal: adding the next CLI is a single drop-in file, not an engine change. Scope right now is CLIs only (Gemini, Codex, aider, opencode, alongside the current Claude Code). MCP and the web UIs are deliberately out of scope, see the last section for why. The reframe: grandma does three separable jobsEvery integration is three jobs, and each CLI supports them to a different degree:
Today all three are hardcoded to claude. The design turns them into a contract each target implements as far as it can, and the engine degrades the rest. That degradation is the whole point: it is what lets hookless aider run on the same engine as fully-hooked opencode. One fact that shapes everything: on Claude Code, Gemini, and Codex the pre-compaction hook CANNOT inject context, only fire (and sometimes block). So the portable pattern is the one grandma already uses, and it generalizes cleanly: checkpoint in the pre-compaction hook, re-inject from the session-START hook. The adapter contract (the extensibility answer)A target is one file, Required.
Optional, engine degrades to nothing if absent. Five functions, one optional. A capable target implements all five; aider implements three and declares the rest off; the engine reads the flags and does the right thing. SelectionHighest precedence first: The four CLIs, concretely (verified against current docs)Every CLI has a native context file plus a headless mode. The append-a-system-prompt flag is a Claude Code luxury, and the full-replace knobs (GEMINI_SYSTEM_MD, Codex model_instructions_file) clobber the CLI's own coding brain, so we never touch those. Memory rides the native file.
Per-CLI notes:
Build order: Gemini first. Its two hardest capabilities (headless, context injection) are first-class and stable, and because its pre-compaction hook cannot inject, it forces the real degrade path from day one, the same path Codex and aider need. Prove it once on Gemini and the rest fall out. Then Codex, then opencode (the full-hook showcase), then aider. Clean-room and testsAdapters consume the same Roadmap
Open questions
Out of scope, on purposeMCP (a pull protocol: it cannot deliver always-loaded memory and only re-plumbs what the context-file load already does) and the web UIs (ChatGPT, Claude.ai: unreachable without a public server, and their terms forbid the automated reading of chat history that a distill step needs). grandma is for tools that run in your terminal and keep a transcript you own. This is a design and build thread. Argue the interface if you disagree, then build one adapter against it. |
Beta Was this translation helpful? Give feedback.
-
|
hey @anshulforyou. I would like to contribute to this. I really like your idea as a whole. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Today grandma is wired to one tool. claude shows up in three shapes across the engine, and any multi-CLI story has to account for all three. Launch injects the assembled memory bundle with exec claude --append-system-prompt. Headless runs claude -p over a transcript for distill and watch. Hooks wire rehydrate-after-compaction and session-end distill into .claude/settings.local.json. So this is not swap the binary name. It is an adapter with a small honest interface, where a CLI implements what it supports and grandma drops cleanly what it cannot.
Here is a suggested design, checked against each target's own docs rather than assumed.
What the targets actually support. The one injection channel every CLI has is the initial user prompt text. The ephemeral system-prompt slot is a Claude Code luxury: neither Gemini CLI nor Codex has an append-system-prompt, and their replace-the-system-prompt knobs (GEMINI_SYSTEM_MD, experimental_instructions_file) clobber the CLI's own coding brain, so they are the wrong place for memory. Memory rides in through the native context file (AGENTS.md for Codex and opencode, GEMINI.md for Gemini, a conventions file for aider) or prepended into the first prompt, never the system slot. Headless mode is strong everywhere (codex exec, gemini -p, aider -m, opencode run), all JSON output except claude. Lifecycle hooks are the scarce resource: only opencode has a real event system (session.compacted, session.idle), while Codex, Gemini and aider have none, so rehydrate-after-compaction simply does not fire there and degrades to a manual grandma rehydrate.
The adapter interface. lib/adapters/.sh, each a bash file defining the same function names, sourced by launch, save and watch. The engine never re-assembles memory, it hands the adapter the bundle assemble.sh already built.
Required:
Optional, engine degrades if absent:
Selection, highest precedence first: a GRANDMA_CLI env var, then a per-sweater cli field in the sweater's frontmatter (so you can keep a Claude sweater and a Gemini sweater side by side), then a cli line in the GRANDMA_HOME config, then the built-in default claude. This mirrors how the engine already takes env overrides.
Keeping the clean-room intact. Adapters consume the same assemble.sh bundle, so the isolation invariant and the denylist and core-purity invariants already cover every CLI unchanged, the adapter transports the bundle and never re-selects memory. Add lib/adapters/* to the CORE list in grandma-test.sh so the no-scope-names and no-personal-data checks apply to adapters too. And add one new invariant for the contextfile mode: assert that after a wrapped session the adapter left no memory-bearing file (an AGENTS.md or GEMINI.md carrying bundle content) in the project working tree, tracked or untracked. That bites the leak-via-context-file failure mode that Claude Code's ephemeral flag never had.
Recommended first target: Gemini CLI. Its two hardest capabilities, headless and context injection, are both first-class, documented and stable, and it has the largest user base, so the payoff comes fast. Because it has no lifecycle hooks, it forces the graceful-degradation path to be real from day one, and that degraded path is the honest common case Codex and aider also share, so proving it once on Gemini de-risks all three. opencode is the stretch target that proves the full-hook path, a small JS plugin mapping session.compacted to rehydrate and session.idle to distill. aider's adapter must force --no-auto-commits to keep grandma's no-auto-commit promise.
Open questions:
Each adapter ships its definition of done: a GRANDMA_DRY_RUN smoke that prints a plan and never execs and survives set -u, and the kebab-fixture path test. This is a design and build thread. Argue the interface if you disagree, then build one adapter against it.
Beta Was this translation helpful? Give feedback.
All reactions