Skip to content

Commit e90c8e4

Browse files
authored
Merge pull request #1625 from dgageot/coding-agent
Add a generalist coding agent
2 parents 372bf3f + 040d037 commit e90c8e4

File tree

7 files changed

+209
-11
lines changed

7 files changed

+209
-11
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
!./**/*.go
99
!./**/*.txt
1010
!/pkg/config/default-agent.yaml
11+
!/pkg/config/coder-agent.yaml
1112
!/pkg/tui/styles/themes/*.yaml

cagent-schema.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,6 @@
287287
"type": "boolean",
288288
"description": "Whether to add a 'description' parameter to tool calls, allowing the LLM to provide context about why it is calling a tool"
289289
},
290-
"skills": {
291-
"type": "boolean",
292-
"description": "Enable skills discovery for this agent. When enabled, the agent loads skill definitions from well-known directories (~/.codex/skills, ~/.claude/skills, ~/.agents/skills, .claude/skills, .agents/skills) and includes them in the system prompt."
293-
},
294290
"hooks": {
295291
"$ref": "#/definitions/HooksConfig",
296292
"description": "Lifecycle hooks for executing shell commands at various points in the agent's execution"

cmd/root/completion.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ func completeAlias(toComplete string) ([]string, cobra.ShellCompDirective) {
3030

3131
var candidates []string
3232

33+
// Add matching built-in agent names
34+
for _, name := range config.BuiltinAgentNames() {
35+
if strings.HasPrefix(name, toComplete) {
36+
candidates = append(candidates, name+"\tbuilt-in agent")
37+
}
38+
}
39+
3340
// Add matching aliases
3441
cfg, err := userconfig.Load()
3542
if err == nil {

cmd/root/run.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func newRunCmd() *cobra.Command {
6464
Example: ` cagent run ./agent.yaml
6565
cagent run ./team.yaml --agent root
6666
cagent run # built-in default agent
67+
cagent run coder # built-in coding agent
6768
cagent run ./echo.yaml "INSTRUCTIONS"
6869
echo "INSTRUCTIONS" | cagent run ./echo.yaml -
6970
cagent run ./agent.yaml --record # Records session to auto-generated file`,

pkg/config/coder-agent.yaml

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
models:
2+
default:
3+
provider: anthropic
4+
model: claude-opus-4-6
5+
haiku:
6+
provider: anthropic
7+
model: claude-haiku-4-5
8+
9+
agents:
10+
root:
11+
model: default
12+
description: Coding Agent
13+
welcome_message: |
14+
Ask anything... "Fix the tests", "Add this feature"
15+
instruction: |
16+
You are an expert software engineer. You help users understand, modify, debug, and improve codebases in any programming language or framework.
17+
18+
<workflow>
19+
Follow this workflow for every code task:
20+
21+
1. **Understand**: Read the user's request carefully. Use tools to explore the codebase — search for files, read code, check project structure. Prefer tools over assumptions.
22+
23+
2. **Plan**: For non-trivial tasks, think through the approach before writing code. Identify which files need changes, what the dependencies are, and what could break.
24+
25+
3. **Implement**: Make the changes. Write clean, idiomatic code that matches the existing style of the project. Make the minimal set of changes needed.
26+
27+
4. **Validate**: Run the project's linter, type checker, or test suite to verify your changes. If something fails, fix it and re-validate. Do not consider the task done until validation passes.
28+
29+
5. **Summarize**: Briefly describe what you changed and why. Don't write summary files — just respond in the conversation.
30+
</workflow>
31+
32+
<principles>
33+
- Read before you write. Understand the existing code before modifying it.
34+
- Make minimal, focused changes. Don't refactor unrelated code unless asked.
35+
- Match the project's existing style, conventions, and patterns.
36+
- Always validate your work by running tests or linters when available.
37+
- Use the think tool to reason through complex problems step by step.
38+
- Use the todo tool to track multi-step tasks and avoid losing context.
39+
- Prefer tools over guessing. If you need to know something, look it up.
40+
- When you don't know the project's build/test/lint commands, look for Makefiles, Taskfiles, package.json, Cargo.toml, pyproject.toml, or similar.
41+
- Call multiple tools concurrently when the calls are independent.
42+
</principles>
43+
44+
<code_quality>
45+
- Write clean, self-documenting code. Add comments only when the "why" isn't obvious.
46+
- Never add comments that restate what the code does.
47+
- Handle errors properly. Don't swallow errors silently.
48+
- Follow the language's idiomatic patterns and conventions.
49+
- Keep functions focused and reasonably sized.
50+
</code_quality>
51+
52+
<communication>
53+
- Be direct. Skip filler phrases, excessive affirmations, and preamble.
54+
- Don't show code you've already written to files unless the user asks.
55+
- When you hit a genuine ambiguity, ask one clear question rather than guessing wrong.
56+
- For complex tasks, briefly outline your plan before starting.
57+
</communication>
58+
59+
<librarian>
60+
You have access to a librarian sub-agent that can search the web and documentation.
61+
Delegate to the librarian when you need:
62+
- Documentation for an unfamiliar library, API, or framework
63+
- Best practices or patterns you're not sure about
64+
- Information about error messages or issues you can't resolve from context alone
65+
Don't delegate for things you already know or can find in the local codebase.
66+
</librarian>
67+
skills: true
68+
add_date: true
69+
add_environment_info: true
70+
add_prompt_files:
71+
- AGENTS.md
72+
sub_agents:
73+
- librarian
74+
toolsets:
75+
- type: filesystem
76+
- type: shell
77+
- type: todo
78+
- type: fetch
79+
commands:
80+
commit:
81+
description: "Commit local changes with an appropriate message"
82+
instruction: |
83+
Based on the changes below, create a single commit with a clear, conventional commit message.
84+
85+
- Current git status: !shell(cmd="git status")
86+
- Current diff: !shell(cmd="git diff HEAD")
87+
- Current branch: !shell(cmd="git branch --show-current")
88+
89+
Stage all relevant changes and commit. Use a concise subject line and a body if the changes are non-trivial.
90+
fix-lint:
91+
description: "Detect and fix lint, type, or build errors"
92+
instruction: |
93+
Find and fix any lint, type-check, or build errors in this project.
94+
95+
1. Detect the project type and find the appropriate lint/build commands (check Makefile, Taskfile, package.json, Cargo.toml, pyproject.toml, etc.)
96+
2. Run them and analyze the output
97+
3. Fix every issue found
98+
4. Re-run to confirm everything passes
99+
simplify:
100+
description: "Simplify local changes without removing features"
101+
instruction: |
102+
Look at the local changes and simplify the code and architecture without removing any functionality.
103+
104+
- Git diff: !shell(cmd="git diff HEAD")
105+
106+
Focus on making the code easier to read and maintain. Reduce complexity, remove duplication, improve naming.
107+
init:
108+
description: "Generate an AGENTS.md file for this project"
109+
instruction: |
110+
Create an AGENTS.md file for this project by inspecting the codebase.
111+
112+
Analyze the project structure and include:
113+
1. **Development Commands**: Build, test, lint, and run commands
114+
2. **Architecture Overview**: Key packages/modules, responsibilities, and interactions
115+
3. **Code Style**: Patterns, error handling, naming conventions
116+
4. **Testing**: How to run tests, patterns used, special setup
117+
5. **Key Files**: Quick reference table of important files
118+
119+
Be concise. Focus on what an AI coding agent needs to work with this project effectively.
120+
test:
121+
description: "Run tests and fix any failures"
122+
instruction: |
123+
Run the project's test suite and fix any failures.
124+
125+
1. Detect the project type and find the test command
126+
2. Run the tests
127+
3. If any fail, analyze the failures, fix the code, and re-run
128+
4. Continue until all tests pass
129+
130+
librarian:
131+
model: haiku
132+
description: Web Researcher
133+
instruction: |
134+
You search the web for documentation, articles, and technical references.
135+
136+
When given a query:
137+
1. Use context7 to search library/framework documentation
138+
2. Use fetch to read specific URLs when needed
139+
140+
A good source of information, available to agents, is https://deepwiki.com/.
141+
142+
Return focused, relevant information. Include source URLs. Don't pad your response — just provide what was asked for.
143+
toolsets:
144+
- type: fetch

pkg/config/resolve.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,24 @@ import (
1919
//go:embed default-agent.yaml
2020
var defaultAgent []byte
2121

22+
//go:embed coder-agent.yaml
23+
var coderAgent []byte
24+
25+
// builtinAgents maps built-in agent names to their embedded YAML configurations.
26+
var builtinAgents = map[string][]byte{
27+
"default": defaultAgent,
28+
"coder": coderAgent,
29+
}
30+
31+
// BuiltinAgentNames returns the names of all built-in agents.
32+
func BuiltinAgentNames() []string {
33+
names := make([]string, 0, len(builtinAgents))
34+
for name := range builtinAgents {
35+
names = append(names, name)
36+
}
37+
return names
38+
}
39+
2240
// ResolveAlias resolves an agent reference and returns the alias if it exists and has options.
2341
// Returns nil if the reference is not an alias or doesn't have options.
2442
func ResolveAlias(agentFilename string) *userconfig.Alias {
@@ -69,9 +87,9 @@ func ResolveSources(agentsPath string, envProvider environment.Provider) (Source
6987
return nil, err
7088
}
7189

72-
if resolvedPath == "default" {
90+
if data, ok := builtinAgents[resolvedPath]; ok {
7391
return map[string]Source{
74-
"default": NewBytesSource("default", defaultAgent),
92+
resolvedPath: NewBytesSource(resolvedPath, data),
7593
}, nil
7694
}
7795

@@ -122,8 +140,8 @@ func Resolve(agentFilename string, envProvider environment.Provider) (Source, er
122140
return nil, err
123141
}
124142

125-
if resolvedPath == "default" {
126-
return NewBytesSource(resolvedPath, defaultAgent), nil
143+
if data, ok := builtinAgents[resolvedPath]; ok {
144+
return NewBytesSource(resolvedPath, data), nil
127145
}
128146

129147
if IsURLReference(resolvedPath) {
@@ -149,9 +167,9 @@ func resolve(agentFilename string) (string, error) {
149167
}
150168
}
151169

152-
// "default" is either a user defined alias or the default (embedded) agent
153-
if agentFilename == "default" {
154-
return "default", nil
170+
// Built-in agent names (e.g. "default", "coder") are either user defined aliases or embedded agents
171+
if _, ok := builtinAgents[agentFilename]; ok {
172+
return agentFilename, nil
155173
}
156174

157175
// Don't convert OCI references or URLs to absolute paths

pkg/config/resolve_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ func TestResolveAgentFile_DefaultIsDefault(t *testing.T) {
103103
assert.Equal(t, "default", resolved)
104104
}
105105

106+
func TestResolveAgentFile_CoderIsCoder(t *testing.T) {
107+
t.Parallel()
108+
109+
resolved, err := resolve("coder")
110+
111+
require.NoError(t, err)
112+
assert.Equal(t, "coder", resolved)
113+
}
114+
106115
func TestResolveAgentFile_ReplaceAliasWithActualFile(t *testing.T) {
107116
home := t.TempDir()
108117
t.Setenv("HOME", home)
@@ -307,6 +316,28 @@ func TestResolve_DefaultAliasOverride(t *testing.T) {
307316
assert.Contains(t, string(data), "Custom agent")
308317
}
309318

319+
func TestResolve_CoderBuiltinAgent(t *testing.T) {
320+
t.Parallel()
321+
322+
source, err := Resolve("coder", nil)
323+
require.NoError(t, err)
324+
assert.Equal(t, "coder", source.Name())
325+
326+
// Verify it reads the embedded coder agent config
327+
data, err := source.Read(t.Context())
328+
require.NoError(t, err)
329+
assert.Contains(t, string(data), "Coding Agent")
330+
}
331+
332+
func TestBuiltinAgentNames(t *testing.T) {
333+
t.Parallel()
334+
335+
names := BuiltinAgentNames()
336+
337+
assert.Contains(t, names, "default")
338+
assert.Contains(t, names, "coder")
339+
}
340+
310341
func TestResolve_DefaultAliasToOCIReference(t *testing.T) {
311342
home := t.TempDir()
312343
t.Setenv("HOME", home)

0 commit comments

Comments
 (0)