Repository navigation
Conversation
Serve the built console SPA from the web port alongside gRPC-Web and the health probes so one harmonograf-server process hands a browser the whole console — no separate static host or frontend dev server. - static_site.py wraps the gRPC-Web/health ASGI app: GET/HEAD for non-API paths serve index.html + real files from the web root, with an index.html SPA fallback for unknown paths (e.g. #/session/<id> deep links). gRPC-Web content-type requests, gRPC service-method paths, and health routes always pass through untouched. The bundle is located via --web-root, then the packaged _console dir (importlib.resources), then ../frontend/dist; a clear warning + graceful degradation when none is found. - Runtime endpoint config: the served index.html gets a window.__HARMONOGRAF_API__ global injected (derived from Host/X-Forwarded-* or --public-base-url), and transport.ts now resolves the gRPC-Web base URL runtime-global → VITE env → compiled-in default, so one built bundle works behind any host/port without a rebuild. - App.tsx parses #/session/<id> on load and hashchange and selects that session in the UI store (eagerly, so it survives ListSessions auto-select), via a small sessionRoute helper. - Packaging: make console builds the frontend into harmonograf_server/_console/; pyproject ships it in the wheel via the hatchling artifacts glob, located at runtime through importlib.resources. Adds server + frontend tests; documents the approach in server/README.md.
Follow-up fixes from PR #294 review: - frontend: apply the #/session/<id> deep link once per target instead of re-firing on every ListSessions poll. Previously a user who deep-linked to session A and then picked session B (which updates the store, not the hash) was dragged back to A on the next poll. Adds a regression test. - server: cache index.html at startup (immutable build artifact) instead of a blocking disk read per request on the event loop shared with gRPC-Web streaming; off-load asset reads via asyncio.to_thread. - server: send Cache-Control: immutable for content-hashed /assets/*; keep index.html no-cache. - server: a missing file-like path (*.js/*.svg) now returns 404 instead of the SPA index.html fallback (avoids MIME-mismatch errors; also fixes favicon.svg). - server: emit the injected window.__HARMONOGRAF_API__ via json.dumps (+ </ guard) instead of hand-rolled escaping. - server: HEAD responses carry headers + Content-Length but no body. - tests: add coverage for _safe_join traversal, 404-for-missing-asset, asset cache header, HEAD no-body, and injection escaping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ional transfer chord, compose parity Make the agent-interaction sequence diagram the recommended sequence view: one vertical lifeline per agent, time down, each message a horizontal connector with an explicit arrowhead (call solid, return dashed). The horizontal score becomes the Gantt-companion alternative. Pair the diagram with a directional transfer chord that encodes who-initiates-vs-who-receives three redundant ways (split outbound/inbound arc sectors, asymmetric source-pinched/target-broad ribbons, source-to-target hue + landing arrowhead). Update figure 11 in the grammar to the directional version. Close information parity across the three composed-console proposals: every piece of session information surfaced in any one proposal is now reachable in all three (sequence diagram, topology chord, plan DAG/strata/reel, drift, heartbeat, ladder, and the span inspector — floated as an overlay in B and C, plus a ?span= deep-link). Verified headless across monokai/paper/dracula/ belafonte-night/solarized-dark; theme switch re-skins without re-render.
…e-track stack Compose the instruments view around two coordinated reading stacks. Plan stack — the plan reel now sits directly above the plan DAG, sharing horizontal alignment, and each reel revision is a button that drives the DAG: clicking a version redraws the DAG for that version's task set (added tasks in the accent "new" treatment, tasks dropped since the prior revision ghosted and dashed like the existing live ghost). A `tid` on each DAG node bridges it to the strata task-ids so a revision's `has`/`added` set reframes the graph. The click is local UI state — it repaints only the DAG host + the reel's active marks, not the whole console (digest-gated, no flash). Defaults to the latest revision; `?ver=` deep-links one. Time-track stack — the judge heartbeat is folded INTO the drift seismograph as one instrument on a shared time axis: the drift traces as before, with judge firings overlaid (on-task ticks in the judge KIND hue, warnings/criticals in the STATUS treatment). The standalone heartbeat panel is gone from the view (still a small figure for the inspector). The intervention ladder sits directly below the seismograph and shares its exact x-domain (padL/padR/width/T via one trackGeom helper), so an intervention at time t lines up vertically under the drift reading at t, with a single shared bottom axis. Preserves the 16-theme ANSI system and KIND=hue / STATUS=treatment grammar; standalone HTML/CSS/JS, no build; theme switch re-skins without a re-render. Verified headless across monokai, paper, dracula, belafonte-night and all three plan revisions.
…, span-connecting gantt edges - arrowheads (chord, gantt edges, sequence diagram) → small SOLID triangles - topology chords → thin gradient strokes (width min(4, 0.9+√count·1.1), non-scaling) instead of filled teardrops; arc caps 4.5px non-scaling - gantt transfer/delegation edges connect span-end → span-start with a landing arrowhead - judge heartbeat derived from the drift so its marks align with the seismograph excursions Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s the multi-plan prefix The header's "Plan N · " prefix (#195, written for a merged-trajectory model) was superseded when the plan picker (#196) landed: the picker scopes the view model to one plan and conveys plan identity via its chip bar, so a header prefix is redundant. #196 left #195's two prefix-tests stale → they failed. Header now stays a plain "rev N of M" (planPrefix = ''); the two stale tests assert no-prefix while keeping their rev-math coverage (denominator reads the highest revisionIndex, not the array length). Fixes the 2 pre-existing TrajectoryView.headerMath failures → full suite 740/740. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port the zicato-language UI study into the real React app as a second,
toggle-able console. Default uiMode is 'md3' so production is unchanged.
- uiStore: persisted uiMode ('md3'|'zicato', default 'md3') + setUiMode/
toggleUiMode, and a scoped zicatoTheme (16 study themes via
data-zicato-theme, never touches the MD3 :root theme).
- App.tsx branches on uiMode → ZicatoConsole vs Shell (#/stress unaffected);
toggle controls in the MD3 AppBar (⧉) and the zicato topbar.
- ZicatoConsole shell (topbar/strip/rail/main/inspector/transport) + the two
rail views (gantt, instruments); reuses the MD3 SessionPicker (⌘K).
- adapter.ts: useZicatoSession maps the live SessionStore + plan hooks into
the study's render inputs (reactive; graceful EMPTY_SESSION fallback).
- Six figures ported to React: GanttZ, ChordZ, SeismographZ/JudgeHeartbeatZ,
LadderZ, PlanZ (reel→DAG), SequenceZ, FingerprintZ; svgUtils + token CSS.
- zicato.smoke.test: console mounts against an empty store; token/agent
mappers verified.
Build/lint/tests green (740/740). NOT yet verified against a live session —
see docs/zicato-frontend-port.md for the full state + resume guide.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eak)
The MD3 global rule `.hg-rail { grid-area: rail }` leaked onto the zicato
console's rail (same class name). The zicato grid (.zk-app-body: 84px / 1fr /
auto) defines no named `rail` area, so the inherited grid-area pulled the rail
out of placement and collapsed .zk-main into the 84px first column — the gantt /
heartbeat / instruments rendered ~48px wide and "didn't scale to the screen".
Reset `grid-area: auto` on `.zk-root .hg-rail` so auto-placement restores it as
the left column and main fills the rest.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e by sub-type - GanttZ: greedy interval packing (MD3 packLanes) assigns each agent's concurrent spans to distinct sub-lanes; the agent row grows to fit its lane count, so overlapping spans no longer render on top of each other. - adapter.gfClassForSpan: goldfive's own llm spans (goal_derive / refine / judge_* / plan) carry no `goldfive.category` attribute and all fell through to one llm-call hue. Infer the sub-type from the span name (goldfive actor only) so judge / refine / plan / reflective get distinct hues. Work spans are unaffected (still coloured by KIND). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing) The figures draw into a fixed viewBox (0 0 940 H) at width:100%, so on a wide pane the whole SVG upscaled ~2× — text, bars and strokes all looked too large. New <Fig> wrapper measures the container (ResizeObserver) and passes that as the viewBox width, so 1 viewBox unit = 1 CSS px (no upscaling) while the figure still fills the pane. Threaded a W prop into GanttZ + PlanZ (its reel scales with W; the DAG's fixed 4-column x is scaled by W/940). Heartbeat / sequence / chord / seismograph / ladder already took W — now fed the measured width. Falls back to a fixed width when ResizeObserver is absent (jsdom), so the smoke test still passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gantt - ganttViewport.ts: GanttView window type + zoomView/panView/fitView/isFit helpers. - GanttZ: optional view/onViewChange props; X maps the visible window; plot clipped so a zoomed view never spills the lane gutter; wheel zooms toward the cursor, pointer-drag pans (click-vs-drag threshold keeps span selection). No view → renders exactly as before (eff = fitView(T)). - MinimapZ: full-timeline overview (one row per agent, span rects, the viewport box), click/drag to seek — the zicato-language port of MD3 Gantt/Minimap.tsx. - GanttViewZ: owns the viewport state + a − / + / fit toolbar; wires GanttZ + MinimapZ. - zicato.css: .zk-gantt-head / .zk-zoom / .zk-minimap styles. - Fig.tsx: un-export useMeasuredWidth (keep the file component-only → clears the react-refresh/only-export-components lint error from the prior scaling commit). Build + lint clean (pre-existing MD3 warning aside); zicato smoke 6/6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s, reasoning detail + floating drawer - adapter: ZSpan.hasReasoning/reasoning (via lib/thinking detection) + a ZSteer list (buildSteers: goldfive corrections → the agent/task they steered, from the refineAttempts/drift registries, severity-tagged). - GanttZ: render a 🧠 glyph on reasoning spans; draw severity-coloured steering arrows (goldfive lane → steered agent), clipped + zoom-window-aware; click → floating drawer (useSteerSelect, no-op outside the console provider). - svgUtils.steerColor; FloatingDrawerZ (port of TrajectoryFloatingDrawer: reasoning chain-of-thought + steering trigger/target detail); steerContext (SteerSelectContext + useSteerSelect, kept in its own module for fast-refresh). - ZicatoConsole: reasoning block in the inspector + the floating drawer + provider. - tests: zicato smoke 6→15 (reasoning/steer derivation); new GanttZ.zoom.test (the zoom viewport actually moves spans / fit restores — guards the prior fix). Build + lint clean; 17 zicato tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e orchestration) Emits a plan through 4 revisions (add / supersede / drop tasks, with revision reasons/kinds) to a running harmonograf server via harmonograf_client directly — no Runner/planner/LLM — so the console's plan reel + DAG can be exercised against real revision evolution. Run: HARMONOGRAF_SERVER=127.0.0.1:7531 uv run --extra orchestration python examples/standalone_observability/replan_scenario.py Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
Author
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.
Redraws the harmonograf console's sequence story in the zicato design language with the corrected framing: the sequence view shows how the agents interact — who said what to whom, when.
Task 1 — vertical sequence diagram is now the recommended view
sequence.htmlis restructured so Option B (the vertical staff) is the RECOMMENDED, primary view, redrawn to read unambiguously as an agent-interaction sequence diagram: one vertical lifeline per agent (neutral, with a name chip), time flowing down, each message a horizontal connector from sender to receiver with an explicit arrowhead — solid for a call, dashed for a return — and the label above in the KIND hue. Activations hug the lifelines; the delegation opens a child band on the tester lifeline and returns; the approval is a gate; the failed check is the only red. Messages use a minimum-row-gap layout so a near-coincident call+return never overprint. The horizontal score becomes the explicit Gantt-companion alternative; the UML frame stays as the before.Task 2 — directional transfer chord
Figure 11 in
grammar.html(mountChord) is rebuilt so direction is obvious three redundant ways at once:"Who talks to whom AND in which direction" is legible at a glance, and it stays legible even on
belafonte-nightwhere the ANSI kind hues collapse (direction carried by treatment, not hue). The same chord is incorporated into the sequence view as the communication-topology summary beside the time-ordered diagram.Task 3 — information parity across the three compose proposals
Audited what each proposal surfaced from the session model and closed every gap so no proposal is missing what the others expose:
?span=deep-link.Constraints / verification
Preserves the zicato design language, the 16-theme ANSI-sourced categorical system, and the KIND=hue / STATUS=treatment grammar. Standalone HTML/CSS/vanilla-JS, no build, no network. Theme switch re-skins without a re-render;
_embed.js?only/?bare/?themestill works (smoke-tested on the 3 restructured sequence sections). Verified headless across monokai, paper, dracula, belafonte-night, and solarized-dark.