Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
780 commits
Select commit Hold shift + click to select a range
b0fd295
perf(desktop): in-memory transcript stash — instant, flash-free sessi…
Kyzcreig Jul 16, 2026
d6e5994
style(desktop): eslint --fix import ordering + padding for the transc…
Kyzcreig Jul 16, 2026
9c4e910
perf(desktop): shiki HTML cache + preload-hydrated stash — kill the h…
Kyzcreig Jul 16, 2026
9e05b0f
Merge upstream NousResearch/main into fork/main (2026-07-15 parity sync)
Kyzcreig Jul 16, 2026
cdb4af4
Merge remote-tracking branch 'refs/remotes/fork/main' into sync/upstr…
Kyzcreig Jul 16, 2026
1b8af38
fix(ci): parity-sync CI gates — map 5 new upstream contributor emails…
Kyzcreig Jul 16, 2026
6e83005
fix(ci): post-merge desktop reconciliation — electron node:test → vit…
Kyzcreig Jul 16, 2026
427d020
style(desktop): eslint --fix post-merge (import order/padding); no-co…
Kyzcreig Jul 16, 2026
1407829
Merge pull request #369 from Kyzcreig/sync/upstream-2026-07-15
Kyzcreig Jul 16, 2026
9d1d9c7
Merge upstream NousResearch/main into fork/main (2026-07-16 catch-up …
Kyzcreig Jul 16, 2026
8142dfa
Merge pull request #370 from Kyzcreig/sync/upstream-catchup-2026-07-16
Kyzcreig Jul 16, 2026
164f4ee
docs(sync): parity-tooling + fork-mergeability specs (Momus-reviewed:…
Kyzcreig Jul 16, 2026
86c0e7d
fix(parity): stabilize bisect classification
Kyzcreig Jul 16, 2026
595b6e7
feat(parity): add fork manifest lint
Kyzcreig Jul 16, 2026
651f62e
feat(parity): add catchup test selection
Kyzcreig Jul 16, 2026
97e9175
feat(parity): separate vacuous coverage acks
Kyzcreig Jul 16, 2026
6f5e60d
feat(parity): wire catchup ack lint and tests gate
Kyzcreig Jul 16, 2026
eb38ffc
Add refactor equivalence harness
Kyzcreig Jul 16, 2026
fba5053
Extract relay header fork extension
Kyzcreig Jul 16, 2026
25db74c
docs(sync): fork-mergeability refactor spec v0.3 + build brief (Momus…
Kyzcreig Jul 16, 2026
8e11a93
fix(parity): fall back to sys.executable when no fleet venv on a CI c…
Kyzcreig Jul 16, 2026
28be2e6
fix(refactor-equiv): address Greptile review — freeze datetime.dateti…
Kyzcreig Jul 16, 2026
4bf7d5f
fix(parity): address Greptile review — $VENV rewrite on persisted bis…
Kyzcreig Jul 16, 2026
e04963b
Merge pull request #371 from Kyzcreig/feat/parity-tooling-v2
Kyzcreig Jul 16, 2026
005281b
Merge remote-tracking branch 'refs/remotes/fork/main' into feat/fork-…
Kyzcreig Jul 16, 2026
5bccdda
Merge pull request #372 from Kyzcreig/feat/fork-ext-harness
Kyzcreig Jul 16, 2026
57abdd6
fix(manifest): golden.json is a data file, not a pytest nodeid — guar…
Kyzcreig Jul 16, 2026
9f52943
Merge pull request #373 from Kyzcreig/fix/manifest-golden-nodeid
Kyzcreig Jul 16, 2026
4b5a1f9
test(cron): capture scheduler fork extension golden
Kyzcreig Jul 16, 2026
a95008d
test(compaction): capture fork extension golden behavior
Kyzcreig Jul 16, 2026
0ae45ec
Add tool gate refactor golden capture
Kyzcreig Jul 16, 2026
255a4c4
Extract tool gate fork helpers
Kyzcreig Jul 16, 2026
e77a87d
refactor(cron): extract scheduler fork helpers
Kyzcreig Jul 16, 2026
51810bd
test(cron): register scheduler extension mutations
Kyzcreig Jul 16, 2026
84da9fa
Register tool gate refactor mutations
Kyzcreig Jul 16, 2026
f20f0cc
refactor(compaction): extract fork announce helpers
Kyzcreig Jul 16, 2026
84f1ed6
test(refactor-equiv): add compaction mutations
Kyzcreig Jul 16, 2026
d0159f3
Register tool gate fork feature manifest
Kyzcreig Jul 16, 2026
ad8de4f
Tighten tool gate extraction budget
Kyzcreig Jul 16, 2026
c1bc431
test(compaction): cover fork formatter branches
Kyzcreig Jul 16, 2026
018cd3c
Acknowledge tool gate manifest vacuous coverage
Kyzcreig Jul 16, 2026
a09af53
docs(sync): track compaction fork extension
Kyzcreig Jul 16, 2026
f9d03bb
Merge pull request #375 from Kyzcreig/feat/fork-ext-r6-toolgate
Kyzcreig Jul 16, 2026
0d0c281
fix(test): bisect six-fixture NONDETERMINISTIC corpus — per-SIDE pari…
Kyzcreig Jul 16, 2026
3f13b37
Merge remote-tracking branch 'refs/remotes/fork/main' into feat/fork-…
Kyzcreig Jul 16, 2026
b45d418
Merge remote-tracking branch 'refs/remotes/fork/main' into feat/fork-…
Kyzcreig Jul 16, 2026
334ae3a
fix(golden): address Greptile P1s — corpus per-model override case us…
Kyzcreig Jul 16, 2026
17d7ab0
fix(golden): compaction runner imports the extracted module DIRECTLY …
Kyzcreig Jul 16, 2026
fa4a3ab
Merge pull request #377 from Kyzcreig/feat/fork-ext-r4-compaction
Kyzcreig Jul 16, 2026
fccc723
Merge remote-tracking branch 'refs/remotes/fork/main' into feat/fork-…
Kyzcreig Jul 16, 2026
bcfb58e
fix(test): bisect six-fixture NONDETERMINISTIC corpus — per-SIDE pari…
Kyzcreig Jul 16, 2026
fafd396
Merge pull request #376 from Kyzcreig/feat/fork-ext-r3-cron
Kyzcreig Jul 16, 2026
4d9e032
Merge remote-tracking branch 'refs/remotes/fork/main' into fix/bisect…
Kyzcreig Jul 16, 2026
ab5f8db
Merge remote-tracking branch 'refs/remotes/fork/fix/bisect-fixture-ra…
Kyzcreig Jul 16, 2026
fa1c80b
fix(test): key the per-side counter by full-path hash — repo.name is …
Kyzcreig Jul 16, 2026
b666f80
Merge pull request #378 from Kyzcreig/fix/bisect-fixture-race
Kyzcreig Jul 16, 2026
b880a46
test: capture state ext refactor golden
Kyzcreig Jul 16, 2026
7ac18ba
refactor: extract pure hermes state helpers
Kyzcreig Jul 16, 2026
19c2e7c
refactor(gateway): extract restart failure codec
Kyzcreig Jul 16, 2026
b728ad4
refactor(gateway): extract route identity helpers
Kyzcreig Jul 16, 2026
cbe8b15
fix(state-ext): keep the hermes_state logger name — logger identity i…
Kyzcreig Jul 16, 2026
9b5c47f
fix(golden): state_ext runner — lazy hermes_state import in the pre-e…
Kyzcreig Jul 16, 2026
7971512
test(restart_codec): add negative-scalar corpus case + scalar-branch …
Jul 16, 2026
6294449
Merge pull request #379 from Kyzcreig/feat/fork-ext-r1-gateway
Kyzcreig Jul 16, 2026
542e4d9
Merge fork/main into feat/fork-ext-r2-state (union mutate.py registries)
Jul 16, 2026
bbfb9ae
Merge pull request #380 from Kyzcreig/feat/fork-ext-r2-state
Kyzcreig Jul 16, 2026
591ae3e
fix(refactor-equiv): golden runners refuse to write into a real HERME…
Jul 16, 2026
b9d2be4
fix(review): guard test no longer writes into the real home; resolve …
Jul 16, 2026
47aad55
fix(cli): fail loud on -m provider/model when provider does not resol…
Kyzcreig Jul 16, 2026
64f0751
Merge branch 'main' into fix/golden-runner-home-guard
Kyzcreig Jul 16, 2026
90dea0d
Merge pull request #381 from Kyzcreig/fix/golden-runner-home-guard
Kyzcreig Jul 17, 2026
2988664
refactor(fallback): layer per-entry reasoning_effort on upstream chok…
Jul 17, 2026
e655dd5
fix(review): None chokepoint resolution keeps current reasoning (sess…
Jul 17, 2026
3f6d865
fix(test): mcp-discovery response deadline must exceed the discovery …
Jul 17, 2026
276d84e
Merge pull request #383 from Kyzcreig/feat/backlog-trio
Kyzcreig Jul 17, 2026
1fa21ac
feat(discord): add react/unreact actions to the discord tool (#387)
Kyzcreig Jul 18, 2026
0fbfe99
fix(model): hot-reload model.aliases without a gateway restart (#386)
Kyzcreig Jul 18, 2026
43c4aea
test(model): assert builtin-alias survival by contract, not a hardcod…
Kyzcreig Jul 18, 2026
216f12d
fix(cron): surface unsafe creation shapes immediately (#389)
Kyzcreig Jul 18, 2026
b2b548f
fix(packaging): declare hermes_state_ext + hermes_undo in py-modules …
Kyzcreig Jul 18, 2026
f8fc82b
feat(cron): model='auto' pins a new LLM cron to the creating agent's …
Kyzcreig Jul 18, 2026
2f0db6b
fix(compaction): cold-start trigger-skew prior prevents empty-history…
Kyzcreig Jul 18, 2026
576c047
test(tui): harden slash worker MCP response timeout (#382)
Kyzcreig Jul 18, 2026
2fe31ac
fix(kanban): prevent PR-state budget starvation (#384)
Kyzcreig Jul 18, 2026
925cd71
fix(gateway): draining gateway must not consume resume-dropbox reques…
Kyzcreig Jul 18, 2026
e0ea617
fix(mem0-scrub): catch natural-language credential disclosure (re-lan…
Kyzcreig Jul 18, 2026
178719d
fix(cron): provider-only fallback entries count as DECLARED (Greptile…
Kyzcreig Jul 18, 2026
8deb96d
fix(gateway): ack a message queued during startup-restore (re-land of…
Kyzcreig Jul 18, 2026
e665670
fix(desktop): role-aware tail-first stamping (re-land of #364) (#398)
Kyzcreig Jul 18, 2026
db8669b
fix(cron): block deliver=origin on sub-hourly jobs at create/update t…
Kyzcreig Jul 18, 2026
3195bf4
fix(mcp): normalize wrapped schemas in refresh re-injection so lcm_* …
Kyzcreig Jul 18, 2026
4616200
fix(kanban): preserve provider in model overrides (#400)
Kyzcreig Jul 18, 2026
c3ab621
fix(gateway): /stop cancels pending clarify prompts so the next messa…
Kyzcreig Jul 20, 2026
a954efc
fix(compaction): announce shows session-truthful reasoning effort, no…
Kyzcreig Jul 20, 2026
8eec56e
fix(footer): honor per-model reasoning_overrides and fallback per-ent…
Kyzcreig Jul 20, 2026
f418cc5
fix(compress): manual /compress granular Model line shows session-tru…
Kyzcreig Jul 20, 2026
03d4cfc
refactor: unify r:<effort> display-label mapping into one chokepoint …
Kyzcreig Jul 20, 2026
136deef
fix(compaction): quoted summary text must not classify as a summary r…
Kyzcreig Jul 20, 2026
475544f
feat(capture): transient-narration gate on world-fact staging + dropp…
Kyzcreig Jul 20, 2026
d524e84
fix: park delivery-exhausted orphan async-delegations + throttle webh…
Kyzcreig Jul 20, 2026
ea1138e
test(tui_gateway): stub _launch_configured_cwd in completion-cwd fall…
Kyzcreig Jul 20, 2026
bcf7f58
fix(cronjob): accept flat model-string arg + warn on silently-dropped…
Kyzcreig Jul 22, 2026
3174e25
fix(plugins): serialize plugin loader import critical-section to clos…
Kyzcreig Jul 22, 2026
c5340c8
fix(process): bound the orphaned-pipe drain in _reconcile_local_exit …
Kyzcreig Jul 23, 2026
37fa0a3
fix(vision): consult provider profile supports_vision when models.dev…
Kyzcreig Jul 23, 2026
5124729
docs(sync): add fork parity doctrine (#417)
Kyzcreig Jul 24, 2026
371f3ae
fix: maintain session denorm across parent rewrites (#418)
Kyzcreig Jul 24, 2026
b51d659
Add claude-opus-5 to pricing + provider catalogs (#419)
Kyzcreig Jul 24, 2026
d995f30
Merge upstream parity into sync/upstream-2026-07-23
Kyzcreig Jul 24, 2026
6c44d07
Merge remote-tracking branch 'fork/main' into sync/upstream-2026-07-23
Kyzcreig Jul 24, 2026
b5d533b
fix(sync): CI round-1 fixes — dead import of upstream-deleted module …
Kyzcreig Jul 24, 2026
923516a
fix(sync): CI round-2 — desktop lint errors from the pin-atom cleanup
Kyzcreig Jul 25, 2026
8d20d24
fix(sync): CI round-3 — durable-route wake target + nousbot contribut…
Kyzcreig Jul 25, 2026
5114780
fix(sync): recalibrate compaction E2E fixture for the fork's skew-cal…
Kyzcreig Jul 25, 2026
dd58e24
fix(sync): size the compaction E2E filler past BOTH fork trigger beha…
Kyzcreig Jul 25, 2026
05fc0f5
test(sync): xfail two non-merge reds with citations + follow-up cards
Kyzcreig Jul 25, 2026
4048de6
sync: upstream parity merge 2026-07-23 (1778 commits, 125 conflict fi…
Kyzcreig Jul 25, 2026
ecbf417
fmt(js): `npm run fix` on merge (#421)
github-actions[bot] Jul 25, 2026
a6662d3
fix(test): hermetic env-detection tests — pin container/supervisor/HO…
Kyzcreig Jul 25, 2026
6415520
fix(desktop): resolve app icon from asar.unpacked so the app can laun…
Kyzcreig Jul 25, 2026
e7d2b9f
fix(curator): scope the shared-tree clean-tree gate to the paths a pa…
Kyzcreig Jul 25, 2026
a263632
fix(gateway): stop double-posting the STT transcript echo for one voi…
Kyzcreig Jul 25, 2026
60ea6b2
fix(lcm): self-heal FTS column drift at startup — reorder init so the…
Kyzcreig Jul 25, 2026
e2e69f6
fix(anthropic): non-whitespace placeholder for the synthetic leading …
Kyzcreig Jul 26, 2026
85ee6f0
test(anthropic): class-level invariant — no conversion path may emit …
Kyzcreig Jul 26, 2026
bab5061
fix(tests): remove two xfail markers left by the 2026-07-23 parity me…
Kyzcreig Jul 26, 2026
cca9129
vendor(lcm): cherry-pick 9 upstream fixes (incl. the Anthropic HTTP 4…
Kyzcreig Jul 26, 2026
0986938
feat(tui_gateway): bound heavy session reads (#441)
Kyzcreig Jul 26, 2026
102c9a2
test: salvage wave3b coverage — Slack internal-event path + delegatio…
Kyzcreig Jul 26, 2026
0b7cc2b
docs(sync): absorption sweep — register absorbed turn-isolation famil…
Kyzcreig Jul 26, 2026
5703452
feat(blackbox): event-driven new-model pricing sentinel (#432)
Kyzcreig Jul 26, 2026
8521235
fix(hermeticity): route 6 Path.home()/".hermes" bypass sites through …
Kyzcreig Jul 26, 2026
9d0a58c
fix(tui_gateway): dedup merge-introduced module-level defs + recover …
Kyzcreig Jul 26, 2026
e54eb50
docs(pricing): cite Anthropic's official page for the Claude Fable 5 …
Kyzcreig Jul 26, 2026
fb6d97f
test(tui_gateway): bind compute-host control stubs to the real signat…
Kyzcreig Jul 26, 2026
f10a7c0
fix(state): skip the trigram sweep in _fts_rebuild_finish when the tr…
Kyzcreig Jul 26, 2026
05b3dad
fix(state): maintain effective_last_active across import and message-…
Kyzcreig Jul 26, 2026
20809f1
fix(mem0): floor_outcome reported an empty search when a gate emptied…
Kyzcreig Jul 27, 2026
9e1d99a
test: replace wall-clock assertions with deterministic signals (5 fla…
Kyzcreig Jul 27, 2026
ba181e7
fix(kanban): reclaim must not launder a blocked card into ready (#437)
Kyzcreig Jul 27, 2026
6d3236d
fix(gateway): hygiene compression deadline must not be tighter than t…
Kyzcreig Jul 27, 2026
0337108
ci(secret-scan): use merge_group base/head SHAs -- unbreak every queu…
Kyzcreig Jul 27, 2026
1420bdd
test: salvage wave3b coverage round 2 (compression persist-failure + …
Kyzcreig Jul 27, 2026
8435be2
feat(blackbox): session depth + CLI invocation correlation columns (#…
Kyzcreig Jul 27, 2026
d002b28
test(e2e): kill the wall-clock race in the sidebar background-dot spe…
Kyzcreig Jul 27, 2026
45cf4a7
docs(sync): land 2026-07-23 parity evidence — forkdelta review, 257 a…
Kyzcreig Jul 27, 2026
7091324
feat(compress): interim progress ack + per-event LCM compaction telem…
Kyzcreig Jul 27, 2026
8d1159a
test(mem0): add dedicated coverage for temporal_parse window parsing …
Kyzcreig Jul 27, 2026
df80d47
fix(gateway): bind the real profile in session context, not "" (#453)
Kyzcreig Jul 27, 2026
caac7e7
fix(backup): skip ephemeral kanban board workspaces in the full-zip w…
Kyzcreig Jul 27, 2026
2ca9832
fix(redact): eliminate catastrophic backtracking in _CFG_DOTTED_RE (#…
Kyzcreig Jul 27, 2026
dacc7ba
test: convert 12 wall-clock Python test assertions to deterministic s…
Kyzcreig Jul 27, 2026
f9f9976
fix(delegate): stamp subagent turns with their real custom-provider l…
Kyzcreig Jul 27, 2026
13818d2
fix(gateway): clear resume_pending for sessions that finished during …
Kyzcreig Jul 27, 2026
0a78078
test(e2e): fix the wall-clock race in tile-unread-bug's unread assert…
Kyzcreig Jul 27, 2026
2dff58f
fix(gateway): let the shutdown drain actually cancel in-flight cron s…
Kyzcreig Jul 27, 2026
e76c5dc
fmt(js): `npm run fix` on merge (#424)
github-actions[bot] Jul 29, 2026
fe838f5
fix(ci): run JS autofix as trusted actor (#463)
Kyzcreig Jul 29, 2026
ba6bf5d
fix(models): add claude-opus-5 to DEFAULT_CONTEXT_LENGTHS (was resolv…
Kyzcreig Jul 31, 2026
50996f1
fix(lcm): merge adjacent assistant rows in active-context assembly (#…
Kyzcreig Jul 31, 2026
ea3274e
fix(gateway): mark /curator cli_only — advertised with no gateway han…
Kyzcreig Aug 3, 2026
a36d6c0
fix(gateway+fallback): stale status adapter after reconnect; stop eff…
Kyzcreig Aug 6, 2026
e523d72
feat(mem0): log full query text (qtext=) on prefetch telemetry lines …
Kyzcreig Aug 6, 2026
11cffc4
feat(kanban): CLI auto-subscribe knob + dispatch unwatched warning (f…
Kyzcreig Aug 6, 2026
b2eb4be
fix(kanban): restore fork contracts clobbered by 11cffc4d5 + catalog …
Kyzcreig Aug 7, 2026
7845f00
fix(cron): resolve dict-form job model instead of reporting "no model…
Kyzcreig Aug 7, 2026
f7b7d89
fix(tests): isolate gateway session ContextVars across test files (#478)
Kyzcreig Aug 7, 2026
f5deb18
fix(cron): attach job identity to turn telemetry (#473)
Kyzcreig Aug 7, 2026
5bd89c0
fix(oneshot): identify kanban worker turns (#471)
Kyzcreig Aug 7, 2026
85e1fe4
ci: route runs-on through CI_RUNNER_LABELS var (self-hosted fallback)…
Kyzcreig Aug 7, 2026
9c223c0
refactor(gateway): extract restart policy helpers (#456)
Kyzcreig Aug 7, 2026
6b37329
fix(failover): honest label for multi-sub pool exhaustion ("no eligib…
Kyzcreig Aug 7, 2026
9146254
fix(kanban): identify dispatcher chat workers (#479)
Kyzcreig Aug 7, 2026
95740a8
ci: fail closed in umbrella result gate (#476)
Kyzcreig Aug 7, 2026
fb08a29
fix(tests): un-skip 4 no-mock restart-cascade E2E tests that went dar…
Kyzcreig Aug 7, 2026
27b6178
fix(lcm): re-vendor v0.21.0-rc2 + announce the below-threshold compac…
Kyzcreig Aug 7, 2026
c6a1c69
fix(cron): dict-form job model + ticker execution-ledger never closed…
Kyzcreig Aug 7, 2026
b74706a
fix(tests): stop test_run_gateway_refreshes_outdated_unit_on_boot kil…
Kyzcreig Aug 7, 2026
ee2fce2
fix(cron): refuse a bare-platform deliver that would silently hit the…
Kyzcreig Aug 7, 2026
debfb5f
fix(tests): stop test_web_server_host_header shadowing the real herme…
Kyzcreig Aug 7, 2026
78a6b4a
fix(desktop-e2e): bound fixture cleanup with a hard deadline — naked …
Kyzcreig Aug 7, 2026
be845cc
feat(kanban): per-task reasoning effort (DB + dispatcher + CLI + tool…
Kyzcreig Aug 7, 2026
2174e73
test(model-metadata): guard Anthropic 1M models against a fallback-ta…
Kyzcreig Aug 7, 2026
fd0e388
fix(kanban-diagnostics): a clean block breaks the crash streak (recov…
Kyzcreig Aug 7, 2026
ae31d8b
fix(models): dots->hyphens only for Anthropic MODELS, not Anthropic-w…
Kyzcreig Aug 7, 2026
40b0df9
feat(gateway): config toggle for the model-switch stale-code guard (#…
Kyzcreig Aug 8, 2026
2bc92c8
fix(kanban): goal-loop block path must pass the ownership guard (#494)
Kyzcreig Aug 8, 2026
cee6829
fix(kanban): respawn guard fail-closed forever on a JSON-quoted PR UR…
Kyzcreig Aug 8, 2026
d85b74e
fix(fallback): stop announcing one failover hop as two chat messages …
Kyzcreig Aug 8, 2026
9e9c4f4
fix(tests): restore the aux-client stub so it stops leaking into late…
Kyzcreig Aug 8, 2026
5636a8a
fix(compaction): below-threshold compactions announce themselves and …
Kyzcreig Aug 8, 2026
a860a97
fix(tokens): price documents per PAGE and audio per SECOND, not a fla…
Kyzcreig Aug 8, 2026
df4b21a
fix(kanban): background-review forks must not fail the parent's task …
Kyzcreig Aug 8, 2026
89b3c1a
fix(compaction): every compaction names the arm that fired it (#502)
Kyzcreig Aug 8, 2026
4f7d049
fix(compaction): show BOTH token counters when they disagree (#503)
Kyzcreig Aug 8, 2026
43203bb
fix(compaction): stop compacting sessions that are nowhere near full …
Kyzcreig Aug 8, 2026
c7455df
fix(cron): `cron run <name> --wait` accepts a job NAME, not just an I…
Kyzcreig Aug 8, 2026
f4a1f5b
fix(lcm): bridge compression.maintenance_min_pressure_ratio into LCMC…
Kyzcreig Aug 8, 2026
829d4e0
fix(compaction): only announce a compaction that actually compacts (#…
Kyzcreig Aug 8, 2026
4271f00
feat(background-review): raise iteration ceiling 16 -> 30 and make ex…
Kyzcreig Aug 8, 2026
acf7d9b
fix(compaction): a pass that compacted nothing must not say it did (#…
Kyzcreig Aug 8, 2026
9ccce7f
feat(providers): add ProviderProfile.process_response_text hook (#495)
Kyzcreig Aug 8, 2026
64f8872
feat(anthropic): gate fine-grained-tool-streaming beta behind a confi…
Kyzcreig Aug 8, 2026
fcb1247
fix(delegation): tombstones must say whether the dead attempt ever st…
Kyzcreig Aug 8, 2026
8c0c8d0
fix(tokens): compose_request_breakdown double-billed document + audio…
Kyzcreig Aug 8, 2026
6c44367
fix(kanban): give `triage` a supported exit and make downstream stran…
Kyzcreig Aug 8, 2026
48a0954
fix(mem0): gate bare status-pings at Gate A (the recurring 'status?' …
Kyzcreig Aug 8, 2026
84ceff5
fix(failover): entitlement 403 announces '(account blocked)', not '(a…
Kyzcreig Aug 8, 2026
d86e166
feat(kanban): a DEPLOY must never be gated on a DISCOVERY — add a non…
Kyzcreig Aug 8, 2026
293b617
fix(memory): strip gateway harness metadata before the provider fan-o…
Kyzcreig Aug 8, 2026
aa27fd8
merge: parity sync with upstream (3,466 commits, 238 conflicts → 0) (…
Kyzcreig Aug 9, 2026
ca02782
fix(kanban): ignore provenance links in triage stranding reports (#519)
Kyzcreig Aug 9, 2026
9bf326a
fix(gateway): restore served provider + reasoning in turn result; re-…
Kyzcreig Aug 9, 2026
6cdf89a
fix(cron): reconcile jobs.json when a run's owner dies mid-execution …
Kyzcreig Aug 9, 2026
b0814d5
fix(compression): honest /compress abort reporting, reachable fallbac…
Kyzcreig Aug 9, 2026
ef8736e
fix(compaction): persisted skew calibration must survive a restart (#…
Kyzcreig Aug 9, 2026
3115a4d
fix(failover): classify corrupt response bodies + name the exhausted …
Kyzcreig Aug 9, 2026
12ce5f3
fix(compress): inherit resident live route (#527)
Kyzcreig Aug 9, 2026
ba27326
fix(kanban): stop zombie goal loops on ownership loss (#522)
Kyzcreig Aug 9, 2026
69d309a
fix(cron): an INTERRUPTED run records last_status=unknown, not error …
Kyzcreig Aug 9, 2026
1e6d99b
fix(compaction): don't burn a warm prompt cache to compact below thre…
Kyzcreig Aug 9, 2026
dcd47fe
fix(failover): honor an identified 7d quota window in the primary coo…
Kyzcreig Aug 9, 2026
dcd9887
test(moa): replace interrupt stopwatch with ordering witness (#534)
Kyzcreig Aug 9, 2026
cea7eb8
[verified] fix(relay): sanitize split surrogates before stream encodi…
Kyzcreig Aug 10, 2026
cc839ab
fix(kanban): guard delete_task against live workers; add HERMES_KANBA…
Kyzcreig Aug 10, 2026
ee8b966
fix(backup): exclude staging DISK IMAGES from the full-tier walk (#536)
Kyzcreig Aug 10, 2026
6f66e6b
fix(config): stop `config set compression.<lcm_knob>` crying wolf (#537)
Kyzcreig Aug 10, 2026
7644a3e
fix(tests): restore sys.modules after the loop-dampening fixture's pu…
Kyzcreig Aug 10, 2026
a340b8a
fix(compaction): key learned skew calibration by (provider, model), n…
Kyzcreig Aug 10, 2026
1677b9d
test(hermetic): fully contain fresh-import module purges (#540)
Kyzcreig Aug 10, 2026
0b2a959
feat(compaction): calibrate token-estimate skew per content class (#541)
Kyzcreig Aug 10, 2026
48003f5
test(hermetic): gate on unrestored sys.modules purges (+2 leakers) (#…
Kyzcreig Aug 10, 2026
1dc9ff1
fix(repair): Pass 1.5 must match tool results on call_id, not just id…
Kyzcreig Aug 10, 2026
4a36004
test: harden macOS full-load hermeticity (#546)
Kyzcreig Aug 10, 2026
e1c4772
feat(kanban): attribute comments to their run and session (#545)
Kyzcreig Aug 10, 2026
86af4b9
fix(tests): snapshot_watched must not iterate sys.modules directly (#…
Kyzcreig Aug 10, 2026
7b5f1d6
fix(terminal): stop per-execution identity leaking via the shell snap…
Kyzcreig Aug 10, 2026
a1a2052
test: convert remaining TRUE-FLAKE-RISK wall-clock assertions to orde…
Kyzcreig Aug 10, 2026
390db4f
fix(tests): stop tests/ shadowing real packages on sys.path; de-flake…
Kyzcreig Aug 10, 2026
6024853
test(mem0): salvage 12 Wave-2 coverage tests from a stranded branch (…
Kyzcreig Aug 10, 2026
efd03b4
fix(terminal): stop the silent output blackout when stdout fd >= FD_S…
Kyzcreig Aug 10, 2026
5a4ec3b
fix(compaction): plugin engines never received the session store, mak…
Kyzcreig Aug 10, 2026
e97b175
fix(kanban): stamp session provenance on comments written from execut…
Kyzcreig Aug 10, 2026
a4d467a
test(tools): isolate terminal path state between tests (#558)
Kyzcreig Aug 10, 2026
99300bf
fix(kanban): stop identity-less notify subs minting a phantom 2nd ses…
Kyzcreig Aug 10, 2026
d49bceb
fix(model-switch): stop /model clobbering the session's reasoning eff…
Kyzcreig Aug 10, 2026
bfb3858
fix(gateway): don't spawn boot-resume turns for sessions with nothing…
Kyzcreig Aug 10, 2026
cdeae84
test(mem0): lock the D-7 interlock's absent-capture fail-safe (#552)
Kyzcreig Aug 10, 2026
ac0fb8b
fix(verification): recognize env options before test commands (#559)
Kyzcreig Aug 10, 2026
8129063
test(fd-drain): fix the FLAKY burn_fds fixture that made the high-fd …
Kyzcreig Aug 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
25 changes: 24 additions & 1 deletion .github/actions/detect-changes/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ outputs:
python:
description: Run Python tests / ruff / ty / windows-footguns.
value: ${{ steps.classify.outputs.python }}
python_prod:
description: Python changes outside tests/ — gates product jobs (Desktop E2E, Docker).
value: ${{ steps.classify.outputs.python_prod }}
frontend:
description: Run the TypeScript testing matrix + desktop build.
value: ${{ steps.classify.outputs.frontend }}
Expand All @@ -33,9 +36,15 @@ outputs:
npm_lock:
description: Post/update the semantic package-lock.json diff PR comment.
value: ${{ steps.classify.outputs.npm_lock }}
installer:
description: Run the PowerShell installer tests on a Windows runner.
value: ${{ steps.classify.outputs.installer }}
mcp_catalog:
description: Require MCP catalog security review label.
value: ${{ steps.classify.outputs.mcp_catalog }}
test_scope:
description: Isolated plugin test scope, or fail-open full.
value: ${{ steps.classify.outputs.test_scope }}
ci_review:
description: Require CI-sensitive file review label.
value: ${{ steps.classify.outputs.ci_review }}
Expand Down Expand Up @@ -82,12 +91,15 @@ runs:
# die with "cannot iterate over: null", which fails every retry
# and forces the fail-open path (seen on stacked PRs). The full
# file list (up to the API's 300-file cap) is on page one.
#
# `.previous_filename` (fork): also surface a renamed file's OLD path
# so a rename touches the lanes that owned either path.
CHANGED=""
for i in 1 2 3; do
if CHANGED="$(gh api \
--paginate \
"repos/${REPO}/compare/${BASE_SHA}...${HEAD_SHA}" \
--jq '.files[]?.filename')"; then
--jq '.files[]? | .filename, (.previous_filename // empty)')"; then
break
fi
if [ "$i" = 3 ]; then
Expand All @@ -103,3 +115,14 @@ runs:
echo "Changed files:"
printf '%s\n' "${CHANGED:-(none)}"
printf '%s\n' "${CHANGED:-}" | python3 scripts/ci/classify_changes.py

TEST_SCOPE=full
if [ "$EVENT_NAME" = "pull_request" ] && [ -n "$CHANGED" ]; then
TEST_SCOPE="$(printf '%s\n' "$CHANGED" | \
python3 scripts/run_tests_parallel.py --changed-files-scope || true)"
fi
case "$TEST_SCOPE" in
full|plugin:*) ;;
*) TEST_SCOPE=full ;;
esac
echo "test_scope=$TEST_SCOPE" | tee -a "$GITHUB_OUTPUT"
135 changes: 66 additions & 69 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ on:
pull_request:
push:
branches: [main]
# merge_group: the merge queue creates a temporary batched branch and fires
# this event; the required checks must run on it or the queue wedges forever.
# On merge_group the detect-changes classifier fails open (EVENT_NAME !=
# pull_request -> empty diff -> every lane true), so the FULL matrix runs on
# the batched candidate — the queue never merges narrowed/untested code.
merge_group:

permissions:
contents: read
Expand All @@ -38,17 +44,20 @@ jobs:
# ─────────────────────────────────────────────────────────────────────
detect:
name: Detect affected areas
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(vars.CI_RUNNER_LABELS || '["ubuntu-latest"]') }}
timeout-minutes: 10
outputs:
python: ${{ steps.classify.outputs.python }}
python_prod: ${{ steps.classify.outputs.python_prod }}
frontend: ${{ steps.classify.outputs.frontend }}
site: ${{ steps.classify.outputs.site }}
scan: ${{ steps.classify.outputs.scan }}
deps: ${{ steps.classify.outputs.deps }}
npm_lock: ${{ steps.classify.outputs.npm_lock }}
installer: ${{ steps.classify.outputs.installer }}
docker_meta: ${{ steps.classify.outputs.docker_meta }}
mcp_catalog: ${{ steps.classify.outputs.mcp_catalog }}
test_scope: ${{ steps.classify.outputs.test_scope }}
ci_review: ${{ steps.classify.outputs.ci_review }}
ci_review_files: ${{ steps.classify.outputs.ci_review_files }}
event_name: ${{ github.event_name }}
Expand All @@ -70,7 +79,8 @@ jobs:
if: needs.detect.outputs.python == 'true'
uses: ./.github/workflows/tests.yml
with:
slice_count: 8
slice_count: 12
test_scope: ${{ needs.detect.outputs.test_scope }}

lint:
name: Python lints
Expand All @@ -86,10 +96,41 @@ jobs:
if: needs.detect.outputs.frontend == 'true'
uses: ./.github/workflows/js-tests.yml

installer-tests:
name: Installer tests
needs: detect
# Windows-only, and only for PRs that touch install.ps1 or its tests.
if: needs.detect.outputs.installer == 'true'
uses: ./.github/workflows/installer-tests.yml

e2e-desktop:
name: Desktop E2E
needs: detect
if: needs.detect.outputs.python == 'true' || needs.detect.outputs.frontend == 'true'
# python_prod (not python): the Playwright suite exercises the built app
# + `hermes serve` backend, which never import anything under tests/.
#
# ⛔ DISABLED — upstream's guard (their #76627: after the Aug 1 engines/npm
# churn the mock-backend Electron window never gets a title, so boot/chat/
# setup specs all fail identically regardless of the diff).
#
# fork-parity note: I briefly restored the fork's condition here because
# `Desktop E2E` concludes SUCCESS on fork/main (runs 31280614721 /
# 31278775668) — which looked like proof upstream's premise was false here.
# It was the wrong inference. fork/main still carries the FORK's desktop
# tree (17 specs); this branch retires that fork and takes upstream's
# apps/desktop verbatim (19 specs, byte-identical to upstream/main), so it
# inherits upstream's BROKEN suite too. Re-enabling reproduced their exact
# symptom and blew the 20-minute cap at 20m20s:
# ✘ e2e/boot.spec.ts › window opens with Hermes title
# ✘ e2e/boot.spec.ts › renderer mounts and shows DOM content
# ✘ e2e/chat.spec.ts › send a message and receive a response
# Green on fork/main measured the fork's suite, not this one.
#
# This job is intentionally SKIPPED, and scripts/ci/evaluate_needs.py has a
# matching exemption so the skip is declared rather than silent (the #476
# rule is 'no required job vanishes unnoticed', not 'never skip').
# Re-enable together with upstream's #76627 fix.
if: ${{ false && (needs.detect.outputs.python_prod == 'true' || needs.detect.outputs.frontend == 'true') }}
uses: ./.github/workflows/e2e-desktop.yml

docs-site:
Expand All @@ -115,6 +156,11 @@ jobs:
needs: detect
uses: ./.github/workflows/uv-lockfile-check.yml

infographic-check:
name: Check no committed infographics
needs: detect
uses: ./.github/workflows/infographic-check.yml

lockfile-diff:
name: package-lock.json diff
needs: detect
Expand All @@ -132,8 +178,10 @@ jobs:
needs: detect
# Trusted main pushes run docker.yml directly so its container-publish
# environment secrets never cross this reusable-workflow call. PR runs
# remain build/test-only and secret-free.
if: needs.detect.outputs.event_name == 'pull_request' && (needs.detect.outputs.python == 'true' || needs.detect.outputs.frontend == 'true' || needs.detect.outputs.docker_meta == 'true')
# remain build/test-only and secret-free. Gated on python_prod (not
# python): the image copies installed code, never tests/ — tests-only
# PRs skip the build.
if: needs.detect.outputs.event_name == 'pull_request' && (needs.detect.outputs.python_prod == 'true' || needs.detect.outputs.frontend == 'true' || needs.detect.outputs.docker_meta == 'true')
uses: ./.github/workflows/docker.yml

supply-chain:
Expand Down Expand Up @@ -176,7 +224,7 @@ jobs:
name: CI review comment (live)
needs: [detect, review-labels, lockfile-diff, supply-chain, osv-scanner, uv-lockfile, history-check, contributor-check, e2e-desktop]
if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork != true
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(vars.CI_RUNNER_LABELS || '["ubuntu-latest"]') }}
timeout-minutes: 40
steps:
- name: Checkout code
Expand All @@ -196,52 +244,15 @@ jobs:
COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
COMMIT_MESSAGE: ${{ github.event.pull_request.head.commit.message }}
COMMIT_URL: ${{ github.server_url }}/${{ github.repository }}/pull/${{ github.event.pull_request.number }}/commits/${{ github.event.pull_request.head.sha }}
# Structured review statuses from workflow_call jobs.
# Each job outputs a JSON array of {source, results: [...]} objects
# that the assembler renders directly — no hardcoded job-name
# matching. We merge all available outputs into one array.
REVIEW_STATUSES: ${{ toJSON(needs.*.outputs.review_status) }}
run: |
set -uo pipefail

# REVIEW_STATUSES is a JSON array of strings (some may be empty
# when a job was skipped). Parse each string and merge into one
# flat array for the assembler.
python3 - <<'PYEOF'
import json, os, sys

raw = os.environ.get("REVIEW_STATUSES", "")
merged = []
if raw:
try:
arr = json.loads(raw)
except (json.JSONDecodeError, TypeError):
arr = []
for item in arr:
if not item:
continue
try:
statuses = json.loads(item)
except (json.JSONDecodeError, TypeError):
continue
if isinstance(statuses, list):
merged.extend(statuses)

# Write merged array to a temp file the poller reads.
with open("/tmp/review_statuses.json", "w") as f:
json.dump(merged, f)
print(f"Merged {len(merged)} review status entries")
PYEOF

python3 scripts/ci/live_comment.py \
--interval 15 \
--timeout 2100 \
--review-statuses-file /tmp/review_statuses.json
--timeout 2100

# ─────────────────────────────────────────────────────────────────────
# Gate: runs after everything. ``if: always()`` ensures it reports a
# status even when some deps were skipped. Only actual ``failure``
# results cause it to fail; ``skipped`` is treated as success.
# status even when some deps were skipped. Only ``success`` and a
# classifier-consistent ``skipped`` result pass the gate.
#
# Branch protection should require ONLY this check.
#
Expand All @@ -255,6 +266,7 @@ jobs:
- tests
- lint
- js-tests
- installer-tests
- e2e-desktop
- docs-site
- history-check
Expand All @@ -269,49 +281,34 @@ jobs:
# we don't require docker to pass rn because it's so slow lol
# - docker
if: always()
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(vars.CI_RUNNER_LABELS || '["ubuntu-latest"]') }}
timeout-minutes: 10
outputs:
needs-json: ${{ steps.evaluate.outputs.needs-json }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Evaluate job results
id: evaluate
env:
NEEDS: ${{ toJSON(needs) }}
run: |
echo "$NEEDS" | python3 -c "
import json, sys
needs = json.load(sys.stdin)
# Emit compact {job_name: result} for the comment assembler.
compact = {name: info['result'] for name, info in needs.items()}
print(f'needs-json={json.dumps(compact)}')
with open('$GITHUB_OUTPUT', 'a') as f:
f.write(f'needs-json={json.dumps(compact)}\n')
failed = [name for name, info in needs.items() if info['result'] == 'failure']
for name, info in sorted(needs.items()):
result = info['result']
icon = '✅' if result in ('success', 'skipped') else '❌'
print(f'{icon} {name}: {result}')
if failed:
print(f'::error::{len(failed)} job(s) failed: {\", \".join(failed)}')
sys.exit(1)
print('All checks passed (or were skipped)')
"
echo "$NEEDS" | python3 scripts/ci/evaluate_needs.py

# ─────────────────────────────────────────────────────────────────────
# CI timing report: collect per-job/step durations from the GitHub API,
# cache them on main (as a baseline), and on PRs generate an HTML diff
# report with a gantt chart + per-step breakdown. The report is uploaded
# as an artifact and a markdown summary is written to $GITHUB_STEP_SUMMARY.
#
# The live comment poller can read the standalone review-status artifact
# after the HTML report is uploaded, so its link points straight at that report.
# The live comment poller dynamically fetches all review-status-* artifacts
# across the orchestrator and sub-workflow runs every cycle, so its link
# points straight at that report.
# ─────────────────────────────────────────────────────────────────────
ci-timings:
name: CI timing report
needs: [all-checks-pass, docker]
if: always()
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(vars.CI_RUNNER_LABELS || '["ubuntu-latest"]') }}
timeout-minutes: 10
steps:
- name: Checkout code
Expand Down Expand Up @@ -364,7 +361,7 @@ jobs:
continue-on-error: true
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ci-timings-review-status
name: review-status-ci-timings
path: review-status.json
retention-days: 14

Expand Down
21 changes: 19 additions & 2 deletions .github/workflows/contributor-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ permissions:

jobs:
check-attribution:
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(vars.CI_RUNNER_LABELS || '["ubuntu-latest"]') }}
timeout-minutes: 10
outputs:
review_status: ${{ steps.check-emails.outputs.review_status }}
Expand All @@ -33,6 +33,7 @@ jobs:
if [ -z "$NEW_EMAILS" ]; then
echo "No new commits to check."
echo "review_status=[]" >> "$GITHUB_OUTPUT"
echo "review_status=[]" > review-status.json
exit 0
fi

Expand Down Expand Up @@ -67,6 +68,8 @@ jobs:
echo -e "$MISSING"
echo ""
echo "Add a mapping file (do NOT edit AUTHOR_MAP in release.py):"
echo " python3 scripts/audit_pr_attribution.py --fix # auto-resolve + create files"
echo "or manually:"
echo -e "$MISSING" | while read -r line; do
email=$(echo "$line" | sed 's/^ *//' | cut -d' ' -f1)
[ -z "$email" ] && continue
Expand All @@ -78,14 +81,28 @@ jobs:

# Emit review_status for unmapped emails
DETAIL=$(echo -e "$MISSING" | sed '/^$/d; s/^ //')
HOW_TO_FIX=$'Add mappings to scripts/release.py AUTHOR_MAP:\n```\n"<email>": "<github-username>",\n```\nTo find the GitHub username for an email:\n```\ngh api \'search/users?q=EMAIL+in:email\' --jq \'.items[0].login\'\n```\n'
HOW_TO_FIX=$'Run from the PR branch:\n```\npython3 scripts/audit_pr_attribution.py --fix\ngit add contributors && git commit -m "chore: map contributor emails" && git push\n```\nOr map one email manually (do NOT edit AUTHOR_MAP in release.py):\n```\npython3 scripts/add_contributor.py <email> <github-username>\n```\nTo find the GitHub username for an email:\n```\ngh api \'search/users?q=EMAIL+in:email\' --jq \'.items[0].login\'\n```\n'
REVIEW_STATUS=$(jq -nc \
--arg detail "$DETAIL" \
--arg how_to_fix "$HOW_TO_FIX" \
'[{"source":"contributor attribution","results":[{"kind":"action_required","title":"Unmapped contributor email(s)","summary":"New contributor email(s) are not in AUTHOR_MAP.","detail":$detail,"how_to_fix":$how_to_fix}]}]')
echo "review_status=$REVIEW_STATUS" >> "$GITHUB_OUTPUT"
echo "review_status=$REVIEW_STATUS" > review-status.json

exit 1
else
echo "✅ All contributor emails are mapped."
echo "review_status=[]" >> "$GITHUB_OUTPUT"
echo "review_status=[]" > review-status.json
fi

- name: Upload review status artifact
if: always() && steps.check-emails.outcome != 'skipped'
continue-on-error: true
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: review-status-contributor-check
path: review-status.json
retention-days: 1
overwrite: true
if-no-files-found: ignore
10 changes: 7 additions & 3 deletions .github/workflows/deploy-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ jobs:
# a skills-index PR that doesn't touch website/** paths and so
# doesn't auto-deploy via the deploy-docs path.
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(vars.CI_RUNNER_LABELS || '["ubuntu-latest"]') }}
timeout-minutes: 30
steps:
- name: Trigger Vercel Deploy
run: curl -fsS --retry 3 --retry-delay 10 -X POST "${{ secrets.VERCEL_DEPLOY_HOOK }}"

deploy-docs:
if: github.repository == 'NousResearch/hermes-agent'
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(vars.CI_RUNNER_LABELS || '["ubuntu-latest"]') }}
timeout-minutes: 30
environment:
name: github-pages
Expand All @@ -65,10 +65,14 @@ jobs:

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 22
node-version: 26
cache: npm
cache-dependency-path: website/package-lock.json

- name: grab npm 12
run: |
npm i -g npm@12

- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.11'
Expand Down
Loading