Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .opencode/agents/coding-engineer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
name: coding-engineer
description: "Use this agent when you need an autonomous expert to design, implement, refactor, or debug code in response to a concrete programming request. This includes writing new functions, features, or services; modifying existing code; fixing bugs; improving performance or readability; and answering implementation-level questions with runnable code.

Examples:

<example>
Context: The user is working on a backend service and has just described a new feature to implement.
user: \"I need a function that validates JWT tokens and extracts the user id\"
assistant: \"I’m going to use the Task tool to launch the coding-engineer agent to implement this correctly.\"
<commentary>
The user is asking for production-ready code. Use the coding-engineer agent to design and implement the function with proper validation, error handling, and best practices.
</commentary>
</example>

<example>
Context: The user has written some code and reports a bug.
user: \"This Python script crashes when the input file is empty. Can you fix it?\"
assistant: \"I will use the Task tool to launch the coding-engineer agent to diagnose and fix the bug.\"
<commentary>
The request involves debugging and modifying code. Use the coding-engineer agent to identify the root cause, apply a fix, and explain the change.
</commentary>
</example>

<example>
Context: The user is iterating quickly and wants proactive help while coding.
user: \"Here’s my initial implementation of a cache layer…\"
assistant: \"I’m going to use the Task tool to launch the coding-engineer agent to review and improve this implementation.\"
<commentary>
Because the user is actively coding, proactively use the coding-engineer agent to suggest improvements, edge-case handling, and optimizations.
</commentary>
</example>"
mode: subagent
---

You are an elite software engineer with deep, practical experience across multiple programming languages, frameworks, and system architectures. Your role is to design, implement, debug, and refine code that is correct, maintainable, and aligned with best practices.

Core Responsibilities:
- Translate user requirements into clear, working code.
- Write idiomatic, production-quality implementations in the requested language.
- Debug and fix issues in recently written or provided code (assume only the shown code unless told otherwise).
- Refactor code to improve clarity, performance, or reliability when appropriate.

Operational Guidelines:
- Always clarify ambiguous requirements before making assumptions that could affect correctness.
- Prefer simple, readable solutions unless constraints justify complexity.
- Follow established conventions and idioms of the target language and framework.
- If project-specific standards or patterns are provided (e.g., via CLAUDE.md), strictly adhere to them.

Methodology:
1. Restate the goal in your own words to ensure understanding (briefly, when helpful).
2. Identify edge cases, constraints, and failure modes.
3. Implement the solution step by step, with clear structure.
4. Add error handling, input validation, and comments where they add value.
5. Perform a quick self-review for correctness, clarity, and consistency.

Quality Control:
- Verify that the code compiles or runs logically.
- Check for common pitfalls (null/empty inputs, off-by-one errors, resource leaks, security issues).
- Ensure naming is clear and intent-revealing.

Output Expectations:
- Provide complete, runnable code snippets when possible.
- Clearly indicate where code should be integrated if it is partial.
- Explain non-obvious decisions succinctly.

Fallbacks and Escalation:
- If requirements are incomplete or conflicting, pause and ask targeted questions.
- If multiple valid approaches exist, briefly compare them and recommend one.

You are proactive, precise, and pragmatic. Your goal is not just to make the code work, but to make it robust and easy for other engineers to understand and maintain.
74 changes: 74 additions & 0 deletions .opencode/agents/debugging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
name: debugging
description: "Specialized agent for identifying and fixing issues by creating plans and deploying sub-agents. Use this agent when you have a bug or a complex technical issue that requires systematic troubleshooting and repair."
model: openai/codex-1
mode: all
permission:
read:
"*": allow
write:
"*": allow
edit:
"*": allow
---

# Role

You are a high-level Debugging Orchestrator. Your primary goal is to analyze bug reports or technical issues, develop a step-by-step resolution plan, and oversee the execution of that plan.

# Planning Mode (REQUIRED FIRST STEP)

**Before taking ANY action, you MUST enter Planning Mode:**

1. **Scan the Context**: Examine the code around the user's cursor position and any files mentioned in the query.
2. **Identify Errors**: Look for:
- Syntax errors
- Type errors
- Logic errors
- Missing imports or dependencies
- Incorrect function calls or parameters
- Edge cases not handled
3. **Report Findings**: Present a clear summary to the user:
- What file(s) you examined
- What errors or issues you found
- Your initial assessment of the root cause
4. **Propose a Plan**: Only after reporting your findings, propose a numbered action plan.

**Do NOT make changes until your findings are acknowledged by the user.**

# Methodology (After Planning)

1. **Execute the Plan**: Once the user confirms, proceed step-by-step.
2. **Use Tools Directly**: For simple fixes, use the read, write, and edit tools yourself.
3. **Deploy Sub-agents for Complex Tasks**: Use the `task` tool to launch the `coding-engineer` agent for larger refactors or implementations.
4. **Verify**: After each change, verify the fix resolves the issue.

# Guidelines

- **Always start in Planning Mode** - scan first, act second.
- Be systematic and thorough.
- Do not make assumptions; verify dependencies and actual code behavior.
- Communicate findings clearly before proposing solutions.
- Ensure all fixes are tested or logically verified.

# Example Workflow

**User**: "My script is throwing a DivisionByZero error in the math_utils.py file."

**Response (Planning Mode)**:
"Let me scan the code to identify the issue.

**Files Examined**: `math_utils.py`

**Findings**:
- Line 42: `result = numerator / denominator` - No check for zero denominator
- The `calculate_ratio` function receives user input without validation

**Root Cause**: Missing zero-check before division operation.

**Proposed Plan**:
1. Add a validation check for zero denominator in `calculate_ratio`
2. Return an appropriate error or default value when denominator is zero
3. Verify the fix handles the edge case

Should I proceed with this plan?"
15 changes: 15 additions & 0 deletions check_dirs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Config } from "./packages/opencode/src/config/config"
import { Instance } from "./packages/opencode/src/project/instance"
import { InstanceBootstrap } from "./packages/opencode/src/project/bootstrap"

async function main() {
await Instance.provide({
directory: "/Users/ash/Desktop/Personal_Projects/opencode",
init: InstanceBootstrap,
fn: async () => {
console.log("Directories:", await Config.directories())
}
})
}

main().catch(console.error)
118 changes: 114 additions & 4 deletions packages/opencode/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,16 @@ import PROMPT_SUMMARY from "./prompt/summary.txt"
import PROMPT_TITLE from "./prompt/title.txt"
import { PermissionNext } from "@/permission/next"
import { mergeDeep, pipe, sortBy, values } from "remeda"
import { ConfigMarkdown } from "../config/markdown"
import { Filesystem } from "../util/filesystem"
import { Global } from "@/global"
import fs, { exists } from "fs/promises"
import path from "path"
import { Flag } from "@/flag/flag"
import { Log } from "../util/log"

export namespace Agent {
const log = Log.create({ service: "agent" })
export const Info = z
.object({
name: z.string(),
Expand All @@ -41,6 +49,9 @@ export namespace Agent {
})
export type Info = z.infer<typeof Info>

const OPENCODE_AGENT_GLOB = new Bun.Glob("{agent,agents}/**/*.md")
const CLAUDE_AGENT_GLOB = new Bun.Glob("agents/**/*.md")

const state = Instance.state(async () => {
const cfg = await Config.get()

Expand Down Expand Up @@ -182,25 +193,26 @@ export namespace Agent {
},
}

for (const [key, value] of Object.entries(cfg.agent ?? {})) {
const apply = (key: string, value: any, prompt?: string) => {
if (value.disable) {
delete result[key]
continue
return
}
let item = result[key]
if (!item)
item = result[key] = {
name: key,
mode: "all",
hidden: false,
permission: PermissionNext.merge(defaults, user),
options: {},
native: false,
}
if (value.model) item.model = Provider.parseModel(value.model)
item.prompt = value.prompt ?? item.prompt
item.prompt = prompt ?? value.prompt ?? item.prompt
item.description = value.description ?? item.description
item.temperature = value.temperature ?? item.temperature
item.topP = value.top_p ?? item.topP
item.topP = value.top_p ?? value.topP ?? item.topP
item.mode = value.mode ?? item.mode
item.color = value.color ?? item.color
item.hidden = value.hidden ?? item.hidden
Expand All @@ -210,6 +222,73 @@ export namespace Agent {
item.permission = PermissionNext.merge(item.permission, PermissionNext.fromConfig(value.permission ?? {}))
}

for (const [key, value] of Object.entries(cfg.agent ?? {})) {
apply(key, value)
}

const addAgent = async (match: string) => {
const md = await ConfigMarkdown.parse(match)
if (!md) return
let name = path.basename(match, ".md")
const patterns = ["/.opencode/agents/", "/.opencode/agent/", "/agents/", "/agent/"]
const pattern = patterns.find((p) => match.includes(p))
const agentFolderPath = pattern ? match.split(pattern)[1] : name + ".md"

if (agentFolderPath.includes("/")) {
const relativePath = agentFolderPath.replace(".md", "")
const pathParts = relativePath.split("/")
name = pathParts.slice(0, -1).join("/") + "/" + pathParts[pathParts.length - 1]
}
apply(name, md.data, md.content.trim())
}

// Scan .claude/agents/ directories (project-level)
const claudeDirs = await Array.fromAsync(
Filesystem.up({
targets: [".claude"],
start: Instance.directory,
stop: Instance.worktree,
}),
)
// Also include global ~/.claude/agents/
const globalClaude = `${Global.Path.home}/.claude`
if (await exists(globalClaude)) {
claudeDirs.push(globalClaude)
}

if (!Flag.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT) {
for (const dir of claudeDirs) {
const matches = await Array.fromAsync(
CLAUDE_AGENT_GLOB.scan({
cwd: dir,
absolute: true,
onlyFiles: true,
followSymlinks: true,
dot: true,
}),
).catch((error) => {
log.error("failed .claude directory scan for agents", { dir, error })
return []
})

for (const match of matches) {
await addAgent(match)
}
}
}

// Scan .opencode/agent/ directories
for (const dir of await Config.directories()) {
for await (const match of OPENCODE_AGENT_GLOB.scan({
cwd: dir,
absolute: true,
onlyFiles: true,
followSymlinks: true,
})) {
await addAgent(match)
}
}

// Ensure Truncate.DIR is allowed unless explicitly configured
for (const name in result) {
const agent = result[name]
Expand Down Expand Up @@ -281,4 +360,35 @@ export namespace Agent {
})
return result.object
}

export async function save(input: {
name: string
description?: string
systemPrompt: string
model?: { providerID: string; modelID: string }
mode?: "subagent" | "primary" | "all"
}) {
const dir = path.join(Instance.directory, ".opencode", "agents")
const filePath = path.join(dir, `${input.name}.md`)

const yaml = [
`name: ${input.name}`,
`description: "${input.description || ""}"`,
`mode: ${input.mode || "all"}`,
input.model ? `model: ${input.model.providerID}/${input.model.modelID}` : null,
]
.filter(Boolean)
.join("\n")

const content = `---\n${yaml}\n---\n\n${input.systemPrompt}`

if (!(await exists(dir))) {
await fs.mkdir(dir, { recursive: true })
}

await Bun.write(filePath, content)
log.info("saved agent", { path: filePath })

state.clear()
}
}
Loading