feat(docs+memory): switching-to-source page; honcho pin derived from pyproject
- website switching-to-source.md (W11, the docs rewrite's missing page): the desktop/installer/docker/nix → source-checkout move, built around the one invariant (data lives in HERMES_HOME, never in the app — nothing is copied, nothing is lost); backup, clone, uv sync --extra all, run, switch back; docker/nix variants; a what-moves-where table; troubleshooting (double-gateway, module errors). Sidebar-wired under Using Hermes. - honcho cli: the 'Install it now? (honcho-ai==2.2.0)' prompt hardcoded the pin — message-only (the install path was already pm.sync_venv lock-owned), but it drifted on every bump. Now derived from the pyproject honcho extra (single authority, 'latest' on lookup failure — never blocks the prompt). The pm-clean plan's 2.6 remainder; the ANCHORS/pyproject extras test half of 2.6 had already healed (16/16 green). W8.1 audited: OBSOLETE — the Dockerfile 'playwright' hits are comments documenting that pm stages the pinned chromium instead; no live invocation to delete.
This commit is contained in:
@@ -501,6 +501,29 @@ def _prompt(label: str, default: str | None = None, secret: bool = False) -> str
|
||||
return val or (default or "")
|
||||
|
||||
|
||||
def _honcho_pin() -> str:
|
||||
"""The pinned honcho-ai version from the pyproject extra — the single
|
||||
authority (a hardcoded message string would drift on every bump)."""
|
||||
try:
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
|
||||
repo = Path(__file__).resolve().parents[3]
|
||||
with (repo / "pyproject.toml").open("rb") as f:
|
||||
data = tomllib.load(f)
|
||||
specs = (
|
||||
data.get("project", {})
|
||||
.get("optional-dependencies", {})
|
||||
.get("honcho", [])
|
||||
)
|
||||
for spec in specs:
|
||||
if isinstance(spec, str) and spec.startswith("honcho-ai=="):
|
||||
return spec.split("==", 1)[1]
|
||||
except Exception:
|
||||
pass
|
||||
return "latest" # never block the prompt on metadata lookup
|
||||
|
||||
|
||||
def _ensure_sdk_installed() -> bool:
|
||||
"""Check honcho-ai is importable; offer to install if not. Returns True if ready."""
|
||||
try:
|
||||
@@ -509,10 +532,11 @@ def _ensure_sdk_installed() -> bool:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
pin = _honcho_pin()
|
||||
print(" honcho-ai is not installed.")
|
||||
answer = _prompt("Install it now? (honcho-ai==2.2.0)", default="y")
|
||||
answer = _prompt(f"Install it now? (honcho-ai=={pin})", default="y")
|
||||
if answer.lower() not in {"y", "yes"}:
|
||||
print(" Skipping install. Run: pip install 'honcho-ai==2.2.0'\n")
|
||||
print(f" Skipping install. Run: pip install 'honcho-ai=={pin}'\n")
|
||||
return False
|
||||
|
||||
print(" Installing honcho-ai...", flush=True)
|
||||
|
||||
117
website/docs/user-guide/switching-to-source.md
Normal file
117
website/docs/user-guide/switching-to-source.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Switching to a Source Install
|
||||
|
||||
You started with the desktop app, the installer script, Docker, or Nix —
|
||||
and now you want to run from a source checkout (to develop on Hermes, use
|
||||
a branch, or escape a packaged-update issue). This page is that move,
|
||||
without losing your sessions, memory, skills, or configuration.
|
||||
|
||||
**The one invariant: your data lives in `HERMES_HOME` (default
|
||||
`~/.hermes`), never inside the application.** A source install is just a
|
||||
new code checkout pointing at the same home. Nothing is copied; nothing
|
||||
is lost. Switching back later is the same procedure in reverse.
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — back up (one command)
|
||||
|
||||
```bash
|
||||
hermes backup
|
||||
```
|
||||
|
||||
This snapshots your home (config, sessions, memory, skills, cron jobs).
|
||||
Not strictly required — the switch doesn't delete anything — but it's
|
||||
the cheap insurance before any install change.
|
||||
|
||||
## Step 2 — clone the checkout
|
||||
|
||||
```bash
|
||||
git clone https://github.com/NousResearch/hermes-agent.git
|
||||
cd hermes-agent
|
||||
```
|
||||
|
||||
For your own development: fork first, clone your fork, and add the
|
||||
upstream remote:
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/NousResearch/hermes-agent.git
|
||||
```
|
||||
|
||||
## Step 3 — create the venv and install
|
||||
|
||||
```bash
|
||||
uv venv
|
||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||
uv sync --extra all
|
||||
```
|
||||
|
||||
This uses the committed `uv.lock` — the same dependency set the
|
||||
packaged builds carry, with hashes.
|
||||
|
||||
## Step 4 — run from source
|
||||
|
||||
```bash
|
||||
hermes # or: hermes gateway / hermes --tui / python -m hermes_cli.main
|
||||
```
|
||||
|
||||
The CLI resolves from your checkout (the venv's `hermes` entry point
|
||||
points at the repo). Your `HERMES_HOME` is untouched — the source
|
||||
install reads the same config, sessions, and memory the packaged install
|
||||
did.
|
||||
|
||||
:::warning Windows App Installer / MSIX users
|
||||
The desktop app's bundled payload and a source checkout are separate
|
||||
installs that can coexist. If the desktop app is running, its backend
|
||||
keeps its own payload — stop it (`hermes gateway stop` or quit the app)
|
||||
before using the source CLI against the same home, so two writers never
|
||||
share one `state.db` (the gateway uses WAL mode; a second writer flips
|
||||
journal modes).
|
||||
:::
|
||||
|
||||
## Step 5 — switching back
|
||||
|
||||
Just run the packaged command again (open the desktop app, or use the
|
||||
installer script). Both installs read the same `HERMES_HOME`; the last
|
||||
one to run owns the session locks. If you stop developing, delete the
|
||||
checkout — your home survives it.
|
||||
|
||||
---
|
||||
|
||||
## Docker users
|
||||
|
||||
A source checkout replaces the image: run the checkout's `hermes`
|
||||
directly, or build the image from the checkout
|
||||
(`docker build -t hermes-agent .`). Your data volume (`/opt/data` by
|
||||
default — the `HERMES_HOME` inside the container) is mounted, not
|
||||
copied: point the source install's `HERMES_HOME` at the same volume and
|
||||
it sees everything the container did.
|
||||
|
||||
## Nix users
|
||||
|
||||
Use the flake from the checkout (`nix run .` / `nix develop`). The Nix
|
||||
store paths change per checkout; your `HERMES_HOME` does not.
|
||||
|
||||
## What moves where (reference)
|
||||
|
||||
| Thing | Location | Moves? |
|
||||
|---|---|---|
|
||||
| Sessions, memory, skills, config | `HERMES_HOME` (`~/.hermes`) | **No** — both installs read it |
|
||||
| Cron jobs | `HERMES_HOME/cron` | No |
|
||||
| Logs | `HERMES_HOME/logs` | No (both install kinds write the same logs) |
|
||||
| Tool binaries (pm store) | machine-scoped tools dir | No — shared between installs |
|
||||
| Python venv | inside the checkout | New — the source venv is the source install |
|
||||
| Desktop payload | inside the app package | Untouched |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"ModuleNotFoundError" running `hermes`** — you're outside the venv, or
|
||||
the venv was built from an old lock. Re-run `uv sync --extra all` inside
|
||||
the activated venv.
|
||||
|
||||
**Two gateways started** — the packaged install's gateway is still
|
||||
running. `hermes gateway status` shows it; `hermes gateway stop` stops
|
||||
it. The gateway lock (`gateway.lock`) prevents silent double-runs on
|
||||
the same profile, but stop one anyway.
|
||||
|
||||
**Different versions of the same skill** — skills live in `HERMES_HOME`,
|
||||
not the checkout; both installs share them. Bundled skills re-sync on
|
||||
first run of the newer code (the skills-sync step in boot bootstrap).
|
||||
@@ -27,6 +27,7 @@ const sidebars: SidebarsConfig = {
|
||||
'user-guide/bot-mode',
|
||||
'user-guide/windows-native',
|
||||
'user-guide/windows-wsl-quickstart',
|
||||
'user-guide/switching-to-source',
|
||||
'user-guide/configuration',
|
||||
'user-guide/managed-scope',
|
||||
'user-guide/configuring-models',
|
||||
|
||||
Reference in New Issue
Block a user