Continuous task execution loop that keeps the agent running until goals are completed via state file monitoring and optional completion promises.
This plugin enables persistent multi-step workflows where tasks span multiple sessions or require iterative refinement. It works similarly to Claude Code's ralph-wiggum-loop but is designed specifically for Hermes Agent's plugin architecture.
- State Persistence: Tracks task progress via
.hermes-loop-state.json - Completion Promises: Define custom termination conditions (file exists, content match, task count)
- Automatic Resumption: Continues from where it left off across sessions
- Blocking Detection: Stops loop when critical issues prevent progress
- Command-style Tools: Intuitive tool names that work like slash commands!
| Command | Description |
|---|---|
init_loop |
Initialize a new loop state |
loop_status |
Check current loop status |
complete_task |
Mark next task as completed |
set_completion_promise |
Define custom termination condition |
add_blocking_issue |
Add blocker that stops loop |
reset_loop |
Reset completed count |
The plugin is available on PyPI and can be installed with hermes cli directly:
hermes plugins install AshMartian/hermes-loop-pluginThe plugin is available for direct installation from our GitHub repository:
pip install git+https://github.com/AshMartian/hermes-loop-plugin.git@v1.0.0After installation, the plugin will be automatically discovered when you start Hermes Agent. No additional configuration required!
hermes plugins update hermes-loopCheck that the plugin is installed correctly:
# Check if package is installed
pip show hermes-loop-plugin
# Or verify plugin location (if using local development)
ls ~/.hermes/plugins/hermes-loop/You should see:
plugin.yaml- Plugin manifest__init__.py- Registration and hooksschemas.py- Tool schemas (what LLM sees)tools.py- Tool handlers (actual implementation)SKILL.md- Comprehensive usage documentation
For development or custom builds, install from source:
# Clone the repository
git clone https://github.com/AshMartian/hermes-loop-plugin.git
cd hermes-loop-plugin
# Install in editable mode for development
pip install -e .
# Or build and install manually
python -m build
pip install dist/hermes_loop_plugin-*.whlIf you need to install the plugin manually:
- Download the package from GitHub Releases or clone the repository
- Install using pip:
pip install dist/hermes_loop_plugin-X.X.X.tar.gz - Restart Hermes Agent to load the plugin
Track progress: Check our GitHub Releases for updates when we publish to PyPI.
Create a .hermes-loop-state.json file in your working directory:
from pathlib import Path
import json
state_file = Path.cwd() / '.hermes-loop-state.json'
with open(state_file, 'w') as f:
json.dump({
"total_tasks": 5,
"completed_tasks": 0,
"blocking_issues": [],
"completion_promise": {
"promise_type": "file_exists",
"condition": "src/features/new-feature.tsx"
}
}, f)Use the tool to define custom termination conditions:
set_completion_promise(
promise_type="content_match",
condition="tests/feature.test.ts",
expected_value="describe('Feature'"
)Run your tasks via subagents or direct implementation, updating the state after each completion:
from pathlib import Path
# Task 1
delegate_task(goal="Implement feature step 1")
# Update state
state_file = Path.cwd() / '.hermes-loop-state.json'
with open(state_file) as f:
state = json.load(f)
state['completed_tasks'] += 1
with open(state_file, 'w') as f:
json.dump(state, f, indent=2)
# Repeat for remaining tasks...The plugin's stop hook monitors the state file and determines whether to continue or stop execution based on:
- Task completion count vs total
- Completion promise fulfillment status
- Blocking issues present
{
"total_tasks": 5,
"completed_tasks": 2,
"blocking_issues": [],
"completion_promise": {
"promise_type": "file_exists",
"condition": "src/features/new-feature.tsx",
"expected_value": null,
"fulfilled": false
},
"created_at": "2026-03-17T09:38:00Z"
}Fields:
total_tasks: Total number of tasks in the loopcompleted_tasks: Number completed so farblocking_issues: List of issues that should stop the loopcompletion_promise: Optional custom termination conditioncreated_at: Timestamp when loop started
Stop after completing a specific number of tasks:
{
"promise_type": "task_count",
"condition": null,
"expected_value": "3"
}Use case: Continue until I've tried at least 3 debugging approaches
Stop when a specific file is created:
{
"promise_type": "file_exists",
"condition": "src/features/new-feature.tsx"
}Use case: Keep implementing until the feature file exists
Stop when a file contains specific content:
{
"promise_type": "content_match",
"condition": "src/utils/validation.ts",
"expected_value": "export function validateInput("
}Use case: Continue until validation logic is implemented
Define your own condition via tool implementation:
{
"promise_type": "custom",
"condition": "my_custom_condition"
}Use case: Complex conditions requiring custom logic (extend the plugin)
Check current loop state and whether continuation is needed.
Parameters: None
Returns: JSON with:
has_remaining_tasks: true if tasks remaintasks_completed: number completed so fartotal_tasks: total tasks in loopcompletion_reached: true if all conditions metblocking_issues: list of blocking issues (if any)
Set custom termination condition for the loop.
Parameters:
promise_type: Type of condition (task_count,file_exists,content_match,custom)condition: Specific condition to check (e.g., file path, content pattern)expected_value: Expected value for condition (optional)
Use the loop to keep subagents running across sessions:
# Initialize state
state_file = Path.cwd() / '.hermes-loop-state.json'
with open(state_file, 'w') as f:
json.dump({"total_tasks": 5, "completed_tasks": 0}, f)
# Dispatch tasks via subagents (loop continues automatically)
delegate_task(goal="Implement Task 1")
mark_task_complete(state_file)
delegate_task(goal="Implement Task 2")
mark_task_complete(state_file)
# Loop will continue until all 5 tasks completeUse loop for plans requiring iteration:
plan = read_file("docs/plans/feature-plan.md")
tasks = parse_plan_tasks(plan)
state_file = Path.cwd() / '.hermes-loop-state.json'
with open(state_file, 'w') as f:
json.dump({"total_tasks": len(tasks), "completed_tasks": 0}, f)
# Execute tasks (loop continues automatically across sessions)Loop works seamlessly with debugging workflows:
state_file = Path.cwd() / '.hermes-loop-state.json'
with open(state_file, 'w') as f:
json.dump({
"total_tasks": 10,
"completed_tasks": 0,
"blocking_issues": [],
"completion_promise": {
"promise_type": "content_match",
"condition": "src/app.tsx",
"expected_value": "// Bug fixed"
}
}, f)
# Follow systematic-debugging process:
# 1. Identify symptoms
# 2. Form hypothesis
# 3. Test hypothesis
# 4. Update state if test fails
# 5. Loop continues until bug fixed or max iterationsstatus = loop_status()
print(f"Remaining: {status['has_remaining_tasks']}")
print(f"Completed: {status['tasks_completed']}/{status['total_tasks']}")cat .hermes-loop-state.jsonIf loop is stuck, remove or rename the state file:
mv .hermes-loop-state.json .hermes-loop-state.json.backup
# Loop will detect missing state and stopTo add new promise types or customize behavior:
- Update
schemas.py- Add new enum values to tool parameters - Modify
tools.py- Implement handler logic for new features - Edit
__init__.py- Update_on_stop_hook()to evaluate new conditions
Example: Add HTTP status promise type:
# In __init__.py, add to _on_stop_hook:
elif promise_type == 'http_status':
import requests
url = completion_promise.get('condition', '')
response = requests.get(url)
expected_status = int(completion_promise.get('expected_value', 200))
promise_fulfilled = (response.status_code == expected_status)Ensure state files are not world-readable if they contain sensitive data:
chmod 600 .hermes-loop-state.jsonPrevent path traversal attacks by validating promise conditions:
def validate_promise_condition(condition: str) -> bool:
"""Prevent path traversal attacks."""
if '..' in condition or condition.startswith('/'):
return False # Reject absolute paths and path traversal
return True| Feature | Hermes Loop | Ralph Wiggum Loop |
|---|---|---|
| Platform | Hermes Agent | Claude Code |
| State file format | JSON | JSON (similar) |
| Promise types | 4 built-in (task_count, file_exists, content_match, custom) | Similar |
| Hook integration | post_tool_call, on_session_start, stop_hook | Similar pattern |
| Tool interface | Explicit tools (loop_status, set_completion_promise) | Implicit via commands |
| Installation | ~/.hermes/plugins/ | .claude-plugin/ |
The Hermes Loop plugin follows the same conceptual model as ralph-wiggum but is adapted for Hermes Agent's tool-based architecture.
MIT License - see LICENSE file in repository root
Repository: https://github.com/AshMartian/hermes-loop-plugin
Contributions welcome! To contribute:
- Fork the repository
- Create a feature branch
- Make your changes
- Update documentation
- Submit a pull request
hermes-loop/
├── plugin.yaml # Plugin manifest
├── __init__.py # Registration and hooks
├── schemas.py # Tool schemas (LLM-facing)
├── tools.py # Tool handlers (implementation)
├── SKILL.md # Usage documentation
└── README.md # This file
- Cleanup and bug fixes
- Initial release with core loop functionality
- Support for task_count, file_exists, content_match promise types
- Automatic state persistence and resumption
- Stop hook integration for loop continuation control