Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2a60947
feat(autoresearch): vendor AutoResearchClaw skills and prompts
Fede654 Apr 22, 2026
10d90ca
feat(autoresearch): implement ResearchSupervisor and program.md template
Fede654 Apr 22, 2026
2fb328c
test(autoresearch): add integration tests for ResearchSupervisor
Fede654 Apr 22, 2026
ae469a7
feat(autoresearch): apply Karpathy guidelines to experiment loop
Fede654 Apr 22, 2026
f65032b
feat(research): generalize supervisor loop to any measurable task type
Fede654 Apr 22, 2026
a34b5af
feat(research): incorporate Autogenesis AOOR loop and HeartbeatMemory…
Fede654 Apr 22, 2026
cd24d2e
fix(research): address audit findings — rollback, observe, reflect gu…
Fede654 Apr 22, 2026
682d844
feat(research): wire ResearchSupervisor as tool + researcher profile …
Fede654 Apr 22, 2026
43c0b78
fix(autoresearch): apply Codex ia-bridge review findings
Fede654 Apr 22, 2026
e0a2286
fix(autoresearch): apply analysis fixes from full cycle validation
Fede654 Apr 22, 2026
57b4f20
fix(autoresearch): correct sandbox messaging and add partial recovery
Fede654 Apr 22, 2026
4a98b12
fix(autoresearch): add Tools Available + anti-XML guard to task briefs
Fede654 Apr 22, 2026
7c5819f
fix(autoresearch): include terminal in research/search default toolsets
Fede654 Apr 22, 2026
a108d29
feat(autoresearch): add research_job tool for detached long-running l…
Fede654 Apr 22, 2026
5edcba2
feat(autoresearch): add research_job orchestration for long-running l…
Fede654 Apr 22, 2026
703b073
perf(autoresearch): implement 5 optimization fixes from log analysis
Fede654 Apr 22, 2026
88be1b4
fix(autoresearch): restore LLM judge on every iteration
Fede654 Apr 23, 2026
a7f8ddb
docs(autoresearch): update research docs with latest architecture and…
Fede654 Apr 23, 2026
1238833
fix(autoresearch): address nicoechaniz PR#1 review — hardcoded paths …
Fede654 Apr 24, 2026
f529d98
fix(execute_code): HRM-55 revert DEFAULT_TIMEOUT 900→300, make RPC ti…
Fede654 Apr 24, 2026
c6a5d00
docs(research): HRM-56 document .lattice/ dependency for research_job…
Fede654 Apr 24, 2026
5a45bae
fix(autoresearch): address nicoechaniz PR#1 review — workspace fallba…
Fede654 Apr 24, 2026
e2e9ba9
docs(autoresearch): nicoechaniz PR#1 follow-ups — surface karpathy sk…
Fede654 Apr 24, 2026
92fd03d
fix(autoresearch): harden LLM judge parser against real-world responses
Fede654 Apr 24, 2026
a01fe26
refactor(researcher): drop mcp-obsidian; vault is plain Markdown + git
Fede654 Apr 25, 2026
24577eb
refactor(researcher): drop mcp-lattice; use the lattice CLI directly
Fede654 Apr 25, 2026
b0f379c
fix(researcher): default model kimi-k2.6 / kimi-coding instead of cla…
Fede654 Apr 25, 2026
924bdc9
docs(researcher): operational tool patterns + codebase layout from sw…
Fede654 Apr 25, 2026
fd07911
chore(autoresearch): drop unused prompts/autoresearch.yaml (HRM-60)
Fede654 Apr 25, 2026
c29f7ce
feat(autoresearch): inherit_profile opt-in for delegate_task workers …
Fede654 Apr 25, 2026
320ce43
feat(autoresearch): persist run lessons via EvolutionStore (HRM-59 v1)
Fede654 Apr 25, 2026
91992c3
feat(autoresearch): centralize detached-agent construction in agent/f…
Fede654 Apr 25, 2026
f3989a9
refactor(autoresearch): consolidate agent/research_*.py into agent/re…
Fede654 Apr 25, 2026
fd45416
feat(autoresearch): wire EvolutionStore.build_overlay into worker bri…
Fede654 Apr 25, 2026
2a3c4ee
feat(autoresearch): extend AIAgent.__init__ with detached-parent kwar…
Fede654 Apr 25, 2026
7561477
docs(researcher): SOUL.md adds autonomous-execution-mode override (HR…
Apr 27, 2026
f976db7
fix(autoresearch): clarify run_research dispatch in subagent contexts…
Apr 27, 2026
ffbf3de
fix(gateway/daemoncraft): run transform_tool_result hooks on syntheti…
Fede654 May 3, 2026
6439bb8
feat(gateway/daemoncraft): port CycleDetector from daemoncraft agents…
Fede654 May 3, 2026
49e1038
fix(DC-123): relay agent turns to Bot Mind panel and restore TTS on D…
Fede654 May 3, 2026
8c9a2be
test(gateway): CycleDetector + synthetic perceive hook coverage
Fede654 May 3, 2026
07101e1
feat(gateway/daemoncraft): emit mc_action_result hook for action_resu…
Fede654 May 3, 2026
d8e2988
feat(gateway/daemoncraft): emit DC-132 turn + tool metrics
Fede654 May 3, 2026
55ea2fd
fix(gateway/daemoncraft): use os.O_APPEND single-write for DC-132 met…
Fede654 May 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions HERMES_RESEARCH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# Hermes AutoResearch

## What This Is

Hermes AutoResearch is the **Karpathy inner loop** for autonomous experimentation inside Hermes. Given a research topic, it runs a baseline experiment, proposes improvements via LLM, executes them through `delegate_task`, keeps improvements and discards regressions, and records structured learnings.

The architecture is **desacoplada**: long-running research loops execute as independent OS processes with durable checkpoints, so the parent agent does not burn iteration budget or die to timeouts.

## Quick Start

### Running a Research Job (Detached)

```bash
# Create a job spec JSON
python -c '
import json
spec = {
"job_id": "my-research",
"job_dir": "/home/user/.hermes/research-jobs/my-research",
"model": "kimi-for-coding",
"provider": "kimi-coding",
"topic": "Analyze WebAssembly adoption in 2025",
"deliverable": "Ranked list of relevant papers with abstracts",
"metric_key": "completeness_score",
"metric_direction": "maximize",
"task_type": "research",
"max_iterations": 3,
}
json.dump(spec, open("/home/user/.hermes/research-jobs/my-research/job.json", "w"))
'

# Launch detached runner
source venv/bin/activate
HERMES_YOLO_MODE=1 python -m agent.research.job_runner \
/home/user/.hermes/research-jobs/my-research/job.json
```

### From Python (Synchronous)

```python
from agent.research.supervisor import ResearchSupervisor, TaskSpec
from pathlib import Path

spec = TaskSpec(
topic="Analyze WebAssembly adoption in 2025",
deliverable="Ranked list of relevant papers with abstracts",
metric_key="completeness_score",
metric_direction="maximize",
task_type="research",
)

supervisor = ResearchSupervisor(parent_agent=agent, workspace=Path("research-workspace"))
history = supervisor.run(
spec,
initial_attempt="",
run_id="run-001",
max_iterations=3,
llm=agent.llm_client,
)
```

## Architecture

```
Parent Agent / CLI
┌─────────────────────────┐
│ research/job_runner.py│ ← Detached OS process
│ (entrypoint) │
└─────────────────────────┘
┌─────────────────────────┐
│ ResearchSupervisor │ ← Karpathy loop orchestrator
│ • TaskSpec │
│ • run() │
│ • _observe() │
│ • _checkpoint() │
└─────────────────────────┘
┌─────────────────────────┐ ┌─────────────────────────┐
│ delegate_task │────▶│ Worker Subagent │
│ (per iteration) │ │ • Reads task_brief.md │
└─────────────────────────┘ │ • Writes attempt.md │
│ • Writes results.json │
│ • Reports metric │
└─────────────────────────┘
```

## Project Structure

```
agent/
├── research/job_runner.py # Detached entrypoint: builds AIAgent, calls run_research
├── research/supervisor.py # ResearchSupervisor + TaskSpec + task briefs
├── research/runner.py # ExperimentRunner + ExperimentHistory
├── research/metrics.py # UniversalMetricParser
└── subdirectory_hints.py # Progressive context discovery (cached)

tools/
├── research_tool.py # run_research() public API
└── research_job_tool.py # start_research_job, research_job_status, collect_research_job

~/.hermes/research-jobs/ # Job specs + checkpoints + logs
~/.hermes/research-workspace/ # Round artifacts (attempt.md, results.json, learnings.jsonl)
```

## The Karpathy Loop

```
Step 1: BASELINE — Worker receives task brief + attempt file, produces deliverable
Step 2: METRIC — UniversalMetricParser reads results.json / stdout
Step 3: JUDGE — LLM judge scores deliverable (if evaluation_mode="llm_judge")
Step 4: OBSERVE — Structured learning appended to learnings.jsonl
Step 5: CHECKPOINT — history.json + checkpoint.json written to disk
Step 6: OPTIMIZE — LLM proposes revised attempt based on history
Step 7: KEEP/DISCARD — If metric improved: keep, else discard; iterate
```

## Task Types

| Type | Default Toolsets | Deliverable | Attempt File |
|------|-----------------|-------------|--------------|
| `code` | terminal, file | Python code | attempt.py |
| `search` | web, terminal, file | Search results | attempt.md |
| `research` | web, terminal, file | Synthesis | attempt.md |
| `generic` | terminal, file | Any text | attempt.md |

## Worker Contract

The worker receives:
- `task_brief.md` — Full instructions including think block, rules, tools available
- `attempt.py` or `attempt.md` — Current attempt to refine
- Environment variable `HERMES_YOLO_MODE=1` to skip command approval

The worker must produce:
- `results.json` with `{"<metric_key>": <value>}`
- Final line: `METRIC: <key>=<value> STATUS: improved|regressed|neutral NOTES: <one line>`

## Checkpoints and Recovery

After every round, the supervisor writes:

```
~/.hermes/research-jobs/<job_id>/
├── checkpoint.json # {round, total_rounds, best_metric, updated_at}
├── history.json # Full results array + best reference
├── runner.log # Runner + supervisor logs
└── state.json # {status, pid, started_at}
```

External monitors can read `checkpoint.json` without polling the process.

## Decision Guide

| Situation | Action |
|-----------|--------|
| Long-running research (>5 min) | Use `research/job_runner` detached |
| Quick experiment (<2 min) | Call `run_research()` directly |
| Need baseline only | Set `llm=None` in supervisor |
| Worker times out | `DelegateSandboxResult.timed_out=True`; loop continues |
| 3 consecutive non-improving | Runner stops early (or 1 if high baseline) |
| Want to inspect history | Read `history.json` from checkpoint dir |

## Performance Optimizations

| Optimization | File | Impact |
|-------------|------|--------|
| **Lock file** | `research/job_runner.py` | Prevents duplicate restarts (~16 min saved) |
| **Provider cache** | `auxiliary_client.py` | Caches `resolve_provider_client` (~14 calls → 1) |
| **Subdirectory hints cache** | `subdirectory_hints.py` | Caches hint loads per directory |
| **Aggressive early stop** | `research/supervisor.py` | Baseline ≥0.9 → stop after 1 non-improving iter |
| **LLM judge every iter** | `research/supervisor.py` | Objective scoring on all loops |

## Anti-Patterns

- **DO NOT** run `research/job_runner` in foreground without `timeout >= 300`
- **DO NOT** poll the process with `ps` / `tail` — read `checkpoint.json` instead
- **DO NOT** launch the same job twice — the lock file prevents this
- **DO NOT** delete `.runner.lock` manually — use `kill` on the process

## Metric Reporting (Worker Contract)

Workers must print metrics in one of these formats:

```
# Hermes format (preferred)
METRIC: accuracy=0.923 STATUS: improved NOTES: Adam lr=0.001 beat SGD baseline

# Standard key: value format
accuracy: 0.923
loss: 0.112
```

The `UniversalMetricParser` also reads `results.json` (structured) or `results.csv` if present in the round directory.

## Skills

Hermes AutoResearch skills are in `skills/autoresearch/` and are loaded automatically.
Domain-specific skills (ML, chemistry, biology) are in `skills/autoresearch/domain/`.
105 changes: 105 additions & 0 deletions RESEARCH_AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Hermes AutoResearch — Worker Agent Contract

## Overview

You are a **Hermes AutoResearch worker**. You receive a goal string and a working directory from the supervisor. Your job is to run the experiment described in `task_brief.md` and report a metric in the required format.

You are NOT responsible for the loop logic (keep/discard, iteration, LLM code improvement). That is handled by the supervisor via `ResearchSupervisor`.

## Inputs

| Input | Source | Description |
|-------|--------|-------------|
| Working directory | `delegate_task` argument | Directory containing `task_brief.md` and `attempt` file |
| Goal string | `delegate_task` argument | Includes metric key and output format |
| `task_brief.md` | Read from working directory | Full instructions, think block, rules, tools available |
| `attempt.py` / `attempt.md` | Read from working directory | Current attempt to refine (iteration > 0) or baseline seed |

## Your Steps

1. **Read `task_brief.md`** — understand the experiment goal, deliverable, and metric key
2. **Read the attempt file** — see what the previous iteration produced
3. **Set up experiment files** — write refined code/synthesis to the working directory
4. **Run the experiment** — execute the code, collect results, verify metric
5. **Write `results.json`** with `{"<metric_key>": <value>}` (structured output, preferred)
6. **Print metric line** — required for fallback stdout parsing
7. **Report status** — include STATUS word in output

## Required Output Format

Your final output MUST include a metric line in one of these formats:

```
# Preferred (Hermes format)
METRIC: <key>=<value> STATUS: improved|regressed|neutral NOTES: <one line>

# Acceptable (standard)
<key>: <value>
```

Example:
```
METRIC: completeness_score=0.95 STATUS: improved NOTES: Covered WebAssembly browser support, non-browser runtimes, and language bindings
```

The metric key must match the key specified in the goal string (e.g., `completeness_score`, `accuracy`, `pass_rate`).

## Tool Format

When calling tools, use the **JSON format** provided by the system. Do NOT use XML tags like `<function_calls>`.

## Tools Available

The task brief declares available tools explicitly. Common sets:

| Task Type | Tools |
|-----------|-------|
| code | terminal, file, code_execution |
| search | web_search, browser, file, terminal |
| research | web_search, browser, file, terminal |
| generic | terminal, file, code_execution |

Use these actively — do NOT assume they are unavailable.

## Stopping Conditions

Stop and report when ANY of the following occurs:

- Experiment completes successfully — report final metric
- Time budget exceeded (check `TIME_ESTIMATE` vs elapsed) — report partial results
- Unrecoverable error — report `STATUS: regressed` with error in NOTES
- Code validation fails after 3 auto-repair attempts — report failure

Do NOT loop indefinitely. The supervisor handles retry logic.

## Lattice State Transitions

You do NOT transition Lattice states directly. The supervisor monitors your output and handles:
- `in_progress` → your worker is running
- Lattice comment posted = supervisor read your metric
- `done` = experiment accepted (supervisor action)
- `archived` = experiment discarded (supervisor action)

If you need to signal an issue to the supervisor, print a line starting with `HERMES_STATUS:`:
```
HERMES_STATUS: blocked — missing numpy, cannot proceed
HERMES_STATUS: timeout — partial results in results.json
```

## Configuration

No configuration file needed. The supervisor (Hermes) provides:
- LLM provider via environment (already configured)
- Working directory via `delegate_task` call
- Metric key and format via goal string
- `HERMES_YOLO_MODE=1` to skip command approval

## Anti-Patterns

Do NOT:
- Use subprocess, os.system, eval, exec, or shell escapes in experiment code
- Make network calls (experiments must be self-contained)
- Invent or fabricate metric values — measure real outcomes
- Run without a time guard (always implement elapsed-time check near 80% of budget)
- Print non-metric lines as `key: value` (they will be parsed as metrics)
- Use XML `<function_calls>` format — use JSON tool format instead
Loading