ai web

Local developer console — chat with your agent, inspect traces, explore graph data, manage sessions, and capture eval cases. Single command, opens in browser, under 100 KB of vanilla JS and CSS, zero build step.

implemented localhost:8888 Embedded in the ai binary. No separate install. Auto-connects to a running ai serve, or spawns one if none is found.

Overview

ai web is a local reverse proxy and single-page app served from the ai binary itself. It auto-detects a running ai serve instance on localhost:8080 (configurable via --a2a) and proxies all /a2a/* traffic there. If ai serve is not found and --no-serve is not set, it spawns one as a subprocess.

  Browser  localhost:8888/ui/                                                
                                                                            │
      ▼  HTTP                                                                
  ai web   (reverse proxy + local APIs)                                      
      ├─ /ui/*               →  embedded SPA  (HTML + JS + CSS, ~80 KB)      
      ├─ /api/web-config      →  mode, a2a url, debug flag, backend status   
      ├─ /api/sessions/*      →  local session store  (JSON files on disk)   
      ├─ /api/evals/*         →  eval case capture + run                     
      ├─ /api/agents/*/trace-stream  →  SSE live trace events                
      ├─ /api/data/*          →  toolbox source list + tool invocation       
      ├─ /api/prompt-diff     →  live system prompt diff  (when --config set)
      ├─ /a2a/*               →  proxied to upstream ai serve                
      └─ /.well-known/*       →  proxied to upstream                         
                                                                            │
            ▼                                                                
      ai serve  localhost:8080   (A2A server, agent execution, MCP tools)    

Flags

All flags are optional. The simplest invocation is just ai web.

FlagDefaultDescription
--port int 8888 Listen port. 0 = OS-assigned. Auto-increments if default in use and --port not explicitly set.
--host string 127.0.0.1 Bind address. Use 0.0.0.0 with --token for team sharing on a LAN.
--a2a string http://localhost:8080 Upstream ai serve endpoint to proxy to.
--no-open false Don't auto-open the browser.
--no-serve false Proxy-only mode — don't auto-start ai serve if backend is unreachable.
--debug false Show the trace panel by default on load.
--restart false Shut down an existing ai web instance on the same port, then start fresh.
--token string "" Bearer token for authentication. When set, all API calls require Authorization: Bearer <token>. Can also be set via AI_WEB_TOKEN env var.
--config string agent.toml Path to agent.toml. When set, enables live system prompt diff watching.
--evals-dir string evals Directory for saved eval case YAML files.
--sessions-dir string .ai/sessions Directory for persistent session JSON files.
--no-persist false Disable session persistence — don't write session files to disk.
  solo dev (default)                                     
  $ ai web                                               
  $ ai web --debug                                       

  team sharing on LAN                                    
  $ ai web --host 0.0.0.0 --token mysecret               

  connect to a remote agent                              
  $ ai web --no-serve --a2a http://my-agent.internal:8080

  restart a stuck instance                               
  $ ai web --restart                                     

Layout

Two-panel layout: chat on the left, trace on the right. A persistent footer bar shows live token counts, running cost, and context window utilization. The trace panel collapses behind a toggle on narrow viewports. Session tabs appear above the chat area when multiple sessions are open.

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐                                           
│  ai web  ·  agent name  ·  model  ·  :8888  ·  [Chat]  [Data]  [Evals]   ● connected                                                                                            │
├────────────────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤                                           
│  session-1  session-2 ●  +                    │                                                                                                                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤                                          │
│                                                │                                                                                                                                │
│            CHAT PANEL                          │         TRACE PANEL                                                                                                            │
│                                                │                                                                                                                                │
│    message history · streaming response        │    post-run ASCII trace                                                                                                        │
│    system prompt toggle · prompt diff          │    LLM call boxes                                                                                                              │
│    inline tool call markers                    │    tool call nodes → click to expand                                                                                           │
│                                                │    cache hit/miss indicators                                                                                                   │
│    input box  ·  Ctrl+Enter to send            │                                                                                                                                │
│    ↑ message history                          │                                                                                                                                 │
├────────────────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤                                           
│  FOOTER BAR  ·  ↑ input / ↓ output tok  ·  cost  ·  turns  ·  context utilization bar                                                                                           │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘                                           

The top nav bar tabs between Chat, Data (graph/SQL explorer), and Evals (capture and run eval cases). Backend connection status is live-polled every 5 seconds.

Chat Panel

Streaming SSE response from the A2A backend. Messages are tagged by role. Tool call markers appear inline in the AI response. The system prompt is viewable via a toggle above the history; when --config is set a live diff appears automatically when the file changes. Press ↑ to cycle previous messages like shell history.

┌──────────────────────────────────────────────────────────────────────┐ 
│  CHAT                 ▶ system prompt  ▶ session info  [turn 3]      │
├──────────────────────────────────────────────────────────────────────┤ 
│                                                                      │
│  you   analyze the Neo4j companies schema                            │
│                                                                      │
│  ai    I'll start by examining the graph schema. Let me query        │
│        the available node labels and relationship types.             │
│                                                                      │
│         · called get_schema                                          │
│         · analyzing 12 node types, 8 relationship types              │
│                                                                      │
│        The schema has three main clusters: Organization is the       │
│        central hub with edges to Article (847k), Investment          │
│        (320k), and Person (94k).                                     │
│                                                                      │
│  you   which companies have the most article coverage?               │
│                                                                      │
│  ai    Let me run a query... ▌                                       │
│                                                                      │
├──────────────────────────────────────────────────────────────────────┤ 
│  ┌──────────────────────────────────────────────────────────────┐    │
│  │ > _                                                          │    │
│  └──────────────────────────────────────────────────────────────┘    │
│  Ctrl+Enter send  ·  ↑ history  ·  Ctrl+K palette                    │
└──────────────────────────────────────────────────────────────────────┘ 

System prompt diff. When --config agent.toml is set, a background watcher polls the file every 500 ms. If the system_prompt field changes, a unified diff appears in the system prompt toggle — useful during prompt engineering sessions.

Trace Panel

Post-run ASCII box trace rendered after each full agent response. Each LLM call is a box with model name, latency, token count, stop reason, and a collapsible input message list. Cache hits are shown inline. Tool calls appear as connector nodes between boxes. Click any tool call to open the side panel with the full query and result.

┌────────────────────────────────────────────────────────────────────────┐ 
│  TRACE                                          turn 3 / 3             │
├────────────────────────────────────────────────────────────────────────┤ 
│                                                                        │
│  ── turn 1 ──────────────────────────────────────────────────          │
│                                                                        │
│  ┌─ claude-sonnet-4-6  1.4s  832 tok  stop: end_turn         ─────┐    │
│  │  ▶ messages [1]                                   [expand]     │    │
│  └────────────────────────────────────────────────────────────────┘    │
│                                                                        │
│  ── turn 2 ──────────────────────────────────────────────────          │
│                                                                        │
│  ┌─ claude-sonnet-4-6  2.1s  1,842 tok  stop: tool_use        ────┐    │
│  │  ▶ messages [3]                                   [expand]     │    │
│  │  cache: hit  ·  cache_read: 1,204 tok                          │    │
│  └────────────────────────────────────────────────────────────────┘    │
│       │                                                                │
│  ├── get_schema ────────────────────────────── → 12 node types ───┤    │
│       │                                                                │
│  ┌─ claude-sonnet-4-6  0.8s    312 tok  stop: end_turn        ────┐    │
│  │  ▶ messages [5]                                   [expand]     │    │
│  └────────────────────────────────────────────────────────────────┘    │
│                                                                        │
└────────────────────────────────────────────────────────────────────────┘ 

Live trace events. The trace panel also subscribes to GET /api/agents/{id}/trace-stream via SSE. This delivers model_call_start events at inference time so the LLM box appears immediately when the model starts — not after the full response lands.

Tool Side Panel

Clicking a tool call node in the trace opens a side panel. The trace panel shows only the summary inline (tool_name → N rows). The side panel shows the full query, parameters, result with syntax highlighting, and latency. Press Escape to dismiss.

┌─────────────────────────────────────────────────────────────────────────────────────────────┐ 
│  CHAT                                   │ TOOL CALL  execute_read_query    [✕]              │
├──────────────────────────────────────┤  ├───────────────────────────────────────────────────┤ 
│  ai    Let me run a coverage query.  │  │ QUERY                                             │
│   ├── execute_read_query → 10 rows   │  │ MATCH (o:Organization)<-[:MENTIONS]-(a)           │
│  ai    The top 10 companies by...    │  │  WHERE NOT EXISTS { (o)<-[:HAS_SUBSIDIARY]-() }   │
│                                      │  │  RETURN o.name, count(a) AS articles              │
│                                      │  │  ORDER BY articles DESC LIMIT 10                  │
│                                      │  │                                                   │
│                                      │  │ RESULT  10 rows  ·  42ms                          │
│                                      │  │  ┌──────────────────────┬────────────┐            │
│                                      │  │  │ name                 │ articles   │            │
│                                      │  │  ├──────────────────────┼────────────┤            │
│                                      │  │  │ Apple Inc.           │ 18,420     │            │
│                                      │  │  │ Microsoft            │ 14,832     │            │
│                                      │  │  └──────────────────────┴────────────┘            │
│  ┌────────────────────────────────┐  │  │  Escape to close                                  │
│  │ > _                            │  │  │                                                   │
└──────────────────────────────────────┘  └───────────────────────────────────────────────────┘ 

Sessions

Each browser tab runs an independent session. Sessions are persisted automatically as JSON files under --sessions-dir (default .ai/sessions/) after each turn. The latest session is restored on page load. The session browser (Ctrl+K → "browse sessions") lets you search and restore past conversations.

  session tabs (above chat)                                                    

  │  neo4j-research  companies-analysis ●  untitled-3  +                      │
  │   (paused)       (active, turn 4)     (paused)                            │


  session browser  (Ctrl+K → browse sessions)                                  

  ┌──────────────────────────────────────────────────────────────┐             
  │  SESSIONS                                                                 │
  ├──────────────────────────────────────────────────────────────┤             
  │  ┌────────────────────────────────────────────────────────┐               │
  │  │  > search sessions...                                  │               │
  │  └────────────────────────────────────────────────────────┘               │
  │                                                                           │
  │  companies-analysis  14 turns  3 min ago                                  │
  │  neo4j-research       9 turns  yesterday                                  │
  │  movie-recs-test      4 turns  2 days ago                                 │
  │                                                                           │
  └──────────────────────────────────────────────────────────────┘             


  persistence API  (local to ai web, not proxied to ai serve)                  

  GET    /api/sessions           list sessions (id, created_at, turns, summary)
  GET    /api/sessions/{id}      full session JSON (messages array)            
  PUT    /api/sessions/{id}      write/overwrite session  (10 MB max)          
  DELETE /api/sessions/{id}      remove session file                           

Use --no-persist to disable disk writes — sessions live in browser memory only. Session IDs are path-validated server-side to prevent directory traversal.

Data Explorer

Switch to the Data tab to explore the connected graph or SQL sources directly. Supports multiple source types (Neo4j, SQL, MongoDB, Redis, and any other mcp-toolbox source). Write queries are detected and require confirmation before execution.

┌───────────────────────────────────────────────────────────────────┐
│  DATA  [ companies2 (neo4j) ▾ ]   Schema  Cypher  Visual          │
├───────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ── Cypher playground ──────────────────────────────────────      │
│                                                                   │
│  ┌───────────────────────────────────────────────────────────┐    │
│  │ MATCH (o:Organization)<-[:MENTIONS]-(a:Article)           │    │
│  │ RETURN o.name, count(a) AS articles                       │    │
│  │ ORDER BY articles DESC LIMIT 10                           │    │
│  └───────────────────────────────────────────────────────────┘    │
│  [ Run  Ctrl+Enter ]  ↑ query history                             │
│                                                                   │
│  RESULT  10 rows  ·  38ms                                         │
│  ┌──────────────────────────────┬────────────────────────────┐    │
│  │ name                         │ articles                   │    │
│  ├──────────────────────────────┼────────────────────────────┤    │
│  │ Apple Inc.                    │ 18,420                    │    │
│  │ Microsoft                     │ 14,832                    │    │
│  │ Google                        │ 13,291                    │    │
│  └──────────────────────────────┴────────────────────────────┘    │
│  [Table]  [JSON]  [CSV ↓]                                         │
│                                                                   │
└───────────────────────────────────────────────────────────────────┘

Schema view. Clicking a node label in the schema tab auto-inserts a MATCH (n:Label) RETURN n LIMIT 25 template in the query editor. Fulltext and vector indexes are listed separately.

SQL sources. When the connected mcp-toolbox source is a SQL database, the playground switches to parameterized SQL with write-keyword detection (INSERT, UPDATE, DELETE, DROP, TRUNCATE) and requires explicit confirmation before execution. Results are sortable by column; CSV download is available.

Source switcher. The dropdown at the top lists all sources configured in toolbox.yaml. Switching sources reloads the schema and clears the query editor.

Eval Integration

Press Ctrl+Shift+S to save the current conversation as an eval case. A modal opens with the full conversation pre-filled so you can review and edit the expected response before saving. Cases are written as YAML to evals/ (configurable via --evals-dir). The Evals tab lets you list, run, and export cases. After a run, pass/fail badges appear inline in the chat history.

  save eval case  (Ctrl+Shift+S)                                          

  ┌──────────────────────────────────────────────────────────────────────┐
  │  SAVE AS EVAL CASE                                                   │
  ├──────────────────────────────────────────────────────────────────────┤
  │  name                                                                │
  │  ┌──────────────────────────────────────────────────────────────┐    │
  │  │ neo4j-schema-coverage-ranking                                │    │
  │  └──────────────────────────────────────────────────────────────┘    │
  │  expected output  (edit before saving)                               │
  │  ┌──────────────────────────────────────────────────────────────┐    │
  │  │  you  which companies have the most article coverage?        │    │
  │  │  ai   Apple Inc. (18,420), Microsoft (14,832)...  ▌          │    │
  │  └──────────────────────────────────────────────────────────────┘    │
  │  → saved to  evals/neo4j-schema-coverage-ranking.yaml                │
  │    [ Save  Ctrl+Enter ]    [ Cancel  Escape ]                        │
  └──────────────────────────────────────────────────────────────────────┘


  eval markers in chat after a run                                        

  │  you   which companies have the most article coverage?  ✓ pass       │
  │  you   what are the sentiment trends for Apple?         ✗ fail       │


  eval YAML format                                                        

  name: neo4j-schema-coverage-ranking                                     
  input: "which companies have the most article coverage?"                
  expected_output: "Apple Inc. (18,420 articles)..."                      
  conversation:                                                           
    - role: user                                                          
      content: "which companies have the most article coverage?"          
    - role: assistant                                                     
      content: "Apple Inc. leads with 18,420 articles..."                 

Eval runs are sent to the eval sidecar at http://127.0.0.1:8093/eval/run (start with ai sidecar start eval-bridge). Results and pass/fail scores are returned per case and displayed in the Evals tab. Export all cases as a JSON array via GET /api/evals/export.

Auth & Team Sharing

By default ai web binds to 127.0.0.1 with no authentication — solo dev mode. To share with teammates on a LAN, add --host 0.0.0.0 and a --token. Team members enter the token once in the browser; it is stored in sessionStorage for the tab lifetime.

  solo dev  (default)                                    
  $ ai web                                               
  →  no auth  ·  binds 127.0.0.1  ·  all requests allowed

  team sharing on LAN                                    
  $ ai web --host 0.0.0.0 --token mysecret               
  →  Bearer token required on all /api/* endpoints       
  →  browser prompts once, stores in sessionStorage      
  →  constant-time comparison prevents timing attacks    

  env var alternative                                    
  $ AI_WEB_TOKEN=mysecret ai web --host 0.0.0.0          

  auth-exempt paths  (no token required)                 
  GET  /ui/*             static assets                   
  GET  /api/web-config   mode + connection status        
  GET  /api/health       port conflict detection         
  POST /api/reload       signal proxy reload             
  POST /api/shutdown     graceful shutdown               

CORS headers are currently echoed back for any origin, making ai web safe for loopback and LAN use. For public internet deployment, a dedicated reverse proxy with a stricter CORS policy and TLS termination is recommended.

Keyboard Shortcuts

Keyboard-first navigation — consistent with the terminal-first brand.

Shortcut Action
Ctrl+Enter / Cmd+EnterSubmit message (chat) or run query (data explorer)
↑Cycle previous messages in chat input (shell-style history)
Ctrl+KCommand palette — new session, browse sessions, toggle trace, clear, save eval
Ctrl+Shift+SSave current conversation as eval case
EscapeClose tool side panel / dismiss modal
  Ctrl+K command palette                                      

  ┌──────────────────────────────────────────────────────────┐
  │  ┌────────────────────────────────────────────────────┐  │
  │  │  > _                                               │  │
  │  └────────────────────────────────────────────────────┘  │
  │                                                          │
  │    new session                                           │
  │    browse sessions                                       │
  │    toggle trace panel                                    │
  │    clear conversation                                    │
  │    save as eval case                                     │
  │    view system prompt                                    │
  │    data explorer                                         │
  │                                                          │
  └──────────────────────────────────────────────────────────┘

Local API

ai web exposes a small HTTP API on its own port for tooling and scripting. These endpoints are served locally and are distinct from the upstream A2A API on :8080.

EndpointDescription
GET /api/healthServer signature — used for port conflict detection. Returns {"server":"ai-web","port":N}.
GET /api/web-configMode, upstream A2A URL, debug flag, backend status, auth enabled flag.
GET /api/backend-statusLive connection status to ai serve. Polled every 5 s by the browser.
GET /api/prompt-diffUnified diff of system prompt since startup. Only populated when --config is set.
GET /api/sessionsList sessions (id, created_at, updated_at, turn count, summary).
GET /api/sessions/{id}Full session JSON including messages array.
PUT /api/sessions/{id}Write session (10 MB max body).
DELETE /api/sessions/{id}Delete session file.
POST /api/evalsSave eval case as YAML (512 KB max).
GET /api/evals/listList YAML files in evals directory.
POST /api/evals/runRun eval cases via eval sidecar at :8093.
GET /api/evals/exportDownload all eval cases as a JSON array.
GET /api/data/sourcesList toolbox sources (name, kind, status).
POST /api/data/toolInvoke an MCP tool directly (schema introspection or query execution).
GET /api/graph/statusWhether a graph backend is configured and reachable.
GET /api/agents/{id}/trace-streamSSE stream of live trace events for a task. Query param: task_id.
POST /api/reloadSignal the running instance to reload its proxy target.
POST /api/shutdownGraceful shutdown.