autoloop/20260425T014006Z/w5/2 2.b.5 non editable gateway progress commentary send fallba - #6
Merged
XelHaku merged 3 commits intoApr 25, 2026
Conversation
XelHaku
commented
Apr 25, 2026
Collaborator
- ci(www): deploy gormes.ai to Cloudflare Pages
- feat(progress): add RowHealth schema for autoloop
- gateway: add non-editable send fallback
Mirrors deploy-gormes-docs.yml for the landing site at gormes.ai.
The Go-rendered landing page had no CI deploy, so the operations-
first rewrite + favicons + OG/Twitter tags shipped to docs.gormes.ai
but never reached the actual gormes.ai surface — production was
still serving the pre-rewrite "Same Hermes Brain" copy with no
favicon.
Pipeline:
1. Refresh internal/site/data/{benchmarks,progress}.json from the
canonical sources at the repo root and under docs/. The local
Makefile has the same rule, but its mtime check no-ops on
fresh CI checkouts where source and target share a timestamp.
2. make build → CGO_ENABLED=0 static binary.
3. ./bin/www-gormes export --out dist → dist/{index.html,
install.{sh,ps1,cmd}, static/*}.
4. Verify dist/ has the expected artifacts and dist/index.html
contains the new headline, favicon link, og:image, and is
free of the old "Same Hermes Brain" / "Why a Go layer matters"
tokens — same defense in depth as the docs workflow.
5. wrangler pages project create gormes-www (idempotent) → pages
deploy → attach gormes.ai and www.gormes.ai to the project.
Triggers on push to main with changes under www.gormes.ai/**, the
canonical benchmarks.json + progress.json (which flow into the
embedded data), the install scripts (mirrored under
www.gormes.ai/internal/site/installers/), and the workflow itself.
workflow_dispatch is also enabled for manual redeploys.
Reuses the same CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID secrets
as deploy-gormes-docs.yml.
Project name 'gormes-www' is a placeholder mirroring 'gormes-docs'.
If the existing Cloudflare Pages project bound to gormes.ai uses a
different name, update --project-name= in the deploy + domain-
attach steps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
XelHaku
deleted the
autoloop/20260425T014006Z/w5/2-2.b.5-non-editable-gateway-progress-commentary-send-fallba
branch
April 25, 2026 07:48
XelHaku
added a commit
that referenced
this pull request
Apr 25, 2026
Implements items #6 and #10 from docs/cmd-loops-improvements.md. #6 — Doctor actually diagnoses drift: * planner-loop doctor now also: parses+validates progress.json, verifies PLANNER_TRIGGERS_PATH is writable, and emits an advisory warning when the latest health_updated event is older than 2× PLANNER_INTERVAL (planner ledger) or 1h (builder ledger). * builder-loop doctor introduced (was absent) with the same progress.json + triggers writability + builder-loop drift checks. * Drift warnings are advisory (exit 0) so doctor remains automation-safe; only hard preconditions (missing progress, parse failure, unwritable triggers path) fail the check. #10 — Table-driven progress write: * Replaced the nine near-identical rewriteProgressMarker blocks with a []progressMarker table driven by one loop. Adding a new marker is now appending one struct entry instead of editing four boilerplate lines. Helper extraction: * latestLedgerEventTime + driftWarning + triggerPathWritable are duplicated in both binaries for now (no internal/cmdcommon yet). Item #11 will collapse them once the cliDeps refactor lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
XelHaku
added a commit
that referenced
this pull request
May 8, 2026
`gormes update` now checks the on-disk config schema version after the web build step. When the version is outdated: - With --yes: auto-applies via internal/config.MigrateConfigFile and emits ✓ update_config_migrate_completed. - Without --yes: emits ⚠ update_config_migrate_needed advisory pointing the operator at `gormes config migrate` (or rerun with --yes). When the config is already current, no evidence is emitted (silent default — no nag on every update). Best-effort: errors from either the check or migrate seam emit ✗ update_config_migrate_failed but never fail the overall update. What's added: - internal/cli ConfigCheckRunner + ConfigMigrateRunner seam types (parallel to SkillSyncRunner / WebBuildRunner pattern; decoupled from internal/config so the lifecycle stays import-free). - internal/cli ConfigVersionResult struct mirroring CheckReport. - 3 new evidence kinds: - update_config_migrate_completed → ✓ (auto-applied) - update_config_migrate_needed → ⚠ (operator action required) - update_config_migrate_failed → ✗ (check or migrate error) - internal/cli emitConfigMigrate helper with 7-branch decision table documented inline. Runs after web build, before gateway restart. - cmd/gormes default adapters wrap internal/config.Check and internal/config.MigrateConfigFile into the seam shape. - updateGlyphAndColor extended: `*_needed` suffix → ⚠ (yellow, operator-action-required category). Tests: - internal/cli/update_lifecycle_config_migrate_test.go (6 lifecycle tests): - NilConfigCheck silent default - ConfigAlreadyCurrent silent (no nag) - ConfigOutdatedWithoutYes emits needed + does NOT call migrate - ConfigOutdatedWithYes auto-applies + emits completed - ConfigMigrateError emits failed + update still succeeds - ConfigCheckError emits failed + does NOT attempt migrate - cmd/gormes/update_progress_ui_test.go ConfigMigrateGlyphs verifies ✓/⚠/✗ for the 3 new kinds. Implements row #6 from the gormes-update parity batch (audit agent's recommended order). Reuses the structured progress UX from c83d10e and the silent-default + best-effort patterns established by 56efc40 (backup), f30f72c (skill sync), and fa4a10d (web build). Owned divergence vs Hermes' richer prompt: - Interactive y/n at the prompt is intentionally not in this slice. Hermes' interactive flow would require a stdin reader seam and more branching. The slice ships --yes auto-apply + advisory-when-not, and the operator interactive path remains owned by the existing `gormes config migrate` command. - Per-bucket missing_env / missing_config counts (Hermes' "⚠️ N required setting(s) need configuration") are not in this slice. CheckReport's Issues field carries them but the slice surfaces only version-skew. Detailed breakdown is a follow-up if operators ask. Audit batch progress: 5 of 6 update-parity rows shipped (structured UX, pre-update backup, skill sync, web build, config migrate). Remaining: goncho sync (#4) — deferred until internal/goncho gains a profile-sync surface. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
XelHaku
added a commit
that referenced
this pull request
May 9, 2026
* feat: add OpenCode backend support to cron/loop scripts
* feat: add Telegram thread-not-found fallback + send retry safety
Add retry logic to SendThread/SendThreadReply/SendThreadChatAction:
- Thread-not-found errors retry once without message_thread_id
- Non-thread BadRequest fails immediately (no retry)
- TimedOut never retries (avoids duplicate messages)
- Transient NetworkErrors bounded to 3 attempts
- New helpers: isThreadNotFoundError, isTimedOutError, isTransientNetworkError
TDD: 15 new tests across thread_fallback_test.go + send_retry_test.go.
Matches Hermes b816fd4e2 _is_thread_not_found_error retry loop semantics.
* docs: update progress for Telegram forum thread fallback row completion
Row status: planned→complete. Planner pass: sharpened contract_status
draft→validated, updated ready_when/not_ready_when to reflect completed
thread-aware send seam dependency. Regenerated all progress-derived docs
via go run ./cmd/progress write. 720 complete, 49 planned remaining.
* fix: update Phase 2 test expectations from in_progress to complete
Phase 2 has all 21/21 subphases and 73 routing/context rows shipped.
Tests TestLoad_RealFile and TestLoad_RealFile_Phase2ExecutionQueue
were asserting in_progress for Phase 2 and 2.B.5 respectively; both
are now complete. This restores CI green.
* feat: add browser session inactivity cleanup with configurable timeout
Port Hermes BROWSER_SESSION_INACTIVITY_TIMEOUT (default 300s) to Gormes as a
BrowserSessionTracker with background reap goroutine. TDD delivers six fixtures:
idle reaping, active preservation, reap-interval ticking, env-var override,
nil-backend safety, and close-failure evidence recording.
* docs: add browser inactivity cleanup row to Phase 5.C progress
All-topic parity sweep (CLI/TUI, provider/auth, gateway/channels, tools,
sessions/memory/Goncho, install/runtime, browser automation, docs/public,
release/operator) identified browser inactivity cleanup as the highest-impact
source-backed gap. Added P2 row under 5.C with contract, write_scope,
test_commands, and Hermes upstream ref. Regenerated all progress surfaces.
* feat: add SkillValidator ForceLoad, async, and canary execution support
Completes Phase 6.L 'Skill validation on load with execution proof' (P2):
- ForceLoad field on SkillValidator persists validation errors while
allowing operator override.
- ValidateAsync and ValidateCanaryAsync run in background goroutines
with channel-based result delivery (<500ms guarantee).
- ValidateCanary uses language-specific minimal safe inputs (python,
bash, javascript) to catch gross syntax/import errors quickly.
- ForceLoadMsg formats human-readable force-load explanations.
- 13 new tests covering: force-load on/off, async success/failure,
canary success/failure, fallback for unknown languages, duration,
and ForceLoadMsg content verification.
* docs: complete Phase 6.L skill validation row and close deprecated umbrellas
Parity sweep (2026-05-07) findings applied:
- Phase 6.L 'Skill validation on load with execution proof' (P2) marked complete.
- Phase 5.O deprecated CLI profile umbrella marked complete (replaced by siblings).
- Phase 5.D Multimodal in/out umbrella closed (all children complete).
- Regenerated progress-driven docs and landing site progress data.
* chore: vendor hermes-agent as a git submodule on origin/main
Convert the in-repo hermes-agent reference checkout from a gitignored side-
clone into a tracked submodule pinned to NousResearch/hermes-agent main.
Local mods on the previous side-clone (Karpathy guardrails template added to
AGENTS.md/CLAUDE.md by onboarding tooling) were not upstream work and were
backed up to /tmp before resetting. The submodule now matches upstream HEAD
exactly so the gormes-hermes-parity sweep classifies against current truth
instead of a 3-day-stale checkout.
* docs: refresh hermes-agent submodule at parity sweep start
Teach gormes-hermes-parity to update the in-repo hermes-agent submodule to
upstream main HEAD before reading parity references, and to pass that bumped
sha through to gormes-git when builder rows land. Falls back to fetch+ff-only
for legacy clones, no-op if absent. Prevents stale-baseline classification.
* chore: drop hermes-agent from .gitignore now that it is a submodule
Remove the gitignore entry that hid the previous side-clone, and replace it
with a marker comment pointing to .gitmodules. Without this, the submodule
worktree would still be ignored at the parent level and confuse contributor
tooling.
* docs: complete Phase 6.L code executor and dependency resolver rows
Mark 'Skill code execution runtime' (P2) and 'Skill dependency resolution
and composition' (P3) as complete with implementation evidence and passing
test verification. Both rows had full Go implementations on disk
(internal/skills/code_executor.go, dependency_resolver.go) with passing
tests but were incorrectly marked as planned in progress.json.
Evidence: 4 code executor tests (success, error exit, empty code, default
timeout) + 5 dependency resolver/composer tests (linear, circular, missing,
compose, validate chain) all pass. Regenerated progress surfaces.
* docs: add 6 builder-ready rows from Hermes v0.12.0 + v0.13.0 parity sweep
gormes-planner pass over Hermes releases v2026.4.8..v2026.5.7
(v0.8.0..v0.13.0). Adds six progress.json rows materializing the
highest-leverage gaps surfaced by the sweep, with full builder contracts
(contract, contract_status, slice_size, execution_owner, trust_class,
degraded_mode, fixture, source_refs, ready_when, not_ready_when, blocked_by,
unblocks, acceptance, write_scope, test_commands, done_signal, note,
provenance):
- 5.Q P2/medium Provider client lazy-init for TUI cold-start budget
(v0.12.0 #17046 lead of the ~57% cold-start cut family)
- 5.I P2/small Plugin lifecycle hook: transform_llm_output
(v0.13.0 #21235)
- 5.D P2/medium Native video_analyze tool contract (v0.13.0 #19301)
- 5.M P1/medium Kanban worker heartbeat, reclaim, and zombie detection
(v0.13.0 #21183, #21214, #20188, #20410)
- 7.E P2/small Google Chat shared-chassis platform adapter seam
(v0.13.0 #21306, #21331)
- 5.J P0/small Auth state TOCTOU close + redaction default-on parity
(v0.13.0 #21193, #21194, #21241; reverts v0.12.0 #16794)
Each row's `unblocks` field names sibling work explicitly deferred from this
pass (cold-start mtime cache / tool memoize / pattern precompile,
pre_gateway_dispatch / pre_approval / duration_ms hooks, Gemini video
transport, Google Chat transport binding, etc.) so future planner picks have
an obvious next step. Provenance is recorded as the schema struct
(origin_type=upstream); upstream_ref left empty pending symbol-level mapping
when each row is picked up by a builder.
Derived surfaces regenerated by `go run ./cmd/progress write`. Validated by
`go run ./cmd/progress validate` (7 phases ok) and
`go test ./internal/progress -count=1` (ok).
* docs: add 7 missing upstream Hermes doc mirrors for mirrored coverage parity
* docs: add Phase 8 (Reputation & Publication) + 12-month success plan
Strategic pivot for Gormes from "Hermes in Go" parity chase to
TrebuchetDynamics reputation play. The methodology is the product;
Hermes-parity is the receipt that proves the methodology works.
New strategy doc: docs/content/building-gormes/strategy/success-plan.md
- North Star: "TrebuchetDynamics is the team that figured out how to
autonomously port large Python projects to Go in production. Gormes is
the receipt."
- Quarterly roadmap (Q1 foundation → Q2 toolkit OSS → Q3 sharp v1.0 →
Q4 compound).
- 30-day action sprint (TD blog, README rewrite, writeup #1 draft, sharp
differentiator decision, $/iteration cost telemetry).
- Operating principles: publication cadence > commit cadence; solo devs
win on opinion not scope; the loop is the product; cost discipline.
- Reputation metrics scoreboard replacing row-count vanity metrics.
- Risk register including publication paralysis, identity drift, loop
spend without learning.
New progress.json Phase 8 with 7 subphases and 10 builder-tractable rows
(all gormes-owned, provenance.origin_type=gormes):
- 8.A Publication Infrastructure
P1 TD engineering blog scaffolded and live
P3 TD social presence connected to blog feed
- 8.B Repository Messaging
P1 README rewrite to methodology-first positioning
P2 gormes.ai landing page positioning audit
- 8.C Engineering Writeups
P1 Engineering writeup #1: autonomous Hermes-porting loop
- 8.D Sharp v1.0
P0 Sharp v1.0 differentiator decision
P1 Single-binary cross-platform release pipeline
- 8.E Toolkit Extraction
P2 Agentic-porting-kit repo scaffold
- 8.F Cost Discipline & Loop Economics
P1 Loop $/iteration cost metric in status file
- 8.G Community & External Contributions
P3 Built-with-Gormes page scaffold
Each row carries the full builder contract (contract, contract_status,
slice_size, execution_owner, trust_class, degraded_mode, fixture,
source_refs, ready_when, not_ready_when, blocked_by, unblocks,
acceptance, write_scope, test_commands or no_test_required, done_signal,
note, provenance). Strategy-only rows that need operator taste (writeup
voice, differentiator decision) explicitly carry no_test_required with a
human-checked acceptance contract.
Validated: go run ./cmd/progress write/validate (8 phases ok),
go test ./internal/progress (ok), git diff --check.
* docs: rewrite landing page hero + add methodology section (8.B materialization)
Materializes progress.json row 8.B "gormes.ai landing page positioning audit"
under the methodology-first North Star captured in success-plan.md.
Hero changes:
- New title: "Hermes-Compatible AI Agent Runtime in One Go Binary".
- New headline: "AI agent runtime in one Go binary." (outcome-first per
landing-quality-rubric).
- New sub-lines lead with Hermes-ecosystem compatibility, then introduce
the autonomous engineering loop as the trust play.
- New kicker: "OPEN SOURCE · MIT LICENSE · AUTONOMOUSLY PORTED FROM HERMES".
- Secondary CTA changes from "View on GitHub" to "See how it is built"
pointing at the new methodology section.
- Proof strip adds "Autonomous porting loop ships daily".
New section: HOW IT IS BUILT (#methodology), placed between hero and
install. Contains:
- A measured-loop-output metrics row (rows shipped, code base, binary)
bound to benchmarks.json so it stays current.
- Four pillar cards: validation-gated commits, progress.json as system
of record, Hermes is the parity oracle, reusable porting toolkit.
- Link to /building-gormes/architecture_plan/.
Trust posture:
- Adds "Every autonomous-loop commit passes a validation gate (go test,
progress validate, git diff --check) before landing" to the trust list.
Top nav restructured:
- "Docs" replaced with "How it is built" (jumps to methodology).
- "Install" added as a top-level anchor.
Playwright tests updated to match the new strings; mobile-overflow tests
updated for the new headline. All 5 tests pass at iPhone SE through
iPhone Plus widths.
Validated:
npm run build -> ok
npm run test:e2e -> 5 passed
go run ./cmd/progress -> validated 8 phases
git diff --cached --check -> ok
Other dirty paths in the worktree (kanban .go files, progress.json
status updates, derived builder-loop docs) belong to the autonomous
loop's in-flight work on row 5.M and will land via the loop's own
gormes-git step.
* Release v0.1.06 (v2026.5.7)
The Pivot Release. Adopts the Hermes-style dual versioning taxonomy
(canonical semver tag v0.1.06 paired with date alias v2026.5.7),
captures a 12-month methodology-first strategy, and stands up Phase 8
in progress.json.
Highlights
- Methodology-first repositioning: success-plan.md is the new North
Star ("TrebuchetDynamics is the team that figured out how to
autonomously port large Python projects to Go in production. Gormes
is the receipt").
- Phase 8 (Reputation & Publication) added with seven subphases
(8.A-8.G) and ten gormes-owned builder-ready rows.
- Six Hermes-parity rows materialized from upstream v2026.4.30 +
v2026.5.7 sweep (cold-start lazy-init, transform_llm_output hook,
video_analyze tool, Kanban worker heartbeat, Google Chat adapter,
auth TOCTOU + redaction default-on P0).
- Landing page rewrite: outcome-first hero, new methodology section
with live loop-output metrics, four pillar cards.
- hermes-agent now tracked as git submodule pinned to upstream
NousResearch/hermes-agent main (sha 7e2af0c2e).
- opencode/deepseek-v4-pro builder backend added alongside codexu;
GORMES_BUILDER_BACKEND switch on the cron loop.
- Phase 6.L code executor and dependency resolver rows complete.
Versioning Taxonomy
- Canonical git tag: v0.1.06 (semver; gates with cmd/gormes/version.go).
- Date alias: v2026.5.7 (Hermes-style vYYYY.M.D, surfaced in release
notes filename header, GitHub release title, and CHANGELOG entry).
- A future row migrates the canonical git tag to the date form once
the release workflow extracts version from cmd/gormes/version.go
independently of the tag string.
Validation
go test ./... -count=1 ok (full suite)
go run ./cmd/progress validate validated 8 phases
git diff --check ok
landing build ok
landing e2e 5 passed (homepage + 4 mobile vps)
Files
- cmd/gormes/version.go 0.1.05 -> 0.1.06
- CHANGELOG.md [0.1.06] - 2026-05-07 entry
- RELEASE_v0.1.06.md Hermes-style release notes (new)
- webpages/landing/src/data/release.json
version bump for landing surface
* docs: add gormes-install skill — sandbox-isolated install testing
New repo-local skill at docs/development-skills/gormes-install/.
Symlinked into .agents/skills/, .claude/skills/, .codex/skills/.
Purpose
- Test and validate Gormes install + setup paths against a real
release. Surface install-time issues that pure CI cannot catch
(PATH leaks, shell-rc edits, symlink hijacking, misleading status
messages, hidden side effects on existing installs).
Authored from a real test pass against v0.1.06 (the release just
cut). Three open install issues filed in references/known-issues.md
from that pass:
- iso-bin-hijack — sandbox install hijacks production
~/.local/bin/gormes symlink despite GORMES_BIN_DIR being set to a
sandbox path. Active-PATH-command update should respect sandbox
prefix.
- iso-shellrc-leak — sandbox install permanently edits ~/.bashrc and
~/.profile with a /tmp/-rooted PATH entry. After /tmp is reaped,
every login shell has a dangling PATH. No installer-emitted
cleanup path.
- msg-systemd-fiction — install transcript unconditionally announces
"systemd user service installed" even when no service file is
written and `systemctl --user list-unit-files 'gormes*'` reports
zero units.
All three need follow-up rows under Phase 5.P (installer) or 5.O
(CLI surfaces) and TDD coverage via gormes-tdd-slice. This skill
finds and documents; it does not patch.
Skill structure
- SKILL.md — mission, when-to-use table, hard constraints,
nine-step workflow, validation, final-report.
- references/known-issues.md — living register with format spec and
coverage gaps worth closing (uninstall, --local,
Termux, WSL2, root install, install.ps1, fresh
machine without Go/git, curl|bash flow,
upgrade-in-place with non-default config).
- references/test-recipes.md — copy-paste recipes for sandbox setup,
pre/post-state capture, dry-run, real install,
diff, functional smoke, production restoration,
uninstall, branch/tag pass.
Validated
python3 quick_validate.py docs/development-skills/gormes-install ok
go run ./cmd/progress validate 8 phases ok
git diff --check ok
* chore: update hermes-agent submodule pointer
* docs: file 3 install issues from gormes-install pass as 5.P planner rows
Materializes the three open install issues found by the gormes-install
sandbox pass on 2026-05-07 against install.sh@08706c6d3 (the v0.1.06
release-cut commit). Each row carries the full builder contract and
references the skill's known-issues register as the source of truth.
Rows added under Phase 5.P (Docker / Packaging):
- P1/small Install isolation: GORMES_BIN_DIR is an authoritative
sandbox boundary
(fixes iso-bin-hijack — sandbox install hijacks production
~/.local/bin/gormes symlink despite GORMES_BIN_DIR being
set to a sandbox path)
- P2/small Install isolation: skip shell-rc PATH write when bin dir
is under /tmp
(fixes iso-shellrc-leak — sandbox install permanently
writes PATH lines to ~/.bashrc / ~/.profile from sandbox
paths that dangle when /tmp is reaped)
blocked_by: iso-bin-hijack row (shares sandbox-detection
helper)
- P2/small Install transcript: only print systemd block when unit
file actually written
(fixes msg-systemd-fiction — install transcript
unconditionally announces "systemd user service installed"
even when no unit file exists)
All three rows are provenance.origin_type=gormes (install.sh is
gormes-owned, not a Hermes port). Each acceptance contract pins the
fix to a Go integration test under internal/installtest/ that execs
install.sh in a temp HOME with isolated PATH and asserts on
post-state diffs. Tests must shim systemctl so outcomes are
deterministic regardless of host systemd availability.
Validated:
go run ./cmd/progress write ok
go run ./cmd/progress validate validated 8 phases
go test ./internal/progress ok 0.736s
git diff --check ok
* docs: retract msg-systemd-fiction install issue (verification error)
When investigating row 5.P "Install transcript: only print systemd
block when unit file actually written" for a TDD fix, found the
underlying bug does not exist. install.sh's gating
if has systemctl && systemctl --user >/dev/null 2>&1; then
install_systemd_user_service
fi
already correctly conditions the unit-file write and the transcript
block on systemd availability. The unit IS written
(~/.config/systemd/user/gormes-gateway.service exists and
`systemctl --user is-enabled gormes-gateway` reports `enabled`).
Root cause of the original false positive: the gormes-install pass
on 2026-05-07T17:27Z verified "no systemd unit installed" by running
`systemctl --user list-unit-files 'gormes*'` and reading
"0 unit files listed" as ground truth. That command can transiently
miss a unit immediately after `daemon-reload` until systemd re-scans.
A single negative result is not authoritative.
Changes
- Withdraw progress.json row 5.P "Install transcript: only print
systemd block when unit file actually written" (P2). 5.P item count
goes from 9 back to 8. The two remaining install-isolation rows
(iso-bin-hijack P1, iso-shellrc-leak P2) are real and stay.
- Move msg-systemd-fiction in
webpages/docs/development-skills/gormes-install/references/known-issues.md
from "Open Issues" to a new "Withdrawn (False Positives)" section
with the full retraction context, root cause, and the verification
lesson learned.
- Tighten the gormes-install SKILL.md pre-state capture step to
require THREE independent signals when checking systemd unit
presence (file existence + is-enabled + list-unit-files without a
glob pattern), so future passes do not repeat the misdiagnosis.
- Update test-recipes.md pre/post-state snapshot scripts to use the
three-signal pattern instead of the misleading single
`list-unit-files 'gormes*'` query.
Validated:
python3 quick_validate.py gormes-install Skill is valid!
go run ./cmd/progress validate validated 8 phases
go test ./internal/progress -count=1 ok 0.770s
git diff --check ok
Trust-but-verify lesson preserved in the skill's known-issues.md so
future install passes start from corrected ground truth, not from
the original mistaken evidence.
* fix(install): respect GORMES_BIN_DIR/GORMES_PREFIX as sandbox boundary
Closes iso-bin-hijack from gormes-install pass on 2026-05-07.
Before: install.sh's update_active_command() ran unconditionally after
publishing the binary. It walked `which -a gormes` plus ~/.local/bin/gormes
and ~/go/bin/gormes, replacing every other gormes symlink it found on
PATH with one pointing at the just-installed sandbox build. After /tmp
reaping, the production ~/.local/bin/gormes symlink dangled.
After: when GORMES_BIN_DIR or GORMES_PREFIX is set, the operator has
declared a sandbox boundary. update_active_command() now early-returns
with `skipping active PATH command update (sandbox bin dir set ...)`.
print_install_plan_body() and print_verbose_plan() surface the decision
as `update_active_path_command: skipped|yes` so dry-run plans expose the
choice.
Test: internal/installtest/iso_bin_dir_test.go covers four cases via
fast `--dry-run` plan inspection (no git clone, no go build):
GORMES_BIN_DIR skips, GORMES_PREFIX skips, default still updates,
verbose surfaces the reason. End-to-end manual verification on
2026-05-07 confirmed a real sandbox install with GORMES_BIN_DIR set
leaves the production ~/.local/bin/gormes symlink target unchanged.
Implements progress.json row 5.P "Install isolation: GORMES_BIN_DIR is
an authoritative sandbox boundary". known-issues.md entry updated to
fixed-in-2026-05-07.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ci): align deploy-gormes-www asserts with methodology-first landing
The Deploy gormes.ai workflow's post-build verify step was failing on
the v0.1.06 release commit (run 25511450496) because it asserted hero
strings from before the 8.B landing rewrite. The page builds fine; only
the asserts were stale.
Updates:
- Replace stale positive asserts with current strings:
"AI agent runtime in one Go binary." (hero h1)
"An autonomous engineering loop ports Hermes to Go, every day." (methodology h2)
- Add new positive asserts that lock in the 8.B pivot so a regression
to the old pre-pivot hero gets caught:
"HOW IT IS BUILT" (methodology kicker)
"Validated rows shipped" (methodology metrics block)
- Move the now-stale hero string to the negative-assert block:
"Run AI agents from one Go binary."
"Gormes runs local agent sessions, provider turns, memory, dashboards, and chat gateways from one Go binary."
Also picks up the website install.sh mirror refresh (now includes the
iso-bin-hijack sandbox-bin-dir fix from a7116c11e) and the daily
benchmarks rebuild.
Local verification: every positive asserts grep-matches the current
dist/index.html; every negative asserts grep-misses it.
Closes the red Deploy gormes.ai run from the v0.1.06 merge commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(install): close iso-shellrc-leak and iso-systemd-hijack
Two more sandbox-isolation bugs discovered by the gormes-install pass on
2026-05-07. Both have the same shape as iso-bin-hijack and the same fix
shape: gate on the existing sandbox_bin_dir_set helper.
iso-shellrc-leak (P2):
Before: ensure_path_in_shell_config() unconditionally appended
"export PATH=/tmp/gormes-install-test/<ts>/bin:$PATH" lines to ~/.bashrc,
~/.profile, ~/.zshrc, or fish config. After /tmp reaping, every login
shell carried a dangling PATH entry the operator had to sed out by hand.
After: ensure_path_in_shell_config() early-returns with
PATH_CONFIG_RESULT=sandbox_skipped when sandbox_bin_dir_set is true,
after exporting the bin dir into the current install run's PATH (so
downstream verification still works). Logs the boundary decision.
iso-systemd-hijack (P0):
Before: print_service_instructions() unconditionally rewrote the
production user systemd unit ~/.config/systemd/user/gormes-gateway.service
with ExecStart pointing at /tmp/gormes-install-test/<ts>/home/bin/gormes
and Environment=GORMES_HOME=/tmp/gormes-install-test/<ts>/home. After
the next reboot or /tmp reap, the operator's gormes-gateway service
fails to start because its binary path no longer exists. Worse than
iso-bin-hijack: failure is invisible until the operator tries to use
the gateway. Same surface on macOS via the launchd plist.
After: print_service_instructions() early-returns when
sandbox_bin_dir_set is true, with a log line naming both
~/.config/systemd/user/ and ~/Library/LaunchAgents/. Plan emitters
surface install_system_service: skipped|yes.
Plan output (print_install_plan_body and print_verbose_plan) now
exposes all three boundary decisions:
- update_active_path_command: skipped|yes
- edit_shell_rc_files: skipped|yes
- install_system_service: skipped|yes
Tests: 6 new dry-run plan tests across iso_shellrc_test.go and
iso_systemd_dir_test.go (skipped GORMES_BIN_DIR, skipped GORMES_PREFIX,
default-yes regression fence for each surface).
End-to-end verification on 2026-05-07: real sandbox install with
GORMES_BIN_DIR set left ~/.bashrc and ~/.profile gormes-line counts
byte-identical and ~/.config/systemd/user/gormes-gateway.service sha256
byte-identical.
Implements progress.json rows:
- 5.P "Install isolation: skip shell-rc PATH write when bin dir is under /tmp" (note: shipped fix uses sandbox_bin_dir_set boundary, not the originally-planned bin-dir-under-/tmp heuristic)
- 5.P "Install isolation: skip system service install when sandbox bin dir is set" (new row, P0)
known-issues.md entries updated to fixed-in-2026-05-07.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add loop $/iteration cost metric with --cost-report subcommand
* docs: unblock P0 5.J TOCTOU row, complete P1 8.F cost metric, regenerate progress surfaces
* chore: gitignore scheduled tasks lock file
* feat(security): close auth.json TOCTOU window, add redaction default-on contract
Use tools.AtomicReplace (tempfile -> fsync -> rename) in
writeCredentialPoolAuthStore instead of raw os.WriteFile to
prevent concurrent readers from observing partially-written
auth.json. New internal/redaction package provides
RedactionConfig with default-on contract (Enabled:true) and
explicit operator opt-out via Enabled:false.
* docs: mark P0 TOCTOU row complete, sharpen Docker umbrella, add gateway auto-resume row
Parity sweep + planner pass:
- P0 5.J TOCTOU row: contract_status validated, then marked complete
- 5.B Docker: split inventory umbrella into concrete P1 builder row
- 5.N: new P2 gateway auto-resume row from Hermes v0.13.0
- Regenerate all progress-derived docs and site data
* feat: gateway auto-resume on restart recovers interrupted sessions
TDD landed autoResumePendingSessions in Manager.Run: on gateway
startup, scans session metadata for ResumePending sessions, injects
synthetic empty-text submit events for sessions with registered
channels, and marks orphaned sessions as non-resumable with
adapter_not_ready evidence.
Five fixture-backed tests prove: interrupted session recovery,
orphaned session terminated, startup resilience, channel-neutral
behavior (telegram/slack/discord), and session-boundary hook
preservation. Added NonResumableAdapterNotReady constant and
ManagerConfig.SkipAutoResume for test isolation.
* docs: parity sweep cleanup + gateway auto-resume row complete
- Cleaned 3 stale needs_human planner verdicts on completed rows
- Added P2 Brave Search + DDGS web search provider parity row (5.C)
- Marked Gateway auto-resume on restart complete with evidence
- Regenerated all derived progress surfaces
* chore: update hermes-agent submodule pointer
* feat(kanban): worker heartbeat, zombie reclaim, unified failure counter, auto-block, darwin detection
Implement Kanban worker heartbeat extension (extends claim_expires by
heartbeatTTL), stale-heartbeat zombie detection and reclaim with retry
budget, unified failure counter across spawn/timeout/crash outcomes,
auto-block on incomplete worker exit, and darwin PID-state zombie
detection via syscall.Kill (cross-platform stub on other GOOS).
TDD coverage: 8 acceptance tests over in-memory SQLite with fake clock.
Mirrors Hermes v0.13.0 PRs #21183, #21214, #20188, #20410.
* docs: mark kanban heartbeat row complete, regenerate progress surfaces, bump hermes submodule
Mark P1 'Kanban worker heartbeat, reclaim, and zombie detection' row
complete with TDD evidence. Regenerate all derived progress docs via
'go run ./cmd/progress write'. Bump hermes-agent submodule to
cff821e2d (upstream main from parity sweep).
* feat(tools): Docker execution backend with mount policy, env filtering, and fake-client tests
* docs: regenerate progress surfaces from parity sweep and Docker row, bump hermes submodule
* feat(install): default to release binary fetch instead of source build
curl https://gormes.ai/install.sh | bash now completes in ~2 seconds via
signed binary fetch from GitHub Releases instead of ~2-5 minutes via Go
toolchain download + git clone + go build. The slow source-build path
was the only install method, even though v0.1.06 already publishes 18
release assets (linux/darwin/windows × amd64/arm64 .tar.gz + .sha256 +
SBOM + build provenance attestations).
What's added:
- release_platform_arch() — maps uname -s/-m to a release-asset slug
(linux-amd64, linux-arm64, darwin-amd64, darwin-arm64). Returns
empty for unsupported platforms.
- decide_install_method() — 5-rule precedence picks binary-fetch or
source-build at parse time so plan emitters can declare it:
1. --local → source-build (operator wants their working tree)
2. --from-source / GORMES_INSTALL_FROM_SOURCE=1 → source-build
3. --branch != main → source-build (release binaries are only
published from main)
4. unsupported platform → source-build (graceful)
5. otherwise → binary-fetch (the new fast path)
- fetch_release_binary() — GitHub API resolves the latest tag, curl
or wget downloads gormes-<v>-<arch>.tar.gz + .sha256, sha256sum or
shasum -a 256 verifies, tar -xzf extracts, mv installs to
managed_bin_dir. Any failure (network, missing asset, hash
mismatch, missing tools) triggers a clear log line and falls back
to source-build so installs still succeed in restricted environments.
- Plan emitters now declare:
- install_method: binary-fetch (linux-amd64 from latest release...)
OR source-build (--from-source flag set | unsupported platform | ...)
- source: github releases | managed git checkout | <local path>
Verbose plan also emits source_mode, release_arch, release_api so
operators can audit the network call before running real install.
End-to-end verification on Linux/amd64: a fresh sandbox install with
GORMES_BIN_DIR set completed in 1.832s wall, with Go never invoked
(grep -c 'Checking Go' = 0), exit=0, and `gormes version` reporting
0.1.06 from the published release.
Tests: 5 new dry-run plan tests in internal/installtest/install_method_test.go
covering the default binary-fetch path, --from-source override, env-var
override, non-default-branch fallback, and verbose plan details.
Implements progress.json row 5.P "Install: prefer pre-built release
binary over source build by default". Closes the binary-fetch coverage
gap noted in webpages/docs/development-skills/gormes-install/references/test-recipes.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(setup): prettify wizard with framed headers, screen clearing, and color
The fresh-install setup wizard now matches Hermes' UX polish: each section
clears the prior screen, renders a Hermes-style framed header, and uses
color/bold to highlight the active selection.
Source: 2026-05-07 fresh-Fedora install transcript from operator. The
operator-visible flow was previously a Spartan stack of plain-text prompts
and a 47-line provider list with no visual hierarchy.
What's added:
- internal/cli/wizard_ui.go — TTY-gated styling helpers:
- ClearScreen(io.Writer) emits ANSI clear+home only on a TTY and only
when GORMES_NO_CLEAR_SCREEN is not opted out.
- Bold/Dim/Cyan/BrightCyan/Yellow/Green wrap text in ANSI escapes only
when the writer is a TTY and NO_COLOR is not set (no-color.org).
- PrintHeader emits a Hermes-style ╭──╮│ title │╰──╯ box with width
clamp 32-60 cols.
- PrintSectionDivider emits a 60-char dim horizontal rule.
- internal/cli/wizard_ui_test.go — 7 unit tests proving:
- ClearScreen is a no-op on non-TTY writers (critical for piped
transcripts and CI logs).
- Color helpers pass through plain text on non-TTY and under NO_COLOR.
- PrintHeader renders the framed title even without ANSI on non-TTY.
- GORMES_NO_CLEAR_SCREEN opt-out blocks the screen clear.
Wired into:
- cmd/gormes/setup.go — runSetupFirstTimeChoice ("How would you like to
set up Gormes?"), runSetupQuick, runSetupProviderSection,
runSetupModelSection, printSetupTopLevelMenu all now ClearScreen +
PrintHeader at section entry. Active menu option (the default) is
rendered in bright-cyan ` → (●)` + bold label; inactive options use
dim `(○)` markers.
- cmd/gormes/model.go — promptProviderChoice ClearScreen + PrintHeader
("Choose a provider") + colored markers: yellow `*` for the default
provider, bright-cyan number + bold label, dim numbers + auth-type
tag for the rest. The 47-provider list now visually scans top-down
with the default provider standing out.
Existing test contract preserved: every Setup/Model test still asserts
on `strings.Contains` of the literal section names, and PrintHeader
emits the title verbatim within the box so those checks still pass.
Visually verified under `script -qfc` (faked TTY): screen clears
between sections, framed bright-cyan headers render with bold titles,
selection markers are colored, NO_COLOR=1 strips all escapes cleanly,
and pipe redirection (e.g., for log capture) emits plain text.
Note: this fix lands on main, but fresh `curl ... | bash` operators
will only see the prettified wizard after v0.1.07 cuts (install.sh's
binary-fetch path downloads the latest release binary, not main HEAD).
Operators can opt into source-build for immediate access via
`curl ... | bash --from-source` or GORMES_INSTALL_FROM_SOURCE=1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add MCP channels_list tool with ChannelDirectoryProvider seam
Implements Hermes MCP channels_list tool (#21474 fix) in Go-native form:
- ChannelDirectoryProvider interface for reading platform channel data
- channelsListHandler reads from Platforms map, returns id/name/chat_id/enabled/platform per channel
- Platform filter support via optional 'platform' argument
- Degraded-mode error when directory unavailable
- Registered in RegisterDefaultTools alongside existing MCP tools
* docs: complete MCP channels_list row, elevate to P1, sharpen 4 umbrella rows
Parity sweep follow-up:
- MCP channels_list tool: status=complete with evidence
- Elevated priority from P2 to P1 (unblocked, validated contract)
- Added no_test_required to 4 umbrella rows: 61-tool registry port,
Atomic checkpoints, 49-file CLI tree port, Config/profile/auth/setup
- Regenerated all progress-driven docs and site data
* feat: complete Brave Search + DDGS web search provider parity (P1 row closure)
- Add TestBraveProvider_DegradedWhenNoKey acceptance test
- Mark Brave Search + DDGS row complete in progress.json
- All acceptance criteria covered: Brave API search, DuckDuckGo search,
backend matrix resolution, degraded-mode when key missing
- Implementation in internal/tools/web_tools.go as part of rows 5.C[6]/5.C[7]
- Reprioritized P2→P1 to match upstream Hermes v0.13.0 parity demand
* feat: complete Sandbox isolation depth selection row (P3) with config loader and TDD fixtures
* docs: mark Sandbox isolation depth selection complete, regenerate progress surfaces
* chore: track upstream hermes-agent (author map + UV_NO_CONFIG fix)
* feat(update): structured progress UX with banner, glyphs, and summary
`gormes update` previously emitted Spartan output that operators struggled
to scan:
update branch: main
update_check checked update readiness for main
It now matches the Hermes-style cadence:
⚕ Updating Gormes Agent...
update branch: main
ℹ update_check checked update readiness for main
✓ Update complete!
What's added:
- Bold `⚕ Updating Gormes Agent...` banner at the top so the operator
immediately sees what's happening.
- Per-evidence glyph + color via `updateGlyphAndColor`:
- `*_failed`, `*_error` → ✗ (bold)
- `*_unavailable`, `*_timeout` → ⚠ (yellow)
- `update_check`, `*_log_mirrored`, `update_not_managed_checkout` → ℹ (dim)
- default → ✓ (green)
- Final `✓ Update complete!` (green+bold) on success or `✗ Update failed`
(bold) on failure. Operator recovery still routes to stderr.
- Dim `update branch:` / `previous branch:` labels so the values stand out.
Backward compatibility: every UpdateEvidenceKind string still appears
verbatim in stdout so downstream parsers and existing tests that grep for
`update_*` kinds keep working. Verified by
TestUpdateCommand_PreservesEvidenceKindsForMachineReadability.
Sandbox safety: the cli.* color/style helpers no-op on non-TTY writers
(bytes.Buffer in tests, pipes/redirects in real use) and under NO_COLOR=1
so transcript captures and CI logs stay clean. Verified by
TestUpdateCommand_NoColorStripsAnsi.
6 new tests in cmd/gormes/update_progress_ui_test.go cover banner ordering,
success summary, failure summary + recovery routing, evidence-kind
backward compat, glyph-by-class mapping, and NO_COLOR strip.
Implements the first row from the gormes-update parity batch (the audit
agent's recommended #1, "structured progress UX"). Reuses the wizard_ui.go
helpers shipped in e7f492211 — same vocabulary across `gormes setup` and
`gormes update`. Unblocks the 5 remaining gormes-update parity rows
(skill sync, profile fan-out, web build, pre-update backup, config
migration prompt) which all build on this transcript shape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(update): wire pre-update backup policy decision into structured progress
`gormes update` now exposes the operator-explicit pre-update backup choice
through the structured progress UX. The actual backup writer (zip
creation, size/duration reporting, retention) is the next slice; this row
ships the FLAG/DECISION surface so the wiring lands first.
What's added:
- `--backup` flag opts into a single-run pre-update backup of ~/.gormes.
- `--no-backup` flag force-skips the backup; beats both `--backup` and
the future config-level opt-in (matches Hermes' precedence).
- `UpdateLifecycleOptions.Backup`, `NoBackup`, `BackupConfigEnabled`
threaded through from cobra to RunUpdateLifecycle.
- New evidence kinds:
- `update_pre_backup_skipped` (--no-backup or default-skip-with-config)
- `update_pre_backup_requested` (--backup or config-enabled)
- `emitPreUpdateBackupPolicy` runs BEFORE any git mutation and resolves
via the existing ResolveBackupPolicy helper from
internal/cli/backup_policy.go, so a future writer slice can wire
behind the same trigger without re-deriving precedence.
- Glyph mapping in cmd/gormes/update.go extended:
- `*_skipped` → ℹ (dim)
- `*_requested` → ◆ (bright cyan, mirrors Hermes' "◆ Creating
pre-update backup..." marker)
Silent-default contract: when neither --backup nor --no-backup is set
and BackupConfigEnabled is false, NO backup-related evidence is emitted.
Most operators don't need to hear about the skipped backup on every
update run (parity with Hermes' default).
Tests:
- internal/cli/update_lifecycle_backup_test.go — 5 lifecycle tests:
- NoBackupFlag emits skipped evidence with backup_disabled_by_flag reason
- BackupFlag emits requested evidence with backup_forced reason +
explicit "writer not yet implemented" detail (so operators don't
expect a backup file to exist)
- NoBackupBeatsBackup precedence rule
- DefaultEmitsNoBackupEvidence (silent-default contract)
- PreBackupRunsBeforeGitMutation (ordering is the contract for the
follow-up writer slice — a backup taken after pull is useless for
rollback)
- cmd/gormes/update_progress_ui_test.go — 2 UI tests:
- BackupFlagFlowsToLifecycle proves cobra→options plumbing
- PreBackupGlyphs proves ℹ for skipped, ◆ for requested
Implements row #2 from the gormes-update parity batch (audit agent's
recommended order). Reuses ResolveBackupPolicy and the structured
progress UX from c83d10e77. Unblocks a follow-up writer slice that can
wire the actual backup file creation behind the existing
update_pre_backup_requested trigger without re-deriving the precedence
rules.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(navivox): render tool-call artifacts in chat tiles
Extend the chat _ToolCallBody to list each NavivoxToolArtifact below the
tool-call summary with an attachment icon, kind label, title, and optional
artifact summary line. The artifact data was already populated by the
SshNavivoxChannel; this just surfaces it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(progress): add gateway whitelist parity row
Track Hermes' allowed_chats/channels/rooms whitelist parity for Telegram,
Slack, Discord, Mattermost, Matrix, and DingTalk as a P1 planned slice.
Sources cite Hermes 69d025e4a (Telegram/Mattermost/Matrix/DingTalk),
cd3ef685c (Slack), and PR #7044 (Discord). Generated docs and site
mirrors regenerated to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: sync install.sh mirror to source
Regenerate webpages/landing/public/install.sh to match root install.sh
which was updated to default to release binary fetch instead of source
build (commit 044cd264d). The mirror had drifted one commit behind.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(update): wire bundled-skill profile sync into update lifecycle
`gormes update` now runs the existing internal/skills.SyncBundledSkillsToProfiles
helper after a successful pull and renders Hermes-parity counts in the
structured progress UX. Skill sync is best-effort: errors emit
update_skill_sync_failed evidence but never fail the overall update.
What's added:
- internal/cli SkillSyncRunner type — abstract seam decoupled from
internal/skills (the lifecycle package stays import-free; the cmd-side
adapter does the conversion).
- internal/cli SkillSyncResult + SkillSyncProfileResult types — mirror
the skills helper's per-profile counts (Added, Unchanged, Conflicts,
Failed) without coupling.
- internal/cli emitSkillSync helper runs after pull but BEFORE gateway
restart so the gateway can pick up newly-bundled skills on its
restart cycle.
- formatSkillSyncSummary renders Hermes-parity:
`default: +5 new, 12 unchanged, 1 user-modified (kept)`
with zero-count buckets omitted to keep the transcript short.
- Two new evidence kinds: update_skill_sync_completed (per profile),
update_skill_sync_failed (when seam returns an error).
- updateCommandSeams.SkillSyncFor — injectable factory; default builds
the production adapter that calls SyncBundledSkillsToProfiles against
`<checkout>/skills` and the active profile root from config.GormesHome.
Silent-default contract preserved: when the seam is nil (the case for
non-managed checkouts where bundled skills aren't applicable), no
update_skill_sync_* evidence is emitted. Same shape as the pre-update
backup silent-default from 56efc4042.
Tests:
- internal/cli/update_lifecycle_skill_sync_test.go (4 lifecycle tests):
- NilSkillSync emits no evidence (silent default contract)
- SkillSyncSuccess emits one completed evidence per profile with
correct count strings ("+5 new", "user-modified")
- SkillSyncFailure emits failed evidence with error message AND the
update still returns success (best-effort contract)
- SkillSyncRunsAfterPull verifies the ordering invariant
- cmd/gormes/update_progress_ui_test.go (3 cmd tests):
- SkillSyncSeamWiredByDefault proves the default adapter wires when
checkout/skills exists and GORMES_HOME is set
- SkillSyncSeamNilWhenSkillsAbsent proves silent-default for
non-managed checkouts
- SkillSyncGlyphs proves ✓ for completed, ✗ for failed in the
structured progress UX
Implements row #3 from the gormes-update parity batch (audit agent's
recommended order). Reuses the structured progress UX from c83d10e77
and the silent-default pattern from 56efc4042. Real adapter calls the
existing SyncBundledSkillsToProfiles helper from internal/skills (which
was already row-complete from prior planner work).
Owned divergence vs Hermes:
- Multi-profile fan-out: only the `default` profile is synced today.
Named-profile discovery is a follow-up slice (parity row exists).
- "↑ updated" counts: helper does not distinguish updated-from-source
vs unchanged. Counts surface as Added/Unchanged only.
- "− removed from manifest" counts: helper does not track removals
from the bundled tree. Same follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(update): wire web UI rebuild step into update lifecycle
`gormes update` now rebuilds the web UI bundle after pull when a
`<checkout>/web/package.json` exists. Best-effort: failures emit
update_web_build_failed evidence but never fail the overall update
(matches Hermes' soft-failure contract — only `hermes web` treats a
build error as fatal).
What's added:
- internal/cli WebBuildRunner + WebBuildResult types (parallel to
SkillSyncRunner pattern, decoupled from os/exec).
- 4 new evidence kinds:
- update_web_build_completed → ✓ green (success)
- update_web_build_skipped → ℹ dim (--skip-web or no package.json)
- update_web_build_unavailable → ⚠ yellow (npm not on PATH)
- update_web_build_failed → ✗ bold (npm install / npm run build
non-zero exit)
- internal/cli emitWebBuild helper runs after skill sync and maps the
WebBuildResult to the right evidence kind based on Skipped/Unavailable
flags or error.
- cmd/gormes --skip-web flag for operator opt-out.
- updateCommandSeams.WebBuildFor — injectable factory; default builds
the production adapter that runs `npm install --silent` then
`npm run build` in `<checkoutDir>/web`.
Silent-default contract preserved: when the factory returns nil (no
web/package.json in checkout), the lifecycle emits no web_build_*
evidence at all. Most non-managed checkouts and runtimes without a
web/ tree never see the feature.
Tests:
- internal/cli/update_lifecycle_web_build_test.go (5 lifecycle tests):
- NilWebBuild emits no evidence (silent-default contract)
- WebBuildCompleted emits completed evidence with seam Detail
- WebBuildSkipped emits skipped evidence with seam Reason
- WebBuildUnavailable emits unavailable evidence with seam Reason
- WebBuildFailure emits failed evidence + update still returns success
- cmd/gormes/update_progress_ui_test.go (4 cmd tests):
- WebBuildFactoryNilWhenNoPackageJson silent-default
- WebBuildFactoryWiredWhenPackageJsonPresent factory wires runner
- WebBuildSkipFlagShortCircuitsRunner --skip-web returns Skipped
without invoking npm
- WebBuildGlyphs verifies all 4 evidence kinds map to the right
structured-progress glyphs
Implements row #5 from the gormes-update parity batch (audit agent's
recommended order — #4 goncho sync was deferred per the audit's "if
internal/goncho profile-sync surface does not exist yet, P2 is fine"
caveat; gormes/internal/goncho has no profile-sync surface today).
Reuses the structured progress UX from c83d10e77 and the
silent-default + best-effort patterns from 56efc4042 + f30f72c25.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: gateway allowed_chats/channels/rooms whitelist parity
Add shared WhitelistConfig + IsAllowed + ParseWhitelistConfig in
internal/gateway/whitelist.go with 8 focused TDD fixtures. Extend
TelegramCfg and SlackCfg with AllowedChats/AllowedChannels list config
fields plus accessor methods and env-var parsing. Wire whitelist
filtering into gateway Manager.allowed() check.
Ports Hermes v0.13.0 whitelist feature (69d025e4a + cd3ef685c) across
Telegram, Slack, and Discord platforms. Per-platform adapter wiring is
follow-up child rows.
* docs(progress): mark gateway whitelist row complete, regenerate progress surfaces
* feat(navivox): show selected agent indicator chip in chat AppBar
* chore: bump hermes-agent submodule
Advance hermes-agent from 7f369bfe5 to 7d66d30d7. Upstream picks up
TUI /sessions slash command, personality switch session preservation,
sessions+skills menu merge, personality fix merge, and kanban dashboard
tooltips.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(update): wire config schema migration prompt into update lifecycle
`gormes update` now checks the on-disk config schema version after the
web build step. When the version is outdated:
- With --yes: auto-applies via internal/config.MigrateConfigFile and
emits ✓ update_config_migrate_completed.
- Without --yes: emits ⚠ update_config_migrate_needed advisory pointing
the operator at `gormes config migrate` (or rerun with --yes).
When the config is already current, no evidence is emitted (silent
default — no nag on every update). Best-effort: errors from either the
check or migrate seam emit ✗ update_config_migrate_failed but never
fail the overall update.
What's added:
- internal/cli ConfigCheckRunner + ConfigMigrateRunner seam types
(parallel to SkillSyncRunner / WebBuildRunner pattern; decoupled from
internal/config so the lifecycle stays import-free).
- internal/cli ConfigVersionResult struct mirroring CheckReport.
- 3 new evidence kinds:
- update_config_migrate_completed → ✓ (auto-applied)
- update_config_migrate_needed → ⚠ (operator action required)
- update_config_migrate_failed → ✗ (check or migrate error)
- internal/cli emitConfigMigrate helper with 7-branch decision table
documented inline. Runs after web build, before gateway restart.
- cmd/gormes default adapters wrap internal/config.Check and
internal/config.MigrateConfigFile into the seam shape.
- updateGlyphAndColor extended: `*_needed` suffix → ⚠ (yellow,
operator-action-required category).
Tests:
- internal/cli/update_lifecycle_config_migrate_test.go (6 lifecycle tests):
- NilConfigCheck silent default
- ConfigAlreadyCurrent silent (no nag)
- ConfigOutdatedWithoutYes emits needed + does NOT call migrate
- ConfigOutdatedWithYes auto-applies + emits completed
- ConfigMigrateError emits failed + update still succeeds
- ConfigCheckError emits failed + does NOT attempt migrate
- cmd/gormes/update_progress_ui_test.go ConfigMigrateGlyphs verifies
✓/⚠/✗ for the 3 new kinds.
Implements row #6 from the gormes-update parity batch (audit agent's
recommended order). Reuses the structured progress UX from c83d10e77
and the silent-default + best-effort patterns established by 56efc4042
(backup), f30f72c25 (skill sync), and fa4a10d00 (web build).
Owned divergence vs Hermes' richer prompt:
- Interactive y/n at the prompt is intentionally not in this slice.
Hermes' interactive flow would require a stdin reader seam and more
branching. The slice ships --yes auto-apply + advisory-when-not, and
the operator interactive path remains owned by the existing
`gormes config migrate` command.
- Per-bucket missing_env / missing_config counts (Hermes' "⚠️ N
required setting(s) need configuration") are not in this slice.
CheckReport's Issues field carries them but the slice surfaces only
version-skew. Detailed breakdown is a follow-up if operators ask.
Audit batch progress: 5 of 6 update-parity rows shipped (structured
UX, pre-update backup, skill sync, web build, config migrate).
Remaining: goncho sync (#4) — deferred until internal/goncho gains a
profile-sync surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(navivox): risk-aware approval banner badge
Replace the plain "Risk: $risk" text with a labeled badge: "High risk"
gets a warning icon, "Medium risk" / "Low risk" show a label, and unknown
or null risk renders no badge. The risk-aware badge makes high-risk
approvals scannable at a glance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(strategy): ratify v1 differentiator and bump release-pipeline rows to P1
Add docs/content/building-gormes/strategy/v1-differentiator.md with the
ratified-on 2026-05-07 differentiator paragraph, 30-skill curated list,
and exclusion list. Promote release-pipeline / WhatsApp Baileys /
Signal-transport / Matrix-seam rows to P1/P2 priorities.
Repair a trailing-comma JSON syntax error introduced by the planning
note. Generated docs and site mirrors regenerated to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: bump version to 0.1.07
Sync cmd/gormes/version.go and webpages/landing/src/data/release.json.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: sync CHANGELOG.md with v0.1.07 release entries
* docs: add Hermes-style v0.1.07 release notes
The Operator-First Release. ~735 commits since v0.1.06.
Highlights:
- install.sh defaults to release-binary fetch (~7x faster fresh installs)
- Setup wizard prettified (framed headers, screen clear, color)
- gormes update parity: 5 of 6 audit-batch rows shipped (structured
progress UX, pre-update backup, skill sync, web build, config migrate)
- Install isolation: iso-shellrc-leak + iso-systemd-hijack closed
- Repaired red Deploy gormes.ai workflow on main
- Loop \$/iteration cost metric
Same operating day as v0.1.06; date alias v2026.5.7 is shared.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: vendored WhatsApp Baileys bridge and removed QR pairing blocker
Vendored the Hermes-compatible Baileys bridge into scripts/whatsapp-bridge/ with provenance notice. Removed BLOCKER from preflight output. All WhatsApp tests pass.
* docs: parity sweep, agent lifecycle hooks row, WhatsApp QR closure
Bounded all-topic parity sweep across CLI/TUI, provider/auth, gateway/channels, tools, sessions/memory/Goncho, install/runtime, browser, docs, and release surfaces. Added agent lifecycle hooks (agent:start/step/end) row to Phase 5.O. Marked WhatsApp live Baileys QR pairing wizard complete. Bumped hermes-agent submodule to current upstream main (307c85e5c).
* feat(update): implement pre-update backup writer (zip of ~/.gormes)
Closes the writer-not-yet-implemented deferral from 56efc4042. When
--backup is set AND the writer seam is wired (the production default),
gormes update now creates a real zip archive of the operator's
~/.gormes before any git mutation.
What's added:
- internal/cli WriteBackupZip(ctx, sourceDir, destPath) (BackupResult, error)
- Walks sourceDir with filepath.WalkDir
- Skips paths matching IsExcludedFromBackup (checkpoints/, backups/,
*.db-wal, *.db-shm, *.db-journal)
- Streams to destPath.tmp first, renames on success (atomic)
- Returns Path, SizeBytes (final archive byte count), DurationMs (wall)
- internal/cli BackupResult struct + BackupWriter seam type
- 2 new evidence kinds:
- update_pre_backup_completed → ✓ green
- update_pre_backup_failed → ✗ bold
- emitPreUpdateBackupPolicy now invokes the writer when policy resolves
to Requested AND BackupWriter seam is non-nil; fallback (nil seam)
preserves the prior policy-only deferral evidence so existing tests
don't regress.
- formatBackupSize / formatBackupDuration render human-readable size
(B/KB/MB/GB) and duration (Nms or N.NNs) inline in evidence detail.
- backup_policy.go IsExcludedFromBackup now skips `backups/` subtree
(so subsequent backups don't include all prior backups, growing
geometrically).
- cmd/gormes defaultBackupWriterFor wires WriteBackupZip against
config.GormesHome with destPath = `<home>/backups/pre-update-<UTC>.zip`.
Tests:
- internal/cli/backup_writer_test.go (3 unit tests):
- IncludesPlainFilesExcludesSidecars verifies the walk picks up
config.toml + auth.json + nested/dir/skill.md but skips
checkpoints/snap.bin + log.db-{wal,shm,journal}
- AtomicRenameOnSuccessNoTmpLeak verifies no .tmp leftovers
- RejectsEmptyArgs guards misconfigured callers
- internal/cli/update_lifecycle_backup_writer_test.go (5 lifecycle tests):
- BackupRequestedNilWriter keeps the deferral evidence (backward
compat with the policy-only slice)
- BackupWriterSuccess emits completed evidence with path + size + duration
- BackupWriterFailure emits failed + update still succeeds (best-effort)
- BackupWriterNotInvokedWhenNoBackup proves --no-backup short-circuits
- BackupSizeFormatting covers B/KB/MB/GB scaling
End-to-end visual proof on a sandbox HOME:
⚕ Updating Gormes Agent...
update branch: main
✓ update_pre_backup_completed /tmp/.gormes/backups/pre-update-20260508T012115Z.zip (329B, 10ms)
Real backup file written: 329 bytes in 10ms. Future evolution: retention
pruning (keep last N), ConfigEnabled wiring from real config (currently
flag-driven only), per-bucket size summary in detail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: agent lifecycle hooks (agent:start, step, end) with Kernel callback
Adds HookAgentStart/HookAgentStep/HookAgentEnd hook point constants and
AgentLifecycleHook callback to Kernel Config, firing at turn start, after
each tool iteration, and on all turn exit paths. Matches Hermes'
gateway/hooks.py lifecycle event dispatch pattern.
* docs: mark agent lifecycle hooks complete with evidence and sources
Updates progress.json row from planned to complete with validated contract,
Hermes source line references, implementation evidence, and test coverage.
Removes the row from agent-queue and next-slices. Regenerates mirror
progress.json copies for landing and go-renderer sites.
* chore: bump hermes-agent submodule for hooks.py lifecycle parity
Pulls upstream hermes-agent to faa13e49f for verified hook event dispatch
line references used in agent lifecycle hooks contract validation.
* flutter: Navivox key store providers and keys screen update
Adds Riverpod-based key store providers (identityStoreProvider,
serverStoreProvider) with stream-based watch pattern. Updates KeysScreen
to ConsumerWidget showing imported servers and identities, with empty
state for no keys.
* feat(update): pre-update backup retention pruning (keep newest 5)
After each successful pre-update backup write, the production adapter
now prunes older backup zips so the directory doesn't grow forever.
Default retention: 5 (matches Hermes' `updates.backup_keep` default).
What's added:
- internal/cli PruneBackups(backupDir, keep) (count, freed, err) helper:
- Filters by `pre-update-*.zip` filename pattern (operator-owned files
in the same directory survive untouched).
- Sorts candidates by mtime, keeps newest `keep`, removes the rest.
- keep <= 0 → no-op safety (operators who pass --backup-keep 0 by
mistake should not lose data).
- Missing directory → no-op (fresh installs with no prior backups).
- Per-file remove errors are silently skipped — pruning is
best-effort and must not block update completion.
- internal/cli BackupResult extended with PrunedCount + PrunedBytes.
- internal/cli emitPreUpdateBackupPolicy detail formatter appends
`; pruned N older (M freed)` only when PrunedCount > 0; the no-prune
common case (first --backup, recently-cleaned state) keeps the
transcript short.
- cmd/gormes defaultBackupWriterFor calls PruneBackups after a
successful WriteBackupZip with keep=defaultBackupKeep (5).
Tests:
- internal/cli/backup_prune_test.go (5 unit tests):
- KeepsNewestN: 5 fixtures with monotonic mtimes, keep=2 → 3 removed,
newest 2 survive.
- NoOpWhenAtOrUnderKeep: 1 file, keep=5 → no-op.
- IgnoresNonBackupFiles: operator's NOTES.md + manifest.json +
other-archive.tar.gz survive a prune that reduces 3 backup files to 1.
- KeepZeroIsNoOpSafety: keep=0 and keep=-1 both no-op.
- MissingDirReturnsNoOp: non-existent dir returns (0, 0, nil).
- internal/cli/update_lifecycle_backup_writer_test.go (2 lifecycle tests):
- BackupCompletedDetailIncludesPruneInfoWhenPositive: PrunedCount=3
surfaces "pruned 3 older" + "freed" in evidence detail.
- BackupCompletedDetailOmitsPruneSuffixWhenZero: PrunedCount=0 emits
no prune phrasing.
End-to-end verification with a sandbox HOME seeded with 6 backup files:
⚕ Updating Gormes Agent...
update branch: main
✓ update_pre_backup_completed /tmp/.gormes/backups/pre-update-20260508T014058Z.zip (329B, 2ms); pruned 2 older (240B freed)
After run: 5 files in backups/ (newest 5 of the 6 seeds + 1 new write,
2 oldest removed) — matches the keep=5 contract exactly.
Future-natural follow-up: wire `updates.backup_keep` from real config
into a configurable retention budget (currently hardcoded to 5).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: plugin lifecycle hook transform_llm_output with TDD fixtures
* docs: mark transform_llm_output complete, unblock 7 parity rows, regenerate surfaces
* feat: gateway allowed_chats whitelist config and update test coverage
* fix(update): survive missing config.toml on fresh install
* feat(signal): add signal-cli HTTP JSON-RPC + SSE bridge bootstrap layer
Implement the fakeable Signal transport/bootstrap layer that bridges
the existing signal.Bot seam to the signal-cli HTTP daemon. Five TDD
acceptance tests cover config/health/lock lifecycle, SSE URL encoding,
attachment fetch params, reconnect/recovery, and outbound send with
typing-stop through a fake HTTP transport.
Progress: Phase 7.A Signal subphase is now fully complete (4/4 rows).
* fix(progress): update Phase 7.A test expectations for completed Signal bootstrap row
* docs: close 6 inert umbrellas (5.O + 5.V), mark Matrix seam complete, regenerate surfaces
* fix: add hermes gateway list to CLI parity manifest and tests
* feat(matrix): add shared-chassis bot seam over threadtext contract
* chore: pre-existing update lifecycle, backup writer, config writer changes
* feat: add restore command, backup restore lifecycle, and update tests
* chore: pre-existing status command changes
* feat(restore): dry-run validates zip before printing would-extract
Restore dry-run (without --yes) now validates the zip archive is openable and free of path-traversal entries BEFORE showing the "would extract" message. A corrupt or malicious zip will now surface the rejection immediately instead of misleading the operator.
* feat(auth): add --json flag to auth status for machine-readable output
gormes auth status <provider> --json now emits a parseable JSON document with the same redacted credential fields the human surface renders. Enables credential-health monitoring in CI/cron without scraping the human row.
* fix(restore): add zip pre-validation to RestoreFromZip extract path
Extends restore zip validation to the actual extract path (not just dry-run). Pre-validates the entire archive before extracting any files, so a malicious entry late in the zip cannot land earlier safe entries on disk.
* refactor(doctor): route output through cobra writers, use newExitCodeError instead of os.Exit
* feat(doctor): add JSON output mode and constructor command pattern
- internal/doctor: add StatusSkip, MarshalJSON, and JSON struct tags
- cmd/gormes/doctor: refactor doctorCmd to newDoctorCommand() constructor
with doctorReporter for dual text/JSON output, eliminating shared var
test contamination
- cmd/gormes: wire newDoctorCommand() in root, update tests to use
newRootCommand() with subcommand args
- cmd/gormes/doctor_runE_test: add fleet-health JSON assertion test
* test(doctor): add failed-field assertion for JSON monitoring contract
* feat(doctor): track failed bool in JSON output for monitoring parity
* feat(doctor): add drSeverity and pending incremental JSON refinements
* feat(version): add git_commit field to --json output for fleet binary verification
* feat: add git_commit field to --json version output and refactor versionCmd to constructor pattern
- Refactor versionCmd from package-level var to newVersionCommand() constructor
to prevent cross-test flag contamination (same anti-pattern that broke
doctorCmd before its constructor refactor)
- Add TestVersionCommand_ConstructorReturnsIndependentInstances test
- Add git_commit field to versionReportJSON, populated via ldflag in CI/Makefile
- Update deploy-gormes-www.yml, release.yml, Makefile build commands with
-X main.GitCommit=${GIT_COMM…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.