Feature hasn't been suggested before.
Describe the enhancement you want to request
I've been experimenting with a new concept to reduce context usage: the forget tool. This tool allows the LLM to choose one or more previous messages in the session to be forgotten (and replace them with a summary optionally), ie messages/files/toolcalls that are no longer required as the LLM itself judges. Typical use case would be reading a log file, find needle in the hay stack, then summarize what was found and forget the log file.
Sometimes you need to go through that process a number of times to get to the bottom of an issue with multiple log files loaded the context could be filled in no time. Other usecases are when implementing multiple features, the forget tool allows the LLM to remove context of previous items so that it doesn't get confused.
The user can also use the /forget [id] command to forget a message. The messages are only hidden from the LLM, the session history contains the full messages, including the replacement messages. /export is also updated to include this and is handy for debugging.
Anyway, it's not perfect, since injecting markers so that the LLM knows what it can indicate to forget to the backend needs to be injected to the messages and as LLMs do, they tend to copy and mimic the markers in their own messages. I've implemented a rather aggressive strategy to remove those markers and send the LLM silent messages to stop doing that. But at least it no longer leads to repetition/being stuck in a loop.
Anyway anyway, it works quite well I might say. It often keeps the context usage below 50k-100k and compacting is so far never needed. It's so much fun to see the token usage actually dropping and bouncing up and down instead of always growing.
Though it must be noted that there could be issues with providers caching the context, and cache misses can still increase the context usage, defeating the purpose of reducing cost, still reducing context so that it doesn't fill up is also valuable. I've not put much time analysing this though.
It's a hassle to keep the project aligned with the latest commits. I've implemented it (with Opus) directly in the source code since there's no hook to make use of. Therefore, for now, I'd humbly request to add those hooks so that I can change this into a plugin. I don't think it's ready to be merged into mainstream opencode (may never be suitable for that, due to the issues with the injected markers). But users can chose to use it as a plugin, and it would save me a lot of hassle keeping the forget tool up to date. Other plugin writers could also benefit to the improved access, potentially getting more varied types of plugins.
Here's the fork of my forget tool project if you're interested in trying it out:
https://github.com/imqqmi/opencode
Here's the Claude Opus generated proposal for adding those hooks:
GitHub Issue: Plugin API Extensions for Context Management Features
Title: Feature Request: Plugin API Extensions for Storage, Schema, TUI, and Command Registration
Summary
This proposal requests four new plugin hooks that would enable plugins to implement rich context management features (like a "forget tool" for hiding irrelevant context) without requiring direct codebase modifications.
Currently, the plugin system supports authentication providers, stateless tools, and ephemeral message transformations. However, features requiring persistence, schema extensions, TUI integration, or user commands cannot be implemented as plugins.
Motivation
While building a context management tool that allows the LLM to hide old/irrelevant content from its context window, I discovered that the current plugin architecture only supports ~25-30% of the required functionality. The remaining 70% required direct codebase modification.
A plugin-based approach would:
- Allow experimentation without forking the codebase
- Enable community-driven feature development
- Keep the core lean while extending capabilities
- Make features portable across OpenCode installations
Proposed Plugin Hooks
1. Storage API Hook
Purpose: Allow plugins to read and update message parts in storage.
// In PluginInput or as a separate hook
interface StorageAPI {
updatePart(sessionID: string, partID: string, updates: Partial<Part>): Promise<void>
getParts(sessionID: string, messageID: string): Promise<Part[]>
getPartByChunkID?(sessionID: string, chunkID: string): Promise<Part | null>
}
// Plugin access
export default async function(input: PluginInput & { storage: StorageAPI }): Promise<Hooks> {
// Can now persist state to OpenCode's storage system
await input.storage.updatePart(sessionID, partID, { customField: "value" })
}
Use Cases:
- Context management tools that mark parts as hidden
- Annotation tools that add metadata to parts
- Rating/feedback systems for LLM responses
2. Schema Extension Hook
Purpose: Allow plugins to register additional optional fields on existing schemas.
"schema.extend": (schemas) => {
schemas.Part.extend({
chunkID: z.string().optional(),
hiddenFromLLM: z.boolean().optional(),
hiddenReplacement: z.string().optional(),
customPluginData: z.record(z.unknown()).optional(),
})
}
Design Considerations:
- All plugin-added fields must be
.optional() for backward compatibility
- Fields could be namespaced:
pluginName.fieldName to avoid conflicts
- Schema changes would need to be declarative and validated at plugin load time
Use Cases:
- Adding metadata fields for analytics
- Custom categorization/tagging of messages
- Storing plugin-specific state on existing entities
3. TUI Rendering Hook
Purpose: Allow plugins to customize how parts are rendered in the terminal UI.
"tui.render.part": (part, context) => {
// Return custom rendering or null to use default
if (part.hiddenFromLLM) {
return {
style: "subdued", // or custom ink components
prefix: "[Hidden] ",
collapsed: true,
expandable: true,
}
}
return null // Use default rendering
}
// Or more granular:
"tui.render.part.style": (part) => {
if (part.hiddenFromLLM) return { opacity: 0.5, color: "gray" }
return null
}
"tui.render.part.badge": (part) => {
if (part.customTag) return { text: part.customTag, color: "blue" }
return null
}
Use Cases:
- Visual indicators for hidden/forgotten content
- Custom badges or labels on messages
- Collapsible sections for large outputs
- Syntax highlighting for custom content types
4. Command Registration Hook
Purpose: Allow plugins to register slash commands accessible to users.
"command.register": {
forget: {
description: "Hide chunks by ID to reduce context",
usage: "/forget <chunkID> [chunkID...]",
args: z.object({
chunkIDs: z.array(z.string()),
}),
execute: async (args, ctx) => {
// ctx includes session info, storage access, etc.
for (const id of args.chunkIDs) {
await ctx.storage.updatePart(ctx.sessionID, id, { hiddenFromLLM: true })
}
return { success: true, message: `Hidden ${args.chunkIDs.length} chunks` }
},
},
// Another example
"show-hidden": {
description: "Toggle visibility of hidden content in TUI",
execute: async (args, ctx) => {
ctx.tui.setOption("showHiddenContent", !ctx.tui.getOption("showHiddenContent"))
return { success: true }
},
},
}
Use Cases:
- User-facing commands for plugin features
- Quick actions without going through the LLM
- Settings/preference commands
- Debug/diagnostic commands
Implementation Considerations
Backward Compatibility
- All new fields must be optional
- Existing sessions should work without migration
- Plugins should gracefully handle missing data
Security
- Storage API should be scoped to prevent cross-session access
- Schema extensions should be validated
- Command execution should respect existing permission model
Performance
- TUI hooks should be fast (< 16ms for smooth rendering)
- Storage API should batch operations where possible
- Schema extensions should be resolved at plugin load time
Alternatives Considered
- Fork and modify: Works but fragments the ecosystem
- External state file: Loses integration with OpenCode's session system
- Message transform only: Can't persist state or integrate with TUI
- Monkey patching: Fragile and not supportable
Prior Art
- VSCode Extension API: Provides rich hooks for editor customization
- Obsidian Plugin API: Schema-like "frontmatter" extensions
- Neovim plugins: Command registration and UI customization
- Zed extensions: Similar storage and rendering hooks
Willingness to Contribute
I'm willing to help implement these hooks if there's interest from the maintainers. The analysis document (docs/PLUGIN_CONSIDERATIONS.md) includes references to the relevant code locations.
Related Files (for reference)
- Plugin interface:
/src/packages/plugin/src/index.ts
- Plugin loading:
/src/packages/opencode/src/plugin/index.ts
- Tool registration:
/src/packages/opencode/src/tool/registry.ts
- Message transform hook:
/src/packages/opencode/src/session/prompt.ts
- Schema definitions:
/src/packages/opencode/src/session/message-v2.ts
Feature hasn't been suggested before.
Describe the enhancement you want to request
I've been experimenting with a new concept to reduce context usage: the forget tool. This tool allows the LLM to choose one or more previous messages in the session to be forgotten (and replace them with a summary optionally), ie messages/files/toolcalls that are no longer required as the LLM itself judges. Typical use case would be reading a log file, find needle in the hay stack, then summarize what was found and forget the log file.
Sometimes you need to go through that process a number of times to get to the bottom of an issue with multiple log files loaded the context could be filled in no time. Other usecases are when implementing multiple features, the forget tool allows the LLM to remove context of previous items so that it doesn't get confused.
The user can also use the /forget [id] command to forget a message. The messages are only hidden from the LLM, the session history contains the full messages, including the replacement messages. /export is also updated to include this and is handy for debugging.
Anyway, it's not perfect, since injecting markers so that the LLM knows what it can indicate to forget to the backend needs to be injected to the messages and as LLMs do, they tend to copy and mimic the markers in their own messages. I've implemented a rather aggressive strategy to remove those markers and send the LLM silent messages to stop doing that. But at least it no longer leads to repetition/being stuck in a loop.
Anyway anyway, it works quite well I might say. It often keeps the context usage below 50k-100k and compacting is so far never needed. It's so much fun to see the token usage actually dropping and bouncing up and down instead of always growing.
Though it must be noted that there could be issues with providers caching the context, and cache misses can still increase the context usage, defeating the purpose of reducing cost, still reducing context so that it doesn't fill up is also valuable. I've not put much time analysing this though.
It's a hassle to keep the project aligned with the latest commits. I've implemented it (with Opus) directly in the source code since there's no hook to make use of. Therefore, for now, I'd humbly request to add those hooks so that I can change this into a plugin. I don't think it's ready to be merged into mainstream opencode (may never be suitable for that, due to the issues with the injected markers). But users can chose to use it as a plugin, and it would save me a lot of hassle keeping the forget tool up to date. Other plugin writers could also benefit to the improved access, potentially getting more varied types of plugins.
Here's the fork of my forget tool project if you're interested in trying it out:
https://github.com/imqqmi/opencode
Here's the Claude Opus generated proposal for adding those hooks:
GitHub Issue: Plugin API Extensions for Context Management Features
Title: Feature Request: Plugin API Extensions for Storage, Schema, TUI, and Command Registration
Summary
This proposal requests four new plugin hooks that would enable plugins to implement rich context management features (like a "forget tool" for hiding irrelevant context) without requiring direct codebase modifications.
Currently, the plugin system supports authentication providers, stateless tools, and ephemeral message transformations. However, features requiring persistence, schema extensions, TUI integration, or user commands cannot be implemented as plugins.
Motivation
While building a context management tool that allows the LLM to hide old/irrelevant content from its context window, I discovered that the current plugin architecture only supports ~25-30% of the required functionality. The remaining 70% required direct codebase modification.
A plugin-based approach would:
Proposed Plugin Hooks
1. Storage API Hook
Purpose: Allow plugins to read and update message parts in storage.
Use Cases:
2. Schema Extension Hook
Purpose: Allow plugins to register additional optional fields on existing schemas.
Design Considerations:
.optional()for backward compatibilitypluginName.fieldNameto avoid conflictsUse Cases:
3. TUI Rendering Hook
Purpose: Allow plugins to customize how parts are rendered in the terminal UI.
Use Cases:
4. Command Registration Hook
Purpose: Allow plugins to register slash commands accessible to users.
Use Cases:
Implementation Considerations
Backward Compatibility
Security
Performance
Alternatives Considered
Prior Art
Willingness to Contribute
I'm willing to help implement these hooks if there's interest from the maintainers. The analysis document (
docs/PLUGIN_CONSIDERATIONS.md) includes references to the relevant code locations.Related Files (for reference)
/src/packages/plugin/src/index.ts/src/packages/opencode/src/plugin/index.ts/src/packages/opencode/src/tool/registry.ts/src/packages/opencode/src/session/prompt.ts/src/packages/opencode/src/session/message-v2.ts