Files
agentmon/docs/plans/2026-01-17-ui-query-validation-design.md
T
William Valentin d748033851 docs: add UI, query API, and validation design
Design for Sessions/Run views, three new query-api endpoints,
and schema validation at ingest-gateway.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 01:43:04 -08:00

5.2 KiB

UI, Query API, and Schema Validation Design

Date: 2026-01-17

Overview

This design covers three related improvements to agentmon:

  1. Web UI — Sessions list, session detail, and run detail views
  2. Query API — New endpoints to support the UI
  3. Schema Validation — Required field validation at ingest-gateway

URL Structure

URL View Description
/ Redirect Redirects to /sessions
/sessions Sessions List Recent sessions, filterable
/sessions/:session_id Session Detail Runs within a session
/runs/:run_id Run Detail Spans within a run

Query parameters for filtering:

  • /sessions?from=2026-01-17&to=2026-01-18 — time range
  • /sessions?framework=opencode — filter by framework
  • /sessions?host=willlaptop — filter by host
  • Parameters combine: /sessions?framework=claude-code&host=willlaptop

Query API Endpoints

GET /v1/sessions

List sessions with filters.

Query params:

  • from, to — ISO timestamps (default: last 24h)
  • framework — filter by source framework
  • host — filter by source host
  • limit — max results (default 50, max 200)
  • cursor — pagination token (opaque, timestamp-based)

Response:

{
  "sessions": [
    {
      "session_id": "s1",
      "started_at": "2026-01-17T08:00:00Z",
      "ended_at": "2026-01-17T09:30:00Z",
      "framework": "claude-code",
      "host": "willlaptop",
      "run_count": 5
    }
  ],
  "next_cursor": "..."
}

GET /v1/sessions/:session_id

Session detail with runs.

Response:

{
  "session": {
    "session_id": "...",
    "started_at": "...",
    "ended_at": "...",
    "framework": "...",
    "host": "..."
  },
  "runs": [
    {
      "run_id": "r1",
      "started_at": "...",
      "ended_at": "...",
      "status": "success",
      "span_count": 12
    }
  ]
}

GET /v1/runs/:run_id

Run detail with spans.

Response:

{
  "run": {
    "run_id": "...",
    "session_id": "...",
    "started_at": "...",
    "ended_at": "...",
    "status": "..."
  },
  "spans": [
    {
      "span_id": "sp1",
      "name": "Bash",
      "kind": "tool",
      "started_at": "...",
      "duration_ms": 1234,
      "status": "success",
      "payload": {}
    }
  ]
}

UI Views

Sessions List

Default view showing last 24 hours, most recent first.

Layout:

  • Filter bar: time range (from/to), framework dropdown, host dropdown
  • Table columns: Session ID, Framework, Host, Run Count, Time (relative)
  • Click row to navigate to session detail
  • "Load more" button for pagination

Session Detail

Shows session metadata and all runs within it.

Layout:

  • Header: Session ID, framework, host, start time, total duration
  • Back link to sessions list
  • Runs table: Run ID, Status, Span Count, Duration, Start Time
  • Click row to navigate to run detail

Status indicators:

  • Green checkmark for success
  • Red X for error
  • Yellow circle for running/unknown

Run Detail

Shows run metadata and all spans within it.

Layout:

  • Header: Run ID, status, start time, duration
  • Back link to session detail
  • Spans table: Name, Kind, Status, Duration
  • Click row to expand/collapse details

Expanded span shows:

  • Model name, tokens, cost (for LLM spans)
  • Error details (for failed spans)
  • Raw payload JSON

Schema Validation

Validation performed at ingest-gateway before publishing to NATS.

Required Fields

All events must include:

schema.name          = "agentmon.event"
schema.version       = 1
event.id             — non-empty string
event.type           — one of: session.start, session.end, run.start,
                       run.end, span.start, span.end, error, metric.snapshot
event.ts             — valid timestamp (RFC3339 or unix-ms)
event.source.framework   — non-empty string
event.source.client_id   — non-empty string
event.source.host        — non-empty string

Validation Responses

Scenario HTTP WebSocket
Valid 202 Accepted {"ack": {"seq": N}}
Missing field 400 + error {"error": "missing_field", "field": "..."}
Invalid type 400 + error {"error": "invalid_type", "value": "..."}
Unknown fields Allow Allow

Non-strict mode: unknown fields in correlation, attributes, and payload are stored as-is.

Frontend Implementation

Technology: Vanilla JavaScript (no framework, no build step).

File structure:

cmd/web-ui/static/
├── index.html      # Shell + router
├── app.js          # Router + page loader
├── pages/
│   ├── sessions.js
│   ├── session.js
│   └── run.js
└── style.css

Routing: History API with catch-all handler serving index.html for all routes.

Data fetching: Native fetch() to query-api endpoints via /api proxy.

Implementation Order

  1. Query API endpoints (sessions, session detail, run detail)
  2. Schema validation at ingest-gateway
  3. Frontend pages (sessions list, session detail, run detail)
  4. Rebuild and deploy

Future Considerations

  • Waterfall visualization for spans (SVG/canvas)
  • Token/cost aggregations in session/run summaries
  • Free-text search across sessions
  • Real-time updates via WebSocket subscription