Skip to content

Commit 0f433d8

Browse files
Merge pull request #25 from HarnessLab/update_17_4
Implemented the next missing parity slice around agent configurations.
2 parents fabbda5 + 02674ba commit 0f433d8

14 files changed

Lines changed: 721 additions & 17 deletions

‎PARITY_CHECKLIST.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ Done:
114114
- [x] Query-engine runtime context-reduction summaries
115115
- [x] Query-engine runtime lineage summaries
116116
- [x] Query-engine runtime resumed-child orchestration summaries
117+
- [x] Filesystem-backed custom agent discovery from `~/.claude/agents` and `./.claude/agents`
118+
- [x] Active agent override precedence across built-in, user, and project agent definitions
119+
- [x] Custom agent resolution in the `Agent` tool with model, tool-filter, and initial-prompt support
117120

118121
Missing:
119122

@@ -141,6 +144,7 @@ Done:
141144
- [x] `agent-context` command
142145
- [x] `agent-context-raw` command
143146
- [x] `token-budget` command
147+
- [x] `agents` command
144148
- [x] Local background session mode
145149
- [x] Local background session listing (`agent-ps`)
146150
- [x] Local background session logs (`agent-logs`)
@@ -195,6 +199,7 @@ Done:
195199
- [x] Local planning guidance section in the Python system prompt
196200
- [x] Local task guidance section in the Python system prompt
197201
- [x] Local LSP guidance section in the Python system prompt
202+
- [x] Local agent-configuration guidance section in the Python system prompt
198203

199204
- [x] Product metadata/branding from `constants/product.ts` — ported to `src/prompt_constants.py`
200205
- [x] API limits constants from `constants/apiLimits.ts` — ported to `src/prompt_constants.py`
@@ -312,7 +317,7 @@ Done (53 slash command names in 37 specs):
312317
Missing npm slash commands (from `src/commands/` — 80+ commands total):
313318

314319
- [x] `/add-dir` — Add a new working directory
315-
- [ ] `/agents` — Manage agent configurations
320+
- [x] `/agents` — Inspect local agent configurations and show active definitions
316321
- [x] `/branch` — Create a branch of the current conversation
317322
- [ ] `/bridge` — Connect for remote-control sessions
318323
- [ ] `/btw` — Quick side question without interrupting main conversation
@@ -361,6 +366,7 @@ Missing npm slash commands (from `src/commands/` — 80+ commands total):
361366
- [ ] Feature-gated: `/buddy`, `/fork`, `/peers`, `/proactive`, `/torch`, `/workflows` (full), etc.
362367
- [ ] Internal: `/backfill-sessions`, `/break-cache`, `/bughunter`, `/commit-push-pr`, `/init-verifiers`, `/mock-limits`, `/version`, `/ultraplan`, `/autofix-pr`, etc.
363368
- [x] `/commit` — Create a git commit (prompt-type with injected git context)
369+
- [ ] Full `/agents` parity for create/edit/delete flows and multi-source management UI
364370

365371
## 6. Built-in Tools
366372

‎README.md‎

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
| 🆕 | **Plugin Runtime** | Full manifest-based plugin system — hooks, tool aliases, virtual tools, tool blocking |
3232
| 🆕 | **Nested Agent Delegation** | Delegate subtasks to child agents with dependency-aware topological batching |
3333
| 🆕 | **Agent Manager** | Lineage tracking, group membership, batch summaries for nested agents |
34+
| 🆕 | **Custom Agent Profiles** | Discover local markdown-defined agents from `~/.claude/agents` and `./.claude/agents` and use them through the `Agent` tool |
3435
| 🆕 | **Cost Tracking & Budgets** | Token budgets, cost budgets, tool-call limits, model-call limits, session-turn limits |
3536
| 🆕 | **Structured Output** | JSON schema response mode with `--response-schema-file` |
3637
| 🆕 | **Context Compaction** | Auto-snip, auto-compact, and reactive compaction on prompt-too-long errors |
@@ -87,6 +88,7 @@ Built on the public porting workspace from [instructkr/claw-code](https://github
8788
| 🧰 **Core Tools** | File read / write / edit, glob search, grep search, shell execution |
8889
| 🔌 **Plugin Runtime** | Manifest-based plugins with hooks, aliases, virtual tools, and tool blocking |
8990
| 🪆 **Nested Delegation** | Delegate subtasks to child agents with dependency-aware topological batching |
91+
| 🧩 **Custom Agents** | Load local agent profiles from `~/.claude/agents` and `./.claude/agents`, inspect them via `/agents`, and delegate with `subagent_type` |
9092
| 📡 **Streaming** | Token-by-token streaming output with `--stream` |
9193
| 💬 **Slash Commands** | Local commands for context, config, account, search, MCP, remote, tasks, plan, hooks, and model control |
9294
| 🌐 **Remote Runtime** | Manifest-backed remote profiles with local `remote-mode`, `ssh-mode`, `teleport-mode`, and connect/disconnect state |
@@ -134,7 +136,7 @@ Built on the public porting workspace from [instructkr/claw-code](https://github
134136
- [x] Ollama, LiteLLM Proxy, and OpenRouter backends
135137
- [x] Core tools: `list_dir`, `read_file`, `write_file`, `edit_file`, `glob_search`, `grep_search`, `bash`
136138
- [x] Context building and `/context`-style usage reporting
137-
- [x] Slash commands: `/help`, `/context`, `/context-raw`, `/prompt`, `/permissions`, `/model`, `/tools`, `/memory`, `/status`, `/clear`
139+
- [x] Slash commands: `/help`, `/context`, `/context-raw`, `/token-budget`, `/prompt`, `/permissions`, `/model`, `/tools`, `/agents`, `/memory`, `/status`, `/clear`
138140
- [x] Session persistence and `agent-resume` flow
139141
- [x] Permission system (read-only, write, shell, unsafe tiers)
140142
- [x] Streaming token-by-token assistant output
@@ -149,6 +151,7 @@ Built on the public porting workspace from [instructkr/claw-code](https://github
149151
- [x] File history journaling with snapshot IDs and replay summaries
150152
- [x] Nested agent delegation with dependency-aware topological batching
151153
- [x] Agent manager with lineage tracking and group membership
154+
- [x] Filesystem-backed custom agent profiles with built-in/user/project precedence
152155
- [x] Local daemon-style background command family
153156
- [x] Local background session workflows: `agent-bg`, `agent-ps`, `agent-logs`, `agent-attach`, `agent-kill`
154157
- [x] Local remote runtime: manifest discovery, profile listing, connect/disconnect persistence, and CLI/slash flows
@@ -205,6 +208,7 @@ claw-code/
205208
│ ├── agent_runtime.py # Core agent loop (LocalCodingAgent)
206209
│ ├── agent_tools.py # Tool definitions & execution engine
207210
│ ├── agent_prompting.py # System prompt assembly
211+
│ ├── agent_registry.py # Built-in + filesystem-backed custom agent discovery
208212
│ ├── agent_context.py # Context building & CLAUDE.md discovery
209213
│ ├── agent_context_usage.py # Context usage estimation & reporting
210214
│ ├── agent_session.py # Session state management
@@ -446,6 +450,7 @@ python3 -m src.main agent \
446450
| `agent-context` | Show estimated context usage |
447451
| `agent-context-raw` | Show the raw context snapshot |
448452
| `token-budget` | Show prompt-window budget, reserves, and soft/hard input limits |
453+
| `agents [agent_type]` | List active local agent definitions or show one agent profile |
449454
| `agent-resume <id> <prompt>` | Resume a saved session |
450455

451456
### Runtime Utility Commands
@@ -545,6 +550,7 @@ These are handled **locally** before the model loop:
545550
| `/permissions` | — | Show active tool permission mode |
546551
| `/model` | — | Show or update the active model |
547552
| `/tools` | — | List registered tools with permission status |
553+
| `/agents` | — | List active local agent definitions or show one profile |
548554
| `/memory` | — | Show loaded CLAUDE.md memory bundle |
549555
| `/status` | `/session` | Show runtime/session status summary |
550556
| `/clear` | — | Clear ephemeral runtime state |
@@ -554,9 +560,42 @@ python3 -m src.main agent "/help"
554560
python3 -m src.main agent "/context" --cwd .
555561
python3 -m src.main agent "/token-budget" --cwd .
556562
python3 -m src.main agent "/tools" --cwd .
563+
python3 -m src.main agent "/agents" --cwd .
557564
python3 -m src.main agent "/status" --cwd .
558565
```
559566

567+
### Custom Agent Definitions
568+
569+
Custom agent profiles can live in either of these directories:
570+
571+
- `./.claude/agents/*.md`
572+
- `~/.claude/agents/*.md`
573+
574+
Project agents override user agents, and user agents override built-ins when the `agent_type` matches.
575+
576+
Example agent file:
577+
578+
```md
579+
---
580+
name: reviewer
581+
description: "Review implementation changes carefully."
582+
tools: read_file, grep_search
583+
model: Qwen/Qwen3-Coder-30B-A3B-Instruct
584+
initialPrompt: Start by identifying the highest-risk files.
585+
---
586+
587+
Inspect code changes and summarize correctness risks, regressions, and missing tests.
588+
```
589+
590+
Inspect the loaded profiles:
591+
592+
```bash
593+
python3 -m src.main agents --cwd .
594+
python3 -m src.main agents reviewer --cwd .
595+
python3 -m src.main agent "/agents" --cwd .
596+
python3 -m src.main agent "/agents show reviewer" --cwd .
597+
```
598+
560599
### Utility Commands
561600

562601
```bash

‎TESTING_GUIDE.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,24 @@ EOF
580580
mkdir -p ./test_cases_tasks
581581
```
582582

583+
### 4.9 Custom agent definitions
584+
585+
```bash
586+
mkdir -p ./test_cases_agents/.claude/agents
587+
588+
cat > ./test_cases_agents/.claude/agents/reviewer.md <<'EOF'
589+
---
590+
name: reviewer
591+
description: "Review implementation changes carefully."
592+
tools: read_file, grep_search
593+
model: Qwen/Qwen3-Coder-30B-A3B-Instruct
594+
initialPrompt: Start by identifying the highest-risk files.
595+
---
596+
597+
Inspect code changes and summarize correctness risks, regressions, and missing tests.
598+
EOF
599+
```
600+
583601
## 5. Slash Command Matrix
584602

585603
Slash commands are handled locally before the model loop.
@@ -601,6 +619,8 @@ python3 -m src.main agent "/permissions" --cwd ./test_cases
601619
python3 -m src.main agent "/model" --cwd ./test_cases
602620
python3 -m src.main agent "/model demo-model" --cwd ./test_cases
603621
python3 -m src.main agent "/tools" --cwd ./test_cases
622+
python3 -m src.main agent "/agents" --cwd ./test_cases_agents
623+
python3 -m src.main agent "/agents show reviewer" --cwd ./test_cases_agents
604624
python3 -m src.main agent "/memory" --cwd ./test_cases
605625
python3 -m src.main agent "/status" --cwd ./test_cases
606626
python3 -m src.main agent "/session" --cwd ./test_cases
@@ -678,6 +698,8 @@ python3 -m src.main agent-prompt --cwd ./test_cases
678698
python3 -m src.main agent-context --cwd ./test_cases
679699
python3 -m src.main agent-context-raw --cwd ./test_cases
680700
python3 -m src.main token-budget --cwd ./test_cases
701+
python3 -m src.main agents --cwd ./test_cases_agents
702+
python3 -m src.main agents reviewer --cwd ./test_cases_agents
681703
```
682704

683705
### 6.2 Extra working directories and `CLAUDE.md` toggle

‎src/__init__.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
set_system_prompt_injection,
1212
)
1313
from .agent_manager import AgentManager
14+
from .agent_registry import (
15+
AgentLoadError,
16+
AgentRegistrySnapshot,
17+
find_agent_definition,
18+
load_agent_registry,
19+
render_agent_detail,
20+
render_agents_report,
21+
)
1422
from .agent_runtime import LocalCodingAgent
1523
from .agent_session import AgentMessage, AgentSessionState
1624
from .agent_tools import build_tool_context, default_tool_registry, execute_tool
@@ -42,7 +50,9 @@
4250
__all__ = [
4351
'AgentContextSnapshot',
4452
'AgentManager',
53+
'AgentLoadError',
4554
'AgentPermissions',
55+
'AgentRegistrySnapshot',
4656
'AgentRunResult',
4757
'AgentRuntimeConfig',
4858
'AccountProfile',
@@ -114,10 +124,14 @@
114124
'describe_token_counter',
115125
'estimate_chat_overhead',
116126
'execute_tool',
127+
'find_agent_definition',
117128
'format_token_budget',
118129
'get_system_context',
119130
'get_user_context',
131+
'load_agent_registry',
120132
'load_session',
133+
'render_agent_detail',
134+
'render_agents_report',
121135
'run_parity_audit',
122136
'save_session',
123137
'set_system_prompt_injection',

‎src/agent_prompting.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from .agent_context import build_context_snapshot
77
from .agent_tools import AgentTool
88
from .agent_types import AgentRuntimeConfig, ModelConfig
9+
from .builtin_agents import AgentDefinition, format_agent_listing
910

1011
SYSTEM_PROMPT_DYNAMIC_BOUNDARY = '__SYSTEM_PROMPT_DYNAMIC_BOUNDARY__'
1112

@@ -76,6 +77,7 @@ def build_system_prompt_parts(
7677
prompt_context: PromptContext,
7778
runtime_config: AgentRuntimeConfig,
7879
tools: dict[str, AgentTool],
80+
available_agents: tuple[AgentDefinition, ...] = (),
7981
custom_system_prompt: str | None = None,
8082
append_system_prompt: str | None = None,
8183
override_system_prompt: str | None = None,
@@ -90,6 +92,7 @@ def build_system_prompt_parts(
9092
get_doing_tasks_section(),
9193
get_actions_section(),
9294
get_using_your_tools_section(enabled_tool_names),
95+
get_agent_guidance_section(enabled_tool_names, available_agents),
9396
get_plugin_guidance_section(prompt_context),
9497
get_mcp_guidance_section(prompt_context),
9598
get_remote_guidance_section(prompt_context),
@@ -204,6 +207,26 @@ def get_tone_and_style_section() -> str:
204207
return '\n'.join(['# Tone and style', *prepend_bullets(items)])
205208

206209

210+
def get_agent_guidance_section(
211+
enabled_tool_names: set[str],
212+
available_agents: tuple[AgentDefinition, ...],
213+
) -> str:
214+
if 'Agent' not in enabled_tool_names and 'delegate_agent' not in enabled_tool_names:
215+
return ''
216+
items: list[str] = [
217+
'Use the Agent tool when a bounded subtask can be delegated to a specialized agent profile.',
218+
'Pick a specific subagent_type when one of the available agent profiles clearly fits the task.',
219+
]
220+
if not available_agents:
221+
return '\n'.join(['# Agents', *prepend_bullets(items)])
222+
rendered_agents = list(format_agent_listing(available_agents[:20]).splitlines())
223+
items.append('Available agent types:')
224+
items.append(rendered_agents)
225+
if len(available_agents) > 20:
226+
items.append(f'... plus {len(available_agents) - 20} more agent definitions.')
227+
return '\n'.join(['# Agents', *prepend_bullets(items)])
228+
229+
207230
def get_plugin_guidance_section(prompt_context: PromptContext) -> str:
208231
plugin_cache = prompt_context.user_context.get('pluginCache')
209232
plugin_runtime = prompt_context.user_context.get('pluginRuntime')

0 commit comments

Comments
 (0)