-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Feature Request: Allow plugin agents to override mode from frontmatter
Summary
Plugin agents are currently hardcoded to mode: "subagent" and cannot be made switchable via the tab interface. This prevents plugins from providing primary agents that users can switch to, even though the AgentOverrideConfigSchema already supports mode field.
Current Behavior
In loadPluginAgents function (around line 46840 in dist/index.js):
const config3 = {
description: formattedDescription,
mode: "subagent", // <-- Hardcoded
prompt: body.trim()
};All plugin agents are forced to mode: "subagent", regardless of any mode field specified in the agent's frontmatter markdown file.
Desired Behavior
Respect the mode field from agent frontmatter:
const config3 = {
description: formattedDescription,
mode: data.mode || "subagent", // <-- Allow override
prompt: body.trim()
};This would allow plugin authors to create switchable agents by adding:
---
name: my_agent
description: My custom agent
mode: "primary"
---
Agent prompt here...Use Case
I'm developing a plugin for competitive analysis (opencode-competitive-analysis) that orchestrates a team of specialist agents. I want to provide a switchable agent for this workflow so users can:
- Switch to the competitive analysis agent via tab
- Use it as their primary agent for market research tasks
- Leverage the tool orchestrator pattern similar to Sisyphus
Currently, I can only invoke this agent via @plugin-name:agent-name mentions, but not switch to it.
Benefits
- Extensibility: Plugins can provide full-featured primary agents, not just subagents
- Consistency: Aligns with
AgentOverrideConfigSchemawhich already supportsmodefor built-in agents - Simplicity: Small code change with minimal risk
- No Breaking Changes: Defaults to "subagent" if mode not specified
Alternatives Considered
- Forking oh-my-opencode to modify behavior (not ideal - can't benefit from upstream updates)
- Using only tool-based approach (less ergonomic - users prefer switching agents)
- Manually editing oh-my-opencode after each update (not sustainable)
Implementation
// In loadPluginAgents function
function loadPluginAgents(plugins) {
const agents = {};
for (const plugin2 of plugins) {
if (!plugin2.agentsDir || !existsSync50(plugin2.agentsDir))
continue;
const entries = readdirSync18(plugin2.agentsDir, { withFileTypes: true });
for (const entry of entries) {
if (!isMarkdownFile(entry))
continue;
const agentPath = join58(plugin2.agentsDir, entry.name);
const agentName = basename7(entry.name, ".md");
const namespacedName = `${plugin2.name}:${agentName}`;
try {
const content = readFileSync32(agentPath, "utf-8");
const { data, body } = parseFrontmatter(content);
const name = data.name || agentName;
const originalDescription = data.description || "";
const formattedDescription = `(plugin: ${plugin2.name}) ${originalDescription}`;
const config3 = {
description: formattedDescription,
mode: data.mode || "subagent", // Allow override from frontmatter
prompt: body.trim()
};
const toolsConfig = parseToolsConfig2(data.tools);
if (toolsConfig) {
config3.tools = toolsConfig;
}
agents[namespacedName] = config3;
log(`Loaded plugin agent: ${namespacedName}`, { path: agentPath });
} catch (error45) {
log(`Failed to load plugin agent: ${agentPath}`, error45);
}
}
}
return agents;
}Additional Considerations
Should we add validation for the mode field? Ensure it's one of ["subagent", "primary", "all"]?
const validModes = ["subagent", "primary", "all"];
const mode = data.mode || "subagent";
if (!validModes.includes(mode)) {
log(`Warning: Invalid mode "${mode}" for agent ${namespacedName}, defaulting to "subagent"`);
config3.mode = "subagent";
} else {
config3.mode = mode;
}Environment
- OpenCode version: latest
- oh-my-opencode version: 2.14.0
- OS: macOS (darwin)
Thank you for this amazing project! Sisyphus has been incredibly helpful.