# Hermes Parity Plan — v6.6 → v6.9

Track: bring ClawAgents to feature parity with Hermes Agent on the four
"Hermes-wins" cells of the v6.5 Feature Matrix. Ship as four sequential
minor releases (one feature per release), Python and TypeScript ports
together. Each phase is self-contained — pause between phases is fine.

| Phase | Version | Feature                         | Hermes LOC | Target LOC (per port) |
| ----- | ------- | ------------------------------- | ----------:| ---------------------:|
| 1     | v6.6.0  | Browser tools (Playwright)      | ~5,800     | ~1,200                |
| 2     | v6.7.0  | Cron / scheduled jobs           | ~2,200     | ~900                  |
| 3     | v6.8.0  | ACP (Agent Communication Proto) | ~2,300     | ~1,100                |
| 4     | v6.9.0  | RL fine-tuning hooks            | ~1,800     | ~600                  |

Total Hermes source surveyed: 12,340 LOC. Target ClawAgents footprint:
~3,800 LOC per port (~7,600 total) — i.e., port the **contracts** not
the line count. Heavy deps (`playwright`, `croniter`, `acp`, RL stack)
are all **optional / lazy-imported**, mirroring how MCP and Pillow are
handled today.

---

## Cross-cutting principles

1. **Optional dependencies only**: base packages MUST install without
   `playwright`, `croniter`, `acp`, or any RL-training stack. Each
   feature module imports its deps inside a `try/except ImportError`
   sentinel and raises a clean error from public entry points if the
   user calls them without the extra installed.

2. **Profile-aware paths**: all on-disk state (cron jobs.json, browser
   sessions, ACP state, RL trajectories) lives under
   `get_clawagents_home() / "<feature>"` so the existing profile and
   `CLAWAGENTS_HOME` override semantics work for free.

3. **Plugin-style integration**: each feature exposes its surface as
   a `Plugin` (Python) / `Plugin` (TS) so users opt in via
   `PluginManager.register()` rather than getting forced into the
   import graph. Browser/cron/ACP/RL modules are NOT imported from
   `clawagents/__init__.py` by default.

4. **Cross-port API parity**: every public symbol exists in both ports
   with snake_case (Python) and camelCase (TS) equivalents. Tests
   assert the symbol surface matches across ports.

5. **Hermetic tests**: each phase ships `tests/<feature>/test_*.py` and
   `<feature>.test.ts`. Tests never hit the real network — Playwright
   uses a local `file://` page, ACP uses an in-process pipe pair, RL
   uses a fake `subprocess.Popen` shim, cron uses a frozen clock.

6. **Operational surface**: each feature has a CLI subcommand
   (`clawagents browser-supervisor`, `clawagents cron tick`,
   `clawagents acp serve`, `clawagents rl status`) so power users can
   wire it into systemd / launchd / cron / supervisord.

---

## Phase 1 — Browser Tools (v6.6.0)

**Why first**: largest capability gap, unlocks web-research agents,
web-form fillers, scraping. Hermes' implementation is multi-backend
(local Chromium via `agent-browser` CLI, Browserbase cloud, Browser Use
cloud, Camoufox stealth). We strip to **direct Playwright** with an
extension point for cloud providers.

### Public surface (Python)

```python
# clawagents.browser
from clawagents.browser import (
    BrowserSession,        # context manager
    BrowserSnapshot,       # accessibility tree page repr
    BrowserError,
    BrowserConfig,         # headless, user_agent, viewport, proxy, ...
    create_browser_tools,  # returns list[FunctionTool] for the agent
)
```

### Tool inventory (mirrors Hermes minus delivery-specific ones)

| Tool                        | Notes                                                      |
| --------------------------- | ---------------------------------------------------------- |
| `browser_navigate(url)`     | URL safety check (SSRF block), then `page.goto`            |
| `browser_snapshot()`        | Accessibility tree → text, with `@e1`/`@e2` refs           |
| `browser_screenshot()`      | Returns base64-encoded PNG content block                   |
| `browser_click(ref)`        | Resolves `@e1` to element, awaits navigation               |
| `browser_type(ref, text)`   | Type-into-input, optional submit                           |
| `browser_wait_for(text)`    | Wait until selector or text appears                        |
| `browser_back()` / `forward()` |                                                           |
| `browser_select_option(ref, value)` |                                                       |
| `browser_dialog(action)`    | Accept / dismiss native dialogs                            |
| `browser_hover(ref)`        |                                                           |
| `browser_evaluate(js)`      | **Off by default**, requires `BrowserConfig.allow_eval`    |
| `browser_close()`           | Tear down session                                          |

### Storage

- `get_clawagents_home() / "browser" / "sessions" / <session_id>`
  for per-session state (cookies, local storage, screenshots).
- Session ID is derived from the run context, so siblings in a multi-
  agent run get isolated browser state.

### Cloud provider extension point

```python
class CloudBrowserProvider(Protocol):
    name: str
    def open(self, cfg: BrowserConfig) -> BrowserSession: ...
    def close(self, session: BrowserSession) -> None: ...

# Built-in stubs (require their own pip extras):
#   clawagents[browser-browserbase]   — provider="browserbase"
#   clawagents[browser-cloud]         — provider="browser-use"
```

Default provider is `local` (Playwright). Cloud providers ship as
**stubs** in v6.6 (raise `NotImplementedError("install clawagents[browser-browserbase] and provide credentials")`) and become real in a later patch release if there is demand.

### TypeScript mirror

`clawagents/src/browser/`:
- `index.ts` — public exports
- `session.ts` — `BrowserSession`, lazy `import("playwright")`
- `snapshot.ts` — accessibility tree snapshot logic
- `tools.ts` — `createBrowserTools(): Tool[]`

NPM extras: `playwright` is a `peerDependency` with `optional: true`.

### Rough size estimate

- Python: `browser/__init__.py` (40), `session.py` (260),
  `snapshot.py` (180), `tools.py` (380), `config.py` (90),
  `errors.py` (30), `_safety.py` (110), `__main__` CLI (70) → ~1,160 LOC
- TS: same shape → ~1,200 LOC
- Tests: ~500 LOC each port, against a local `data:` URL fixture

---

## Phase 2 — Cron / Scheduled Jobs (v6.7.0)

**Why second**: smallest scope, well-defined contract (Hermes' cron is
already library-shaped), lets users self-schedule reminders.

### Public surface (Python)

```python
from clawagents.cron import (
    CronJob, CronStore, Scheduler,
    parse_schedule,          # "30m", "every 2h", "0 9 * * *", ISO ts
    create_job, get_job, list_jobs, remove_job, update_job,
    pause_job, resume_job, trigger_job,
    tick,                    # run all due jobs once
    SchedulerDaemon,         # threading-based 60s tick loop
)
```

### Storage

- `get_clawagents_home() / "cron" / "jobs.json"` (file-locked,
  fcntl on POSIX, msvcrt on Windows, mode 0o600).
- `get_clawagents_home() / "cron" / "output" / <job_id> / <ts>.md`
  for run output.

### Job execution model

A job is a **callable spec**. Two execution modes:

1. **Inline** (default): runs `await callable(**kwargs)` in the
   scheduler thread/loop. Suitable for library users embedding cron
   in their app.
2. **Subprocess** (opt-in): `subprocess.Popen([sys.executable, "-m",
   "clawagents.cron.runner", job_id])`. Used by the bundled CLI
   `clawagents cron tick` so each job gets a fresh interpreter.

Hermes' "isolated session" guarantee → we satisfy it via the existing
`forked_subagent` machinery: a job spec can declare `isolated=True`
which the runner translates to `RunContext.fork(skip_memory=True)`.

### Cron expressions

- Optional `croniter` for full cron syntax (`pip install clawagents[cron]`).
- Without `croniter`: only `every Xm/h/d`, `Xm/h/d` one-shot, ISO
  timestamps work. Full cron raises `MissingDependencyError("install croniter")`.

### TypeScript mirror

`clawagents/src/cron/`:
- Pure JS scheduler using `setInterval`, optional dep on `cron-parser`.
- Same JSON file format → Python and TS schedulers are
  interoperable on the same `~/.clawagents/<profile>/cron/jobs.json`.

### CLI

```
clawagents cron list
clawagents cron add --schedule "every 30m" --task "summarize my email"
clawagents cron remove <id>
clawagents cron tick      # run-once for systemd-timer / launchd
clawagents cron daemon    # foreground 60-sec loop
```

### Rough size estimate

- Python: `cron/__init__.py` (30), `jobs.py` (450), `scheduler.py`
  (260), `runner.py` (110), `cli.py` (80) → ~930 LOC
- TS: same → ~900 LOC

---

## Phase 3 — ACP Adapter (v6.8.0)

**Why third**: ACP is a well-specified external protocol
(agent-client-protocol package on PyPI/npm). Once Phase 1 and 2 are
in, ACP gives us interop with Claude Code, Codex, Cursor, etc.

### Public surface (Python)

```python
from clawagents.acp import (
    AcpServer,             # mounts ClawAgent over ACP
    AcpClientShim,         # let a ClawAgent CALL another ACP server as a tool
    AcpAuth,
    AcpPermissions,
    serve_stdio,
    serve_websocket,
)
```

### Sessions

- ACP `Session` objects mapped to `ClawAgent` instances + `RunContext`.
- Persistence in `get_clawagents_home() / "acp" / "sessions" / <id>.jsonl`.
- Resume / fork supported by reusing `RunContext.fork()`.

### Permissions

- Hermes' `permissions.py` (80 LOC) maps ACP approval requests to
  Hermes' tool approval flow. We map them to `RunHooks.before_tool`
  with the existing `ApprovalRequiredEvent` stream.

### Optional dependency

- `pip install clawagents[acp]` → installs `agent-client-protocol`.
- Without it, importing `clawagents.acp` works but `serve_stdio` raises.

### CLI

```
clawagents acp serve --transport stdio
clawagents acp serve --transport ws --port 9292
clawagents acp client <command>     # talk to another ACP server
```

### Rough size estimate

- Python: `acp/__init__.py` (40), `server.py` (450),
  `session.py` (260), `tools.py` (180), `events.py` (130),
  `permissions.py` (60), `auth.py` (40), `cli.py` (80) → ~1,240 LOC
- TS: same shape (using `@zed-industries/agent-client-protocol`) → ~1,100 LOC

---

## Phase 4 — RL Fine-Tuning Hooks (v6.9.0)

**Why last**: lowest installed-base demand, but valuable for the
"agents are RL training data" thesis. Port the trajectory-export
contract; do not vendor TRL/SLIME/Atropos.

### Public surface (Python)

```python
from clawagents.rl import (
    RLTrajectoryExporter,    # convert TrajectoryRecorder → RL-ready format
    HuggingFaceTRLAdapter,   # writes JSONL TRL trainer expects
    SLIMEAdapter,            # writes SLIME-format training set
    AtroposEnvAdapter,       # exposes a ClawAgent run as a Gym-style env
    RLConfig,
    locked_fields,           # mirrors Hermes' "infrastructure-locked" config
)
```

### Trajectory export

The existing `TrajectoryRecorder` already captures `(messages, tool
calls, rewards-or-judge-scores)`. RL exporters consume that:

- `TRL` format: `{"prompt": ..., "chosen": ..., "rejected": ...}` for
  DPO; `{"prompt": ..., "completion": ..., "reward": ...}` for PPO.
- `SLIME` format: SLIME's expected JSON schema.
- `Atropos` format: rollout-style `{"obs": ..., "actions": [...], "rewards": [...]}`.

### Out-of-process training

Training itself is **out of scope** — we don't subprocess `trl`/`slime`.
We just emit the data, and document "use this with `trl train ...`".
Optional `clawagents rl train --config <config.yaml>` shells out to
`trl` if installed.

### CLI

```
clawagents rl export --format trl --out trl-data.jsonl
clawagents rl status   # last export, locked fields, env validation
```

### Rough size estimate

- Python: `rl/__init__.py` (30), `exporter.py` (180),
  `adapters/{trl,slime,atropos}.py` (90 each = 270),
  `config.py` (70), `cli.py` (60) → ~610 LOC
- TS: trajectory export only (no Atropos env adapter — that's
  Python-Gym-specific) → ~400 LOC

---

## Release sequencing

Each phase = its own commit chain + PyPI/GitHub release + version
bump. No interim feature flags — each release is shippable on its own.

```
v6.6.0  Phase 1: Browser tools
v6.7.0  Phase 2: Cron + scheduled jobs
v6.8.0  Phase 3: ACP adapter
v6.9.0  Phase 4: RL fine-tuning hooks
```

Feature Matrix in both READMEs gets a green "✅ (v6.X)" tick after
each phase ships. The matrix becomes "ClawAgents matches Hermes on
all surveyed dimensions" by v6.9.0.
