178 lines
7.0 KiB
Markdown
178 lines
7.0 KiB
Markdown
# Default Agents — Design
|
||
|
||
**Date:** 2026-04-23
|
||
**Status:** Approved
|
||
|
||
## Goal
|
||
|
||
Ship ClaudeDo with a curated set of default agents so that users have useful agents available on first launch, without losing the file-based ownership model (user-editable, user-deletable). Provide a "Restore defaults" action to recover missing defaults on demand.
|
||
|
||
## Agents to Ship
|
||
|
||
Six markdown agents covering the common stages of task execution plus one general-purpose agent:
|
||
|
||
| File | Focus |
|
||
|---|---|
|
||
| `code-reviewer.md` | Review diff for bugs, logic errors, convention adherence. Flags only high-confidence issues. |
|
||
| `test-writer.md` | Generate unit/integration tests for changed code. Follows existing test patterns. |
|
||
| `debugger.md` | Systematic root-cause analysis — reproduce, isolate, hypothesize, verify. |
|
||
| `security-reviewer.md` | OWASP-style audit focused on auth, SQL injection, input handling, secret exposure. |
|
||
| `explorer.md` | Fast codebase navigation and answering "where/how" questions. Terse output. |
|
||
| `researcher.md` | General-purpose research, doc summarization, analysis, investigation. Non-code. |
|
||
|
||
Each file uses Claude Code's standard agent frontmatter:
|
||
|
||
```markdown
|
||
---
|
||
name: <agent name>
|
||
description: <one-line description>
|
||
---
|
||
|
||
<system prompt body>
|
||
```
|
||
|
||
Content target: ~20–40 lines per file. Style matches the existing Claude Code agent conventions.
|
||
|
||
## Behavior
|
||
|
||
**Seed on first launch, restore on demand:**
|
||
|
||
1. Bundled agents live alongside the Worker binary at `<AppContext.BaseDirectory>/DefaultAgents/*.md`.
|
||
2. At Worker startup, for each bundled file: if `~/.todo-app/agents/<name>.md` does NOT exist, copy it in. If it exists, leave it alone — the user owns their copy.
|
||
3. A "Restore default agents" button in the settings modal re-runs the same check, restoring any that the user has deleted.
|
||
|
||
The seed path and the restore path are the same code — only the invocation differs (startup vs. hub call).
|
||
|
||
## Components
|
||
|
||
### `DefaultAgents/*.md` (bundled content)
|
||
|
||
Location: `src/ClaudeDo.Worker/DefaultAgents/`
|
||
Packaging: `<Content Include="DefaultAgents\*.md" CopyToOutputDirectory="PreserveNewest" />` in `ClaudeDo.Worker.csproj`.
|
||
At runtime they land at `<AppContext.BaseDirectory>/DefaultAgents/*.md` next to the executable.
|
||
|
||
### `DefaultAgentSeeder` (new service)
|
||
|
||
Location: `src/ClaudeDo.Worker/Services/DefaultAgentSeeder.cs`
|
||
|
||
```
|
||
public sealed class DefaultAgentSeeder
|
||
{
|
||
public DefaultAgentSeeder(string bundleDir, string targetDir);
|
||
public Task<SeedResult> SeedMissingAsync(CancellationToken ct = default);
|
||
}
|
||
|
||
public sealed record SeedResult(int Copied, int Skipped);
|
||
```
|
||
|
||
Behavior of `SeedMissingAsync`:
|
||
- If `bundleDir` doesn't exist, log warning and return `(0, 0)`.
|
||
- Enumerate `*.md` in `bundleDir`.
|
||
- For each file, if the target path (`targetDir/<filename>`) is missing, copy it; else increment `Skipped`.
|
||
- Create `targetDir` if missing (consistent with existing `AgentFileService.WriteAsync`).
|
||
- Per-file exceptions are caught and logged; the seeder continues with the next file. The method itself does not throw for individual file failures.
|
||
|
||
### `Program.cs` wiring
|
||
|
||
After `AgentFileService` registration and before `app.Run()`:
|
||
|
||
```csharp
|
||
var bundleDir = Path.Combine(AppContext.BaseDirectory, "DefaultAgents");
|
||
var seeder = new DefaultAgentSeeder(bundleDir, agentsDir);
|
||
await seeder.SeedMissingAsync();
|
||
builder.Services.AddSingleton(seeder);
|
||
```
|
||
|
||
The seeder is also registered as a singleton so the hub can invoke it for the restore flow.
|
||
|
||
### `WorkerHub.RestoreDefaultAgents`
|
||
|
||
Location: add method to existing `src/ClaudeDo.Worker/Hub/WorkerHub.cs`.
|
||
|
||
Signature: `public async Task<SeedResult> RestoreDefaultAgents()`
|
||
|
||
Behavior:
|
||
- Calls `DefaultAgentSeeder.SeedMissingAsync()`.
|
||
- Returns the `SeedResult` to the caller.
|
||
- No separate broadcast — the UI will call `GetAgents` after the restore returns, reusing the existing refresh path.
|
||
|
||
### UI — Settings Modal
|
||
|
||
Location: `src/ClaudeDo.Ui/Views/Modals/SettingsModalView.axaml` + `SettingsModalViewModel`.
|
||
|
||
Add a "Restore default agents" button to the modal. On click:
|
||
1. Disable the button, show a spinner label.
|
||
2. Call `WorkerClient.RestoreDefaultAgentsAsync()`.
|
||
3. Show a brief inline confirmation: `"Restored {Copied} agent(s)"` or `"All defaults already present"`.
|
||
4. Trigger the existing agent list refresh so the new files appear immediately in the rest of the UI.
|
||
|
||
### `WorkerClient` method
|
||
|
||
Add `Task<SeedResult> RestoreDefaultAgentsAsync(CancellationToken ct = default)` to `WorkerClient` — thin wrapper that invokes the hub method.
|
||
|
||
## Data Flow
|
||
|
||
**Startup:**
|
||
```
|
||
Worker starts → DefaultAgentSeeder.SeedMissingAsync()
|
||
→ copies missing files into ~/.todo-app/agents/
|
||
AgentFileService.ScanAsync() (on first GetAgents call) → sees the seeded files
|
||
```
|
||
|
||
**User restores:**
|
||
```
|
||
Settings modal button click
|
||
→ WorkerClient.RestoreDefaultAgentsAsync()
|
||
→ WorkerHub.RestoreDefaultAgents()
|
||
→ DefaultAgentSeeder.SeedMissingAsync()
|
||
→ returns SeedResult(copied, skipped)
|
||
UI shows confirmation, triggers GetAgents refresh
|
||
```
|
||
|
||
## Error Handling
|
||
|
||
| Failure | Behavior |
|
||
|---|---|
|
||
| Missing `DefaultAgents/` bundle dir | Log warning, return `(0, 0)`. Startup proceeds. |
|
||
| Individual file copy failure (disk, permissions) | Catch per-file, log, continue with the remaining files. |
|
||
| Corrupt bundled markdown (no valid frontmatter) | Copied anyway — the `AgentFileService` frontmatter parser already falls back to filename-as-name. |
|
||
| Startup seeder exception (unexpected) | Log as warning, do not crash the Worker. Agents can still be restored via the button. |
|
||
| Hub `RestoreDefaultAgents` exception | Propagate to client as SignalR error; UI shows a generic "Restore failed" message. |
|
||
|
||
## Testing
|
||
|
||
**Unit:** `tests/ClaudeDo.Worker.Tests/Services/DefaultAgentSeederTests.cs`
|
||
|
||
- Seeds all files when target dir is empty.
|
||
- Skips files that already exist.
|
||
- Preserves existing user-modified files (file mtime / content unchanged).
|
||
- Returns accurate `SeedResult` counts.
|
||
- Handles missing bundle dir gracefully (returns `(0, 0)`, no throw).
|
||
- Creates target dir if it doesn't exist.
|
||
|
||
**Integration:** extend `tests/ClaudeDo.Worker.Tests/Hub/AgentSettingsHubTests.cs`
|
||
|
||
- `RestoreDefaultAgents` invokes the seeder and returns the count.
|
||
|
||
**No UI tests.** The project has no UI test harness; settings modal behavior is exercised manually.
|
||
|
||
## Build / Packaging
|
||
|
||
`src/ClaudeDo.Worker/ClaudeDo.Worker.csproj` gains:
|
||
|
||
```xml
|
||
<ItemGroup>
|
||
<Content Include="DefaultAgents\*.md">
|
||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||
</Content>
|
||
</ItemGroup>
|
||
```
|
||
|
||
No new NuGet dependencies.
|
||
|
||
## Out of Scope
|
||
|
||
- Editing bundled agents in-place (user edits their copy under `~/.todo-app/agents/`; bundle is read-only by convention).
|
||
- Versioning / updating user copies when the bundled version changes. If a bundled agent is improved in a later release, the user's copy is not overwritten. A future release may add a "diff / reset to bundled" flow, but not now.
|
||
- Packaging as embedded resources. Content files copied to output are simpler, inspectable on disk, and consistent with the file-based agent model.
|