5556 Commits

Author SHA1 Message Date
Hermes Agent
92ec0c0297 refactor(hermes): rename the owner agent host to worker.bstein.dev
Introduce worker.bstein.dev as the canonical hostname for the owner-only
Hermes coordinator, previously agent.hermes.bstein.dev.

The old host is deliberately kept alive. CoreDNS, both agent Ingresses and
the hermes-sites certificate now serve BOTH names, so merging this cannot
take away the endpoint the operator uses to reach the coordinator. Retiring
agent.hermes.bstein.dev is a separate, separately scheduled change. No
redirect middleware is added.

What switches to the new host:
- HERMES_DASHBOARD_PUBLIC_URL and the oauth2-proxy --redirect-url
- the Keycloak hermes-agent-proxy rootUrl
- operator docs, skills, the ZAP baseline target and the triage monitor default

What stays dual-homed until retirement:
- CoreDNS hosts entry, both agent Ingress rules, certificate SANs
- API_SERVER_CORS_ORIGINS (now a comma-separated pair)
- the Keycloak redirect URIs, web origins and post-logout origins, so a
  rollback only needs the oauth2-proxy --redirect-url reverted and does not
  require re-running the ensure job

ensure_proxy_client now takes optional trailing legacy URLs; called with a
single URL it emits the identical payload as before, so the chat and triage
clients are unaffected. The ensure Job is bumped to -11 so Flux re-runs it;
login on the new host fails until that Job completes.

Because the session and CSRF cookies use the __Host- prefix they are bound to
one origin, so a fresh login must start on worker.bstein.dev and existing
sessions do not carry over -- re-login is required after rollout.

Knowledge catalogs and diagrams regenerated with `make knowledge`.
2026-08-21 10:13:33 +00:00
Hermes Agent
26705c1f66 chore(knowledge): regenerate stale Atlas catalogs
`make knowledge` output on main no longer matched the manifests it is
rendered from: Flux kustomizations added since the last regeneration
(hermes-scm-broker, hermes-scm-broker-code, hermes-scm-namespace,
hermes-observer-rbac, hermes-observer-bindings,
vault-hermes-jenkins-token-seed) and the Atlas AI Operations dashboard
panels were missing from the committed artifacts.

This is a pure `make knowledge` run against unmodified main, separated
into its own commit so the hostname rename that follows reviews as a
hostname rename and nothing else. No hand edits.
2026-08-21 09:58:42 +00:00
e3de466ad1 Merge pull request 'Complete direct CLI lane concurrency omitted by #30 (supersedes #31)' (#35) from feature/hermes-direct-cli-lane-concurrency-2-replacement into main
Some checks failed
Tests / Declarative: Post Actions failed: 36, skipped: 7, passed: 2591
Reviewed-on: atlas/titan-iac#35
Reviewed-by: bstein <bstein@noreply.scm.bstein.dev>
2026-08-21 07:58:17 +00:00
66a537ddbe Merge branch 'main' into feature/hermes-direct-cli-lane-concurrency-2-replacement 2026-08-21 07:57:35 +00:00
8ace4d47e1 Merge pull request 'refactor(hermes): rename chat and triage public hostnames' (#34) from feature/hermes-domain-rename-chat-bstein-triage into main
Reviewed-on: atlas/titan-iac#34
Reviewed-by: bstein <bstein@noreply.scm.bstein.dev>
2026-08-21 07:48:55 +00:00
Hermes Agent
4277aa6a02 fix(hermes): allow two direct CLI lane workers 2026-08-21 07:11:55 +00:00
Hermes Agent
79be4d1c71 refactor(hermes): rename chat and triage public hosts 2026-08-21 06:43:19 +00:00
db70509e08 Merge pull request 'Persist Hermes per-profile Kanban concurrency of two' (#30) from feature/hermes-kanban-profile-concurrency-2 into main
Reviewed-on: atlas/titan-iac#30
Reviewed-by: bstein <bstein@noreply.scm.bstein.dev>
2026-08-21 06:12:01 +00:00
468b21beb7 Merge branch 'main' into feature/hermes-kanban-profile-concurrency-2 2026-08-21 06:11:08 +00:00
25fcda010f Merge pull request 'feat(hermes-voice): add premium conversation instrument' (#29) from hermes/chat-voice-conversation-instrument into main
Reviewed-on: atlas/titan-iac#29
Reviewed-by: bstein <bstein@noreply.scm.bstein.dev>
2026-08-21 04:06:44 +00:00
bf38f81787 Merge branch 'main' into hermes/chat-voice-conversation-instrument 2026-08-21 04:06:31 +00:00
flux-bot
0c264e873b chore(maintenance): automated image update 2026-08-21 01:50:29 +00:00
flux-bot
79c1809286 chore(maintenance): automated image update 2026-08-21 01:49:29 +00:00
flux-bot
287b61ed3e chore(maintenance): automated image update 2026-08-21 01:46:27 +00:00
flux-bot
12f568e78b chore(maintenance): automated image update 2026-08-21 01:41:26 +00:00
Hermes Agent
dda2d5fb60 fix(hermes): persist per-profile Kanban concurrency 2026-08-21 00:27:38 +00:00
Hermes Agent
c8f53ecdf5 feat(hermes-voice): add conversation state instrument 2026-08-20 23:13:51 +00:00
flux-bot
33534e3b52 chore(bstein-dev-home): automated image update 2026-08-20 21:59:54 +00:00
flux-bot
ded90b607a chore(bstein-dev-home): automated image update 2026-08-20 21:57:54 +00:00
ac01fbd38a Merge pull request 'fix(hermes): poll the session contract the chat tenants actually serve' (#25) from fix/hermes-chat-session-continuity-contract into main
Reviewed-on: atlas/titan-iac#25
Reviewed-by: bstein <bstein@noreply.scm.bstein.dev>
2026-08-20 21:55:16 +00:00
Hermes Agent
d22588dddb fix(hermes): poll the session contract the chat tenants actually serve
Returning to chat.hermes.bstein.dev after a Keycloak logout/login showed
"This session is unavailable to this account. Start a new chat." even
though the session was intact and owned by the same subject.

The banner comes from the continuity fallback the router injects into
every chat page. It polled `/api/sessions/<id>` and
`/api/sessions/<id>/messages` — routes that belong to the Hermes agent
dashboard (added by scripts/patch_web_session_activity.py, applied only
in agent-deployment.yaml). The router proxies browser traffic to the
tenant Hermes WebUI instead, whose only session read is
`GET /api/session?session_id=<id>`; the dashboard paths are unrouted
there, so server.py answered its generic 404 for every poll and the
fallback reported a false ownership failure.

The script runs only on a full document load of `/session/<id>`, which is
exactly what the OIDC round-trip produces when oauth2-proxy returns the
browser to `rd=/session/<id>` — hence the "only after relogin" symptom.

Poll the WebUI contract instead, and let its own answers decide what the
banner claims: 409 `session_profile_mismatch` is the single response that
means the session is outside this account's active scope, 404 now means
the conversation is no longer stored, and 401/403 still re-enter OIDC.
The steady-state poll drops to one request and backs off to 3s/15s now
that it reaches a real endpoint on the tenant Raspberry Pi.

`boundSessionSnapshot` follows the same move: it caps the WebUI envelope
`{"session": {..., "messages": [...]}}`, relaying every other session key
verbatim rather than re-serializing a fixed struct that would silently
drop metadata the banner depends on.

Isolation is unchanged and now covered: the router still resolves the
slot from the salted Keycloak subject, overwrites any client-supplied
X-Hermes-Tenant-Identity, and forwards only the two tenant cookies.

Tests: relogin keeps a stable slot and resolves the durable session; a
second subject replaying the owner's session id, WebUI cookie and a
forged tenant header gets 404 from its own backend and never reaches the
owner's; the legacy dashboard paths are pinned as permanent 404s against
a stub of the deployed WebUI dispatch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 18:14:55 +00:00
flux-bot
11bd04cce5 chore(maintenance): automated image update
Some checks failed
Tests / Declarative: Post Actions failed: 35, skipped: 7, passed: 2586
2026-08-20 13:49:00 +00:00
flux-bot
1c731b5baa chore(maintenance): automated image update 2026-08-20 13:48:53 +00:00
flux-bot
16bf178b18 chore(maintenance): automated image update 2026-08-20 13:45:52 +00:00
flux-bot
ce0b81c49f chore(maintenance): automated image update 2026-08-20 13:39:52 +00:00
flux-bot
347183090a chore(bstein-dev-home): automated image update 2026-08-20 09:53:23 +00:00
flux-bot
b036fbba88 chore(bstein-dev-home): automated image update 2026-08-20 09:51:23 +00:00
flux-bot
a45a9b67fe chore(maintenance): automated image update
Some checks failed
Tests / Declarative: Post Actions failed: 35, skipped: 7, passed: 2586
2026-08-20 01:51:22 +00:00
flux-bot
58d6da2fac chore(maintenance): automated image update 2026-08-20 01:50:23 +00:00
flux-bot
1a82ab4912 chore(maintenance): automated image update 2026-08-20 01:47:21 +00:00
flux-bot
4d026ff2b4 chore(maintenance): automated image update 2026-08-20 01:42:20 +00:00
9872ee0995 Merge pull request 'fix(monitoring): keep VictoriaMetrics writable so public dashboards render' (#23) from hermes/fix-grafana-no-data-vm-storage into main
Reviewed-on: atlas/titan-iac#23
Reviewed-by: bstein <bstein@noreply.scm.bstein.dev>
2026-08-20 00:50:00 +00:00
2b683d9775 Merge branch 'main' into hermes/fix-grafana-no-data-vm-storage
Some checks failed
Tests / Declarative: Post Actions failed: 35, skipped: 7, passed: 2586
2026-08-20 00:49:40 +00:00
flux-bot
417355b2af chore(bstein-dev-home): automated image update 2026-08-19 22:00:51 +00:00
flux-bot
4470e1e3ae chore(bstein-dev-home): automated image update 2026-08-19 21:57:51 +00:00
flux-bot
00741d6830 chore(maintenance): automated image update
Some checks failed
Tests / Declarative: Post Actions failed: 40, skipped: 7, passed: 2578
2026-08-19 13:48:54 +00:00
flux-bot
33b373fffe chore(maintenance): automated image update 2026-08-19 13:48:48 +00:00
flux-bot
5c23790df9 chore(maintenance): automated image update 2026-08-19 13:45:48 +00:00
flux-bot
297dd27db3 chore(maintenance): automated image update 2026-08-19 13:40:47 +00:00
Hermes Agent
c4eac8ceee fix(monitoring): keep VictoriaMetrics writable 2026-08-19 10:51:44 +00:00
flux-bot
8675cb81d0 chore(bstein-dev-home): automated image update 2026-08-19 10:09:21 +00:00
jenkins
e28b32bd4e hermes: run the reviewed agent image and arm the takeover
Some checks failed
Tests / Declarative: Post Actions failed: 40, skipped: 7, passed: 2578
Pins hermes-agent to sha256:4a385fbd, built by hermes-agent-image #11 from
this exact main revision through the daemonless Kaniko lane. Enables
kanban.auto_supervise and returns chat tenancy to the documented four slots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 23:55:14 -03:00
flux-bot
493c1a1f4f chore(maintenance): automated image update 2026-08-19 02:03:02 +00:00
flux-bot
776b70e11a chore(maintenance): automated image update 2026-08-19 01:48:59 +00:00
jenkins
87f2c58e32 ci(hermes-agent-image): keep image file modes world-readable
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 22:35:18 -03:00
jenkins
baeb70e8b7 ci(hermes-agent-image): pull the base mirror inside the cluster network
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 20:44:36 -03:00
jenkins
fcbff58951 ci(hermes-agent-image): let release verification read the build evidence
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 20:32:00 -03:00
jenkins
b6ae6225f6 hermes: source handoff forge evidence through the scm broker
The acceptance harness pinned a forge client that has never existed in any
commit or pod (/opt/coordinator/gitea_api.py, digest f0943db4..., GIT/POST
grammar, an askpass helper). Every Gitea-backed check was therefore
unrunnable as merged. Point the harness at the credential-isolated SCM
broker client that actually ships in the agent pod.

- policy: GITEA_CLIENT=/opt/scm/gitea_api.py; trust /opt/scm/ instead of
  the phantom /opt/coordinator/; admit the client's real grammar
  (`read <api-path>`, exactly one path) with the same atlas/titan-iac pin
  and dot-segment rejection; bare HTTP methods are refused in every mode.
  The armed POST/PATCH/DELETE windows remain but are documented as
  deferred: the deployed client cannot execute them.
- exec: pin the client digest to the sha256 of
  services/hermes/scm-common/scripts/gitea_api.py — the exact file the
  hermes-scm-boundary-v2 ConfigMap mounts at /opt/scm/gitea_api.py — so
  the pin is derivable from merged source and equal to the deployed
  client. gitea_api.py gains a narrow /api/v1/user identity read in
  _authorize_read (see below), so the pin is the NEW source hash
  76efd16dedbeb74425b12fbbdbfaa391854771292077e0463bf22706855ae6dc.
  Drop the dangling GIT_ASKPASS (no helper exists; broker git needs
  none) and swap /opt/coordinator for /opt/scm in SAFE_PATH.
- checks: all forge/baseline/lineage probes use (client, "read", path).
  The SELF-vantage identity checks now truthfully assert the *broker's*
  forge identity (the only one the platform can exercise) is not an
  administrator and holds push-scoped, non-administrative repository
  authority; the administrative-route check asserts the broker read
  allowlist's live refusal of branch_protections. The remote-main step
  keeps `origin` (the broker remote exists only in pool workspaces and
  the broker origin is cluster-local); its rationale now tells the
  operator to ensure origin fetchability.
- gitea_api.py/_authorize_read: allow exactly `/api/v1/user` (no query,
  no sibling routes) as operation "identity" so the harness can prove
  the broker identity is not an administrator. The broker imports the
  same module, so one reviewed edit covers both sides of the boundary.
- rules: DENIAL_MARKERS now match the client's real refusal lines
  ("SCM broker request failed with HTTP 400/403" and the no-credential
  rejection) and drop "gitea api returned http 403", which the client
  never emits; a broker 404 is deliberately not denial evidence.
- ephemeral: index/verification reads use the real grammar; manual
  cleanup guidance now says close/delete require operator forge
  credentials (the client exposes no mutation besides create-draft);
  armed mode is documented as deferred until the probes are rebuilt on
  the broker's bounded mutation surface.
- docs: broker vantage/evidence section, operator prerequisites (broker
  healthy, no /vault/secrets/gitea-token anywhere on the harness path,
  current ConfigMap mount, operator-side client + origin fetchability),
  armed-mode deferral.
- tests: read-grammar accepted / GET refused in every mode, /opt/scm
  attestation pin proven equal to the merged source digest, real
  denial-marker matching, /api/v1/user identity route bounds; the
  repository-pin mutant probe speaks the new grammar. Full handoff +
  gitea + broker families pass (952 tests), mutation gate 13/13, per-file
  line+branch coverage >=95%, all touched sources within the 500-line cap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 18:21:38 -03:00
jenkins
e85fc7e633 hermes: deploy friendly automatic model labeling to consumer chat
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 18:21:37 -03:00
jenkins
0b25056d4e hermes: let the scm broker actually reach the forge ingress
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-18 18:21:27 -03:00