Skip to content

Subagents#35

Merged
themartto merged 9 commits into
devfrom
subagents
Jun 11, 2026
Merged

Subagents#35
themartto merged 9 commits into
devfrom
subagents

Conversation

@themartto

@themartto themartto commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

New Features

  • Introduced Subagents: Create isolated agent profiles in ~/.openheim/agents/{name}.md files with optional TOML frontmatter configuration (model, provider, tool allowlist, max iterations). Orchestrator automatically gains a delegate_task tool to delegate tasks to configured subagents. Subagents execute in sandboxed isolation and return only their final answer.

Documentation

  • Added comprehensive documentation on creating and using subagents.

@themartto

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces subagent delegation: independent configured agents that receive isolated task execution via a new delegate_task tool. Subagent profiles are discovered from Markdown files with optional TOML frontmatter, tool execution is restricted via allowlisting, and final answers are returned to the parent orchestrator. Integration wires the delegation tool into agent initialization.

Changes

Subagent Delegation

Layer / File(s) Summary
Subagent Profile Loading and Schema
src/subagents/mod.rs, src/lib.rs
AgentProfile struct and SubagentLoader read and parse ~/.openheim/agents/*.md files with optional +++-delimited TOML frontmatter. Metadata fields (model, provider, tools, max_iterations) override defaults; Markdown body becomes system prompt. Malformed profiles are skipped with warnings. Tests verify frontmatter parsing, missing fields, unterminated blocks, and malformed TOML.
Scoped Tool Executor (Allowlist Filter)
src/tools/scoped_executor.rs
ScopedExecutor wraps any ToolExecutor and enforces a tool allowlist by filtering list_tools output and returning descriptive "not available" messages for disallowed execute calls. Tests confirm filtering behavior and allowlist enforcement.
Delegation Tool Implementation
src/tools/delegate.rs
DelegateTool exposes the delegate_task function schema with an enum of available profile names. Execution resolves per-profile config/LLM overrides, constructs an isolated agent with tool allowlisting inside the parent's sandbox, runs a fresh agent loop with task-only first message, and returns only the final answer plus optional iteration-limit notice. Tests verify schema, unknown-agent handling, isolated execution, iteration limits, and conditional enablement via with_delegation.
Integration into AgentState and Exports
src/acp/mod.rs, src/tools/mod.rs
AgentState::new loads subagent profiles and wraps the base executor with with_delegation to conditionally add the delegate_task tool. Module exports expose DelegateTool, with_delegation, and ScopedExecutor via public re-exports.
Documentation and Changelog
CHANGELOG.md, docs/SUMMARY.md, docs/architecture.md, docs/subagents.md
Changelog entry, architecture module map, table-of-contents update, and comprehensive guide covering subagent concepts, profile file format, TOML fields, execution flow (isolation, tool restrictions, sandbox boundary), and working examples.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • weirdstuff-dev/openheim#33: delegate_task and subagent delegation wire into the tool-executor construction using work_dir and allow_shell set up in PR #33, sharing the same sandboxing infrastructure.

Poem

🐰 Delegate the burden, brave orchestrator dear,
A subagent whispers facts so crystal clear,
Within a sandbox, allowlist held tight,
Markdown profiles guide each isolated flight,
The parent sleeps soundly—only answers appear!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Subagents' is generic and vague, lacking specificity about the actual changes; it does not convey meaningful information about the implementation details or scope. Use a more descriptive title that clarifies the primary change, such as 'Add subagent delegation with Markdown profile loading' or 'Implement isolated subagent execution via profiles'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/subagents.md (1)

20-25: 💤 Low value

Optional: Add language specifiers to fenced code blocks for linter compliance.

The markdownlint tool flags fenced code blocks without language specifiers. Consider adding text or plaintext to the directory tree block (line 20) and explicitly marking the markdown example (line 105) with markdown to satisfy the linter while keeping the documentation clear.

📝 Suggested additions

For the directory tree (line 20):

-```
+```text
 ~/.openheim/agents/

For the markdown example (line 105):

-```markdown
+````markdown
 +++
 description = "Verifies a specific factual claim..."
 ...
-```
+````

Note: Use `````markdown` to properly escape the nested markdown code fence.

Also applies to: 105-113

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/subagents.md` around lines 20 - 25, Add language specifiers to the two
fenced code blocks: the directory-tree block that contains "~/.openheim/agents/"
and the nested markdown example that begins with "+++\ndescription = \"Verifies
a specific factual claim...\"". Change the top directory fence to something like
```text and mark the nested example with ```markdown (use a five-backtick fence
if needed to escape the inner triple backticks) so the markdown linter no longer
flags them.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/subagents/mod.rs`:
- Around line 97-105: The code currently uses std::fs::read_to_string(&path)?
which lets I/O errors abort load() while only parse_profile errors are caught;
change the per-file read to handle Err by logging a warning and continuing so
I/O failures don't stop loading other profiles. Specifically, wrap the
read_to_string call in a match or if let (e.g., match
std::fs::read_to_string(&path) { Ok(content) => { match parse_profile(name,
&content) { Ok(profile) => profiles.push(profile), Err(e) => tracing::warn!(file
= %path.display(), error = %e, "Skipping invalid subagent profile"), } }, Err(e)
=> tracing::warn!(file = %path.display(), error = %e, "Skipping unreadable
subagent profile"), }), keeping parse_profile handling as-is and leaving any
top-level directory iteration errors to propagate.

---

Nitpick comments:
In `@docs/subagents.md`:
- Around line 20-25: Add language specifiers to the two fenced code blocks: the
directory-tree block that contains "~/.openheim/agents/" and the nested markdown
example that begins with "+++\ndescription = \"Verifies a specific factual
claim...\"". Change the top directory fence to something like ```text and mark
the nested example with ```markdown (use a five-backtick fence if needed to
escape the inner triple backticks) so the markdown linter no longer flags them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca0c8b8e-e8dd-4d17-9cac-e4548f9ea597

📥 Commits

Reviewing files that changed from the base of the PR and between 73a43f9 and 61802b3.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • docs/SUMMARY.md
  • docs/architecture.md
  • docs/subagents.md
  • src/acp/mod.rs
  • src/lib.rs
  • src/subagents/mod.rs
  • src/tools/delegate.rs
  • src/tools/mod.rs
  • src/tools/scoped_executor.rs

Comment thread src/subagents/mod.rs Outdated
@themartto themartto marked this pull request as ready for review June 11, 2026 06:34
@themartto themartto merged commit fbb5832 into dev Jun 11, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant