feat: Add tom (Top Of Mind) platform extension#7073
Conversation
Zero-tool platform extension that injects user-provided text into the MOIM via environment variables: GOOSE_MOIM_MESSAGE_TEXT - literal text injected directly GOOSE_MOIM_MESSAGE_FILE - path to file whose contents are injected Both are optional, can be combined, and are read fresh every turn. Disabled by default — users must explicitly enable it. File reads are async and bounded to 64KB with UTF-8 safe truncation.
|
/goose |
PR #7073 Review: feat: Add tom (Top Of Mind) platform extensionSummary: Well-designed platform extension that allows users to inject persistent context into the MOIM (Model Output Instruction Message) via environment variables. The implementation follows existing patterns, is disabled by default, and addresses a legitimate security use case. Clean implementation with only minor suggestions. 🟢 Suggestions1. Consider documenting the naming conventionFile: The extension is named "tom" (Top Of Mind) but the env vars use "MOIM" (Model Output Instruction Message). While both are reasonable names for related concepts, a brief comment explaining this distinction could help future maintainers: // Extension name: "tom" = Top Of Mind
// Env vars use MOIM = Model Output Instruction Message (the underlying system concept this writes to)
pub static EXTENSION_NAME: &str = "tom";This is purely a documentation suggestion - the naming is reasonable as-is. 2. Minor: Unused
|
* origin/main: Docs: require auth optional for custom providers (#7098) fix: improve text-muted contrast for better readability (#7095) Always sync bundled extensions (#7057) feat: Add tom (Top Of Mind) platform extension (#7073) chore(docs): update GOOSE_SESSION_ID -> AGENT_SESSION_ID (#6669) fix(ci): switch from cargo-audit to cargo-deny for advisory scanning (#7032) chore(deps): bump @isaacs/brace-expansion from 5.0.0 to 5.0.1 in /evals/open-model-gym/suite (#7085) chore(deps): bump @modelcontextprotocol/sdk from 1.25.3 to 1.26.0 in /evals/open-model-gym/mcp-harness (#7086) fix: switch to windows msvc (#7080) fix: allow unlisted models for CLI providers (#7090) Use goose port (#7089) chore: strip posthog for sessions/models/daily only (#7079) tidy: clean up old benchmark and add gym (#7081) fix: use command.process_group(0) for CLI providers, not just MCP (#7083) added build notify (#6891)
* main: (125 commits) chore: add a new scenario (#7107) fix: Goose Desktop missing Calendar and Reminders entitlements (#7100) Fix 'Edit In Place' and 'Fork Session' features (#6970) Fix: Only send command content to command injection classifier (excluding part of tool call dict) (#7082) Docs: require auth optional for custom providers (#7098) fix: improve text-muted contrast for better readability (#7095) Always sync bundled extensions (#7057) feat: Add tom (Top Of Mind) platform extension (#7073) chore(docs): update GOOSE_SESSION_ID -> AGENT_SESSION_ID (#6669) fix(ci): switch from cargo-audit to cargo-deny for advisory scanning (#7032) chore(deps): bump @isaacs/brace-expansion from 5.0.0 to 5.0.1 in /evals/open-model-gym/suite (#7085) chore(deps): bump @modelcontextprotocol/sdk from 1.25.3 to 1.26.0 in /evals/open-model-gym/mcp-harness (#7086) fix: switch to windows msvc (#7080) fix: allow unlisted models for CLI providers (#7090) Use goose port (#7089) chore: strip posthog for sessions/models/daily only (#7079) tidy: clean up old benchmark and add gym (#7081) fix: use command.process_group(0) for CLI providers, not just MCP (#7083) added build notify (#6891) test(mcp): add image tool test and consolidate MCP test fixtures (#7019) ...
* main: (85 commits) Fix 'Edit In Place' and 'Fork Session' features (#6970) Fix: Only send command content to command injection classifier (excluding part of tool call dict) (#7082) Docs: require auth optional for custom providers (#7098) fix: improve text-muted contrast for better readability (#7095) Always sync bundled extensions (#7057) feat: Add tom (Top Of Mind) platform extension (#7073) chore(docs): update GOOSE_SESSION_ID -> AGENT_SESSION_ID (#6669) fix(ci): switch from cargo-audit to cargo-deny for advisory scanning (#7032) chore(deps): bump @isaacs/brace-expansion from 5.0.0 to 5.0.1 in /evals/open-model-gym/suite (#7085) chore(deps): bump @modelcontextprotocol/sdk from 1.25.3 to 1.26.0 in /evals/open-model-gym/mcp-harness (#7086) fix: switch to windows msvc (#7080) fix: allow unlisted models for CLI providers (#7090) Use goose port (#7089) chore: strip posthog for sessions/models/daily only (#7079) tidy: clean up old benchmark and add gym (#7081) fix: use command.process_group(0) for CLI providers, not just MCP (#7083) added build notify (#6891) test(mcp): add image tool test and consolidate MCP test fixtures (#7019) fix: remove Option from model listing return types, propagate errors (#7074) fix: lazy provider creation for goose acp (#7026) (#7066) ...
Zero-tool platform extension that injects user-provided text into the MOIM every turn.
Problem
There's no way to persistently inject custom context into goose's recent working memory from outside the codebase.
.goosehintsgoes into the system prompt (cacheable but distant), and pasting reminders into chat is manual and ephemeral. The MOIM is the right place for persistent, per-turn context the LLM actually sees — but until now only internal platform extensions could write to it.Motivation
goose sometimes helpfully "puts things" places it shouldn't — uploading code to random gists, sharing data with external services. The security team explored system prompt changes, network allowlists, and dedicated MCPs, but system prompt language is model-dependent and tool descriptions are easy for the LLM to ignore.
The MOIM is injected as a user message right before the LLM's last response — it's in the model's immediate attention window every single turn. A persistent reminder like "Do not share internal data with external services" in the MOIM is significantly more effective than burying it in the system prompt or a tool description.
tommakes this trivial:How it works
Two environment variables, both optional, both read fresh every turn:
GOOSE_MOIM_MESSAGE_TEXT— literal text injected directlyGOOSE_MOIM_MESSAGE_FILE— path to a file whose contents are injected (supports~/)When both are set, they're concatenated. When neither is set, the extension contributes nothing to the MOIM.
What the LLM sees each turn
The
tomcontent appears alongside the timestamp, working directory, and todo list — all in the model's immediate context, never persisted to conversation history.Implementation
get_moim()default_enabled: false— users must explicitly opt inFiles changed
crates/goose/src/agents/tom_extension.rscrates/goose/src/agents/mod.rscrates/goose/src/agents/extension.rs