Skip to content

tracking: hermes_agent package restructure #14182

@alt-glitch

Description

@alt-glitch

Overview

Restructure the hermes-agent codebase from a flat collection of top-level modules and independent packages into a single hermes_agent/ package with clear subpackages, dependency direction, and import hygiene.

No logic changes. No API changes. No behavior changes. The same code runs the same way — it just lives at better addresses.

Approach: Top-down layered. Move packages with the fewest inbound dependencies first, working inward toward the core. Each PR moves one layer, leaves the codebase fully working. No shims, no migration scripts, no deferred breakage.

Manifest: hermes_restructure_manifest_v3.md (in repo root, untracked)


Why now

Problem 1: There's no package. The pyproject.toml tells the story — 11 loose py-modules at the root, 8 independent packages discovered via packages.find, and entry points pointing at three different top-level locations. There is no hermes_agent you can import.

Problem 2: Related code is scattered. Model adapters live in agent/, transports live in agent/transports/, execution backends are nested under tools/environments/. The CLI is split between an 11k-line cli.py and a 51-file hermes_cli/ package.

Problem 3: The cost of waiting compounds. Every PR merged against the current structure deepens existing patterns. Before v1 is the natural moment.


Target structure

hermes_agent/
├── constants.py, state.py, logging.py, time.py, utils.py   # leaf modules
├── agent/          # core agent loop, prompt builder, context, memory
├── providers/      # transport + adapter per provider, credentials, pricing
├── backends/       # execution environments (local, docker, ssh, modal, ...)
├── tools/          # tool registry, dispatch, all tool implementations
│   ├── browser/, mcp/, skills/, media/, files/, security/
├── cli/            # CLI entry point, REPL, commands, auth, models, UI
│   ├── auth/, models/, ui/
├── gateway/        # gateway runner, session dispatch, platforms
├── acp/            # ACP adapter
├── cron/           # cron scheduler
└── plugins/        # bundled plugins (memory, context_engine)

Dependency DAG (post-restructure)

hermes_agent.cli
    ↓
hermes_agent.agent  ←  hermes_agent.gateway  ←  hermes_agent.acp
    ↓        ↘
hermes_agent.providers    hermes_agent.tools
                              ↓
                         hermes_agent.backends

hermes_agent.constants, .state, .logging, .time  ←  imported by everything

PR Tracker

PR Sub-issue Status What moves Files Blast radius
PR 1 #14586 📋 Planned acp_adapter/hermes_agent/acp/ 9 1 prod + 11 test refs
PR 2 #14587 📋 Planned cron/hermes_agent/cron/ 3 15 prod + 81 test refs
PR 3 #14588 📋 Planned gateway/hermes_agent/gateway/ ~48 68 prod + 1,224 test refs
PR 4 #14589 📋 Planned hermes_cli/ + plugins/hermes_agent/cli/ + hermes_agent/plugins/ ~72 319 prod + 990 test refs
PR 5 #14590 📋 Planned tools/ + top-level modules → hermes_agent/tools/ + hermes_agent/backends/ ~88 318 prod + 1,088 test refs
PR 6 #14591 📋 Planned agent/ + leaf modules → hermes_agent/agent/ + hermes_agent/providers/ ~59 595 prod + ~950 test refs

Dependency graph

PR1 (#14586) → PR2 (#14587) → PR3 (#14588) → PR4 (#14589) → PR5 (#14590) → PR6 (#14591)
(strictly sequential — each PR rewrites imports that depend on prior moves)

Abort points

Each PR delivers standalone value. Safe stopping points:

  • After PR 1hermes_agent/ package exists, canary PR proves the workflow
  • After PR 3 — all "peripheral" packages moved (acp, cron, gateway)
  • After PR 6 — single package, clean imports, full restructure complete

What each PR does NOT do

Every PR is purely mechanical. Across all PRs:

  • No logic changes — code behavior is identical before and after
  • No layer inversion fixesagent/ importing from cli/ is moved as-is
  • No API changes — CLI commands, entry points, config format unchanged
  • No migration script — top-down approach means each PR is atomic

Commit strategy (same for all PRs)

Commit What Why
Commit 1 Pure git mv — files move, zero content changes 100% similarity for clean blame
Commit 2 Import rewrite — all 6 categories (import, from-import, patch(), monkeypatch, sys.modules, importlib) Content changes only in import/string lines
Commit 3 Infra + fixups — pyproject.toml, shell scripts, __init__.py re-exports, .git-blame-ignore-revs Build system points at new locations

Verification checklist (run after every PR)

python -c "import hermes_agent"
rg "^from <old_package>[\. ]" --type py     # adjust pattern per PR
rg "(import_module|__import__|importlib)\(.*['\"]" --type py
pytest
hermes --help && hermes-agent --help

Key decisions

Decision Choice Rationale
Move order Top-down (least-imported first) Each file's imports rewritten at most once per moved dependency
plugins/ Moves into hermes_agent/plugins/ Single package boundary
__init__.py re-exports Ship in same PR that creates sub-packages Zero breakage between PRs
sys.path hacks Strip from production code Redundant with editable install
Process-name matching Keep old patterns for one release cycle Backwards compat for running gateways
Migration script Not needed Top-down approach is atomic per PR

Learnings from V1 prototype

The monolithic approach (branch sid/foundational-restructure, draft PR #14498) validated the mechanics:

  1. Tests are ~75% of the diff (each test averages ~15 rewrite sites)
  2. git mv in a separate commit gets 100% similarity — clean blame
  3. Non-.py files (scripts/hermes-gateway, install.ps1) get missed by **/*.py globs
  4. 4 test files write old-style imports as string literals into dynamically-created plugin files
  5. Plugin sys.modules surgery needs dedicated verification (string-based paths)
  6. _get_bundled_dir() in skills_sync breaks silently after move (wrong Path(__file__) depth)

Superseded

Reference

Follow-up issues

Issue Priority What
#14278 Medium Fix agent→cli layer inversions in providers/
#14279 Low Remove legacy process-name patterns after v1

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havecomp/acpAgent Communication Protocol adaptercomp/agentCore agent loop, run_agent.py, prompt buildercomp/cliCLI entry point, hermes_cli/, setup wizardcomp/cronCron scheduler and job managementcomp/gatewayGateway runner, session dispatch, deliverycomp/toolsTool registry, model_tools, toolsetstype/refactorCode restructuring, no behavior change

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions