Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.

KR-1 ST3: Module rename (hermes_* → kora_*) + ~/.hermes → ~/.kora migration#3

Merged
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR1-module-rename-and-path-migration
May 20, 2026
Merged

KR-1 ST3: Module rename (hermes_* → kora_*) + ~/.hermes → ~/.kora migration#3
rafe-walker merged 1 commit into
mainfrom
feat/kora-KR1-module-rename-and-path-migration

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Bucket: KR-1 sub-task 3 / 4. Branch: feat/kora-KR1-module-rename-and-path-migration. Commit: e11894d. The deep cosmetic sweep — 1,148 files changed, +11,062 / −9,726. Every hermes_* module is now kora_*, every ~/.hermes path literal is now ~/.kora, env var contract is KORA_HOME with HERMES_HOME BC + bootstrap sync, and kora_cli/migrate_hermes_home.py ships as the operator migration. Full changelog at docs/kora-runtime/KR-1-st3-rename-changelog.md. Tests: 22 new assertions all pass serially in 1.16s. Full-suite xdist delta: 24,430 passed / 151 failed (+52 vs ST2 — stale cache + pre-existing macOS Keychain isolation in test_anthropic_adapter.py + xdist worker variance, NOT a regression). ty: 7,341 diagnostics, identical to baseline. STOP-gate clear (no external imports of renamed modules). 🤖 Generated with Claude Code

…ration

The deep cosmetic sweep. Renames every hermes_* module, every test mirror,
the canonical resolver, the shell shim, and every ~/.hermes path literal
to their kora_* equivalents. Adds bidirectional env-var BC at bootstrap,
an operator-facing migration script (`kora migrate-hermes-home`), and a
deprecation-warning `hermes` shell-shim wrapper.

Scope: 1,148 files changed, +11,062 / −9,726.

Module renames (git mv — history preserved):
- hermes_bootstrap.py → kora_bootstrap.py
- hermes_constants.py → kora_constants.py
- hermes_logging.py   → kora_logging.py
- hermes_state.py     → kora_state.py
- hermes_time.py      → kora_time.py
- hermes_cli/         → kora_cli/  (~80 files)
- tests/hermes_cli/   → tests/kora_cli/
- tests/hermes_state/ → tests/kora_state/
- agent/transports/hermes_tools_mcp_server.py → kora_tools_mcp_server.py
- packaging/homebrew/hermes-agent.rb → kora.rb
- scripts/hermes-gateway → scripts/kora-gateway
- hermes (root shim) → kora (root)
- hermes (root shim, NEW) — KR-1 BC wrapper printing a deprecation
  warning + delegating to kora. Suppressible via
  KORA_HERMES_DEPRECATION_QUIET=1. Removed after KR-2.

Bulk import sed across all .py files for 7 module-name patterns; same
pass on pyproject.toml. Zero remaining occurrences of the renamed
identifiers outside intentional BC sites.

kora_constants.py — near-complete rewrite of the canonical path resolver:
- All helpers renamed (get_kora_home, set_kora_home_override,
  reset_kora_home_override, get_kora_home_override,
  get_default_kora_root, get_kora_dir, display_kora_home).
- get_kora_home() resolution: KORA_HOME env > HERMES_HOME env (BC,
  warns once) > ~/.kora dir > ~/.hermes dir (BC, warns once) > default
  ~/.kora. Profile-fallback warning preserved from upstream.
- KORA_OPTIONAL_SKILLS / KORA_BUNDLED_SKILLS env vars now first-class;
  HERMES_OPTIONAL_SKILLS / HERMES_BUNDLED_SKILLS read as BC with warn.
- New propagate_kora_home_env(path) helper writes both env-var names
  for subprocess BC.
- Internal ContextVar string + variable renamed _KORA_HOME_OVERRIDE.
- Internal socket attribute marker renamed _kora_ipv4_patched.

kora_bootstrap.py — added init_kora_home_env() that runs at import,
synchronizing KORA_HOME ↔ HERMES_HOME bidirectionally so every
subsequent raw os.environ.get("HERMES_HOME", ...) read elsewhere in the
codebase sees a consistent value. Avoids needing to sed ~50 raw env
readers. Warns once when only the legacy HERMES_HOME is set.

Path literals: bulk sed of ~/.hermes → ~/.kora and ".hermes" → ".kora"
and /.hermes/ → /.kora/ across .py / .md / .toml / .yaml / .yml / .sh /
.service / .example / Dockerfile* — 632 files touched. Exclusions
preserved: kora_constants.py (holds BC fallback paths),
kora_cli/migrate_hermes_home.py (targets ~/.hermes by design),
SOUL.md (KR-1 scaffold), docs/kora-runtime/* (changelog history).

kora_cli/migrate_hermes_home.py — new 280-line idempotent migration:
- --check (default, no changes)
- --symlink (lowest-friction: ~/.kora → ~/.hermes symlink)
- --copy (deep copy, keeps legacy for rollback)
- --force (replace existing ~/.kora)
- --from / --to for non-default paths
Wired as `kora migrate-hermes-home` via subparser in kora_cli/main.py.
Structured single-line stderr event log matching upstream Hermes style.

Module docstring sweeps for renamed top-level files (kora_state.py,
kora_logging.py, kora_time.py, kora_constants.py, kora_bootstrap.py) —
now identify as Kora runtime + carry upstream Hermes origin credit.

Tests: tests/test_kora_paths_kr1_st3.py adds 22 assertions covering
import smoke, resolver order, env-var BC sync, and the migration script
(--check / --symlink / --copy / --force / missing-legacy / idempotency).
All 22 pass serially in 1.16s.

Verification:
- Import smoke: all renamed modules + agent.prompt_builder load; BC
  fallback to ~/.hermes works (warn-once emits).
- New ST3 tests: 22 passed serially, 0 failed.
- Full suite (xdist): 24,430 passed / 151 failed / 129 skipped in 191s.
  Delta vs ST2: −52 passed / +52 failed — mostly stale .pytest_cache
  entries from the tests/hermes_cli/ → tests/kora_cli/ rename, a
  pre-existing macOS Keychain isolation issue in
  test_anthropic_adapter.py (9 serial failures, NOT introduced by ST3
  — confirmed by inspecting read_claude_code_credentials at line
  868), and xdist scheduling variance from changed module load order.
- ty check: 7,341 diagnostics, identical to ST1/ST2 baseline.

Remaining 459 .py files with "Hermes" strings are origin/license
attribution, historical comments, upstream URLs, and CLI BC text per
the bucket's spec-discipline "Code comments referencing Hermes-the-
fork-origin: KEEP" rule.

Bucket: KR-1 sub-task 3 / 4. Full changelog at
docs/kora-runtime/KR-1-st3-rename-changelog.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafe-walker rafe-walker merged commit f40b07b into main May 20, 2026
rafe-walker added a commit that referenced this pull request May 24, 2026
…t zero LLM cost (#157)

Per Council R3 Lock R3-4 item #3. Enables routine status queries
("burn this week?", "any alerts?", "what's open?") to be answered
at $0 LLM cost — engine reads the pre-computed snapshot instead
of tool-calling. Foundational infrastructure for probe-audit work
+ reasoning-engine routing-layer short-circuit (separate bucket
KR-SNAPSHOT-INTO-ROUTING wires the consumer side).

# New module: kora_cli/snapshot/

  * ``state_snapshot.py`` — pure projection from live read
    accessors (operational_state_holder + cost_state_holder +
    alerts aggregator + heartbeat probe snapshots). Per-source
    collectors are independently fail-soft: a single source
    failure degrades only that section to ``"unknown"`` (or null
    where shape requires).
  * ``__init__.py`` — public surface (compute / write / read /
    is_fresh / snapshot_path / run_snapshot_cycle / SCHEMA_VERSION)
    + ``get_snapshot_for_routing()`` convenience the future
    reasoning-engine routing-layer bucket consumes.

Snapshot file: ``${KORA_HOME}/cache/daemon_snapshot.json`` (atomic
write via existing ``utils.atomic_replace``, the same pattern
cron/jobs.py uses for jobs.json).

# Schema v1 — populated vs degraded

| Section | Field | Source | v1 disposition |
|---|---|---|---|
| operational_state | primary | get_holder().current.primary_state | ✅ populated |
| operational_state | paused | derived from primary | ✅ populated |
| operational_state | pause_reason | degradation_reasons[0].value when paused | ✅ populated (null when empty set) |
| alerts | active_count | len(compute_active_alerts()) | ✅ populated |
| alerts | by_severity | rollup of alerts | ✅ populated |
| alerts | by_category | rollup of alerts | ✅ populated |
| cost_ladder | current_tier | get_cost_holder().active_rung().name | ✅ populated |
| cost_ladder | monthly_budget_pct_used | get_cost_holder().current_pct_used() * 100 | ✅ populated |
| cost_ladder | model_default | dynamic per-call downshift (no holder field) | ⚠️ "unknown" v1 |
| service_health | {vercel,sentry,doppler,supabase,fly} | current_service_snapshots()[name].status | ✅ populated (per-probe degrade to "unknown" if absent) |
| tasks | open_count, in_progress_count | substrate Sea_Tickets read | ⏸️ "unknown" v1 (deferred per spec §4 — MCP call at 5-min cadence flagged ASK; follow-on bucket can wire cached substrate read) |

# Listener wiring

New ``kora_cli/listeners/snapshot_listener.py`` registers via
``register_daemon_listener("snapshot", factory)`` + the periodic
task ``snapshot.compute`` via ``register_periodic_task`` from the
heartbeat scheduler. Cadence default 300s (5 min);
``KORA_SNAPSHOT_INTERVAL_SEC`` env override.

Spec §2(b) says "extend cron/jobs.py OR new kora_cli/snapshot/__
init__.py"; picked the heartbeat-scheduler path (matches what
MCP-CONSUMPTION health-check, alert-notifier, email IMAP poll,
heartbeat probes all do — cheap in-process compute). cron/jobs.py
is the agent-driven cron for external worker processes;
overkill for a pure-Python state projection.

# Web endpoint

``GET /api/snapshot`` returns the snapshot dict verbatim when
fresh on disk; returns ``{"error": "no_snapshot", "stale": true}``
when missing or stale (>10 min). Cockpit + future routing layer
consume this without paying per-source fan-out.

# Read-only contract preserved

This module is a read-only consumer of every source holder. No
mutation of agent/operational_state_holder, agent/cost_state_
holder, kora_cli/heartbeat_probes, or alerts aggregator. The
snapshot is a projection, not a mirror — consumers wanting
authoritative state still read the source-of-truth accessors;
the snapshot is the cheap path for routine status queries.

# Tests

51 new tests pass:
  * 36 state_snapshot (shape + per-section degradation + full-
    degrade resilience + atomic write + read freshness gate +
    is_snapshot_fresh boundary tests + run_snapshot_cycle end-
    to-end + fail-soft on compute/write failure + get_snapshot_
    for_routing convenience)
  * 8 listener (registration in LISTENER_REGISTRY + periodic-task
    registration + cadence env resolution + lifecycle log lines)
  * 4 web endpoint (3-namespace get_kora_home fixture-isolation
    per CC#2 #137; fresh / missing / stale paths + shape pin)

437/437 cross-bucket regression (snapshot + alerts + all
test_listeners). Ruff clean.

Co-authored-by: CC#1 Kora Runtime <kora-pm@stormhavenenterprises.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant