Skip to content

feat(gateway): presence + traffic web console (MVP, mocked mesh)#215

Merged
hartsock merged 2 commits into
mainfrom
feat/gateway-web-console-mvp
Jul 11, 2026
Merged

feat(gateway): presence + traffic web console (MVP, mocked mesh)#215
hartsock merged 2 commits into
mainfrom
feat/gateway-web-console-mvp

Conversation

@hartsock

@hartsock hartsock commented Jul 8, 2026

Copy link
Copy Markdown
Member

Summary

agent-bridle-gateway — a new workspace crate: an axum HTTP/WebSocket server that serves a self-contained two-tab operator web console, the "web UI first" cut of the LLM-flight-recorder + WebAuthn-presence plan (#214).

  • Presence tab — real WebAuthn enrollment (navigator.credentials.create, user-verification required, ES256 and EdDSA offered) and a discharge/approval round-trip (navigator.credentials.get) over a WebSocket. The gateway binds the WYSIWYS Challenge via agent-bridle-core::step_up (reused, never forked), assembles the core Discharge, and relays it to a mock MeshDischargeProvider. It performs no verification itself — the gateway is untrusted for authority (§8.3); the work-box gate re-verifies against the enrolled credential.
  • Traffic tab — a live LlmFlowRecord table (the iptraf-for-LLM view) fed by a deterministic mock flow source over the same WebSocket.

Vertical slice, mocked mesh (the chosen MVP shape): the browser WebAuthn ceremony and the HTTP/WS transport are real; only the agent-mesh Bus leg and the gate's verification are stubbed, so the whole operator UX is drivable end-to-end before the mesh transport (P-d), the ES256 verifier (P-e), and enrolled-credential pinning (§7.2) land.

Honesty preserved throughout (the repo's "never overclaim" rule): the console's banner states the untrusted-relay posture, and the approval screen flags that the action summary is advisory, not bound into the signature (§8.5 WYSIWYS limit).

Home decision

A new workspace member, not airship/drake-agent — the gateway hard-reuses agent-bridle-core::step_up, and a separate repo would fork that crypto surface (the drift the newt mobile doc warns against). Heavy async deps (axum/tokio) stay isolated to this crate, out of the lean core (ADR 0008); publish = false. airship deploys it later; the homelab TLS/PKI supplies the secure origin off-localhost.

Test plan

  • 9 unit tests — challenge binding (reuses core), discharge assembly (well-formed / refused / malformed), single-use + generation-bump, mock-flow ordering/fidelity, enrollment count.
  • 4 end-to-end tests — a real server on an ephemeral loopback port: serves the console + assets, /api/status + /api/presence/enroll/options (ES256+EdDSA/UV-required) + /api/traffic, and a full tokio-tungstenite WebSocket presence round-trip (hello + flows → simulate_requestdischarge_request → assertion → discharge_result).
  • Ran the live binary: serves the console (both tabs, real navigator.credentials), mesh:mocked, returns flow records.
  • cargo fmt --check, cargo clippy --all-targets -D warnings, and the full pre-push matrix (workspace tests + coverage ≥75% + publish-check) all green.

To try it: cargo run -p agent-bridle-gateway → open http://localhost:8787.

Follows the plan in #214; the deferred prerequisites (P-d/P-e, §7.2 pinning, the real MeshDischargeProvider, and the §8.5 WYSIWYS binding) are documented there.

🤖 Generated with Claude Code

…(MVP, mocked mesh)

WHAT: A new workspace crate 'agent-bridle-gateway': an axum HTTP/WS server that
serves a self-contained two-tab operator web console.
  - Presence tab: real WebAuthn enrollment (navigator.credentials.create, UV
    required, ES256+EdDSA offered) and a discharge/approval round-trip
    (navigator.credentials.get) over a WebSocket. The gateway binds the WYSIWYS
    Challenge via agent-bridle-core::step_up (reused, never forked), assembles the
    core Discharge, and relays it to a MOCK MeshDischargeProvider — performing NO
    verification itself, because the gateway is untrusted for authority (§8.3): the
    work-box gate re-verifies against the enrolled credential.
  - Traffic tab: a live LlmFlowRecord table (the iptraf-for-LLM view) fed by a
    deterministic mock flow source over the same WebSocket.

WHY: Realizes the 'web UI first' decision for the LLM-flight-recorder + WebAuthn
plan (PR #214). It is the vertical slice the operator chose: the browser WebAuthn
ceremony and the HTTP/WS transport are REAL; only the agent-mesh Bus leg and the
gate's verification are stubbed, so the whole operator UX is drivable end-to-end
before the mesh transport (P-d), the ES256 verifier (P-e), and enrolled-credential
pinning (§7.2) land. Honesty is preserved throughout: the console states the
untrusted-relay posture and the unbound-action-summary (§8.5 WYSIWYS) limit.

Home: a NEW workspace member (not airship/drake) because it hard-reuses
agent-bridle-core::step_up; a separate repo would fork that crypto surface. Heavy
async deps (axum/tokio) stay isolated to this crate, out of the lean core (ADR
0008); publish=false. airship deploys it later; the homelab TLS/PKI supplies the
secure origin off-localhost.

Tests: 9 unit + 4 end-to-end (real server on an ephemeral port; HTTP asset/JSON
checks + a full tokio-tungstenite WebSocket presence round-trip). Ran the live
binary: serves the console, offers ES256+EdDSA/UV-required, returns flow records.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hartsock hartsock added the risk:low Low-risk change label Jul 8, 2026
…eway

Cargo.lock is tracked; the new gateway crate's dependency tree (axum,
axum-core, tokio-tungstenite, tungstenite, matchit, etc.) must be committed
so CI builds reproducibly (a --locked build would otherwise fail).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@hartsock hartsock merged commit 5a8bc65 into main Jul 11, 2026
13 of 14 checks passed
hartsock added a commit that referenced this pull request Jul 11, 2026
Patch release: everything merged since the 0.7.1 bump — the presence +
traffic web console MVP (#215), in-memory-seam net_proxy tests (#166,
#216), and the flight-recorder / WebAuthn-presence design plan (#214).
Published crates (core, tool-shell, tool-web, facade, mcp) are
unaffected in API; downstream "0.7" pins (newt-agent) pick this up
without a manifest change.

agent-bridle-gateway (new in #215, unpublished) carried its own
hardcoded version — bumped in lock-step here; converting it to
version.workspace = true is a follow-up.


Claude-Session: https://claude.ai/code/session_01U3LeKBnJvMtHBp9vESiTzs

Co-authored-by: Shawn Hartsock <hartsock@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:low Low-risk change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant