Web UI
Local administration interface for outheis.
Overview
Overview
The Web UI provides a browser-based interface for configuring and monitoring outheis. It runs on localhost:8080 and is explicitly not designed for remote access — all user data stays local.
┌─────────────────────────────────────────────────────────────┐
│ outheis [Overview] [Save] │
├─────────────┬───────────────────────────────────────────────┤
│ System │ │
│ Overview │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ Config │ │Dispatcher│ │ Agents │ │Messages │ │
│ Messages │ │ Running │ │ 5/6 │ │ 42 │ │
│ Scheduler │ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ Knowledge │ Recent messages │
│ Memory │ ┌─────────────────────────────────────────┐ │
│ Skills │ │ 14:32 cato → relay Daily updated │ │
│ Rules │ │ 14:30 scheduler agenda_review │ │
│ Patterns │ │ 14:15 zeno → relay Found 3 matches │ │
│ │ └─────────────────────────────────────────┘ │
│ Vault │ │
│ Agenda │ │
│ Codebase │ │
│ Migration │ │
│ Tags │ │
└─────────────┴───────────────────────────────────────────────┘
Starting the Server
Starting the Server
cd outheis-minimal/webui
pip install fastapi uvicorn
python server.py
Opens at http://localhost:8080. The server watches ~/.outheis/human/ for changes.
Remote Access via SSH Tunnel
Remote Access via SSH Tunnel
The Web UI binds to localhost only. To access it from another machine, forward the port over SSH:
ssh -L 8080:localhost:8080 user@your-server
Then open http://localhost:8080 in your local browser. The tunnel forwards your local port 8080 to port 8080 on the remote machine — no firewall changes needed, no public exposure.
To keep the tunnel open in the background:
ssh -fNL 8080:localhost:8080 user@your-server
-f forks to background, -N suppresses shell execution.
Files View
Files View
Full browser for all configured vault directories:
- Directory tree on the left — all vaults as roots, directories collapsed by default, click to expand
- File viewer/editor on the right — same rendered/source toggle as other file views
- All file types visible in the tree:
- Text files (
.md,.txt,.json,.py, …) — editable, Save button - Image files (
.png,.jpg,.svg, …) — rendered inline, Download button - Binary files (
.pdf,.docx, …) — Download button - Obsidian wikilinks —
![[image.jpg]]and![[image.jpg|WxH]]are resolved and rendered as inline images - Delete — confirmation dialog, removes file from vault
Tags View
Tags View
The Tags view scans the vault for all #tags and presents them grouped by namespace prefix:
- Scan button — queues a
tag_scandispatcher task (same async UX as the Scheduler) - Results are cached; the scan button re-runs on demand
- Tags are grouped by namespace prefix (
#action-*,#date-*,#rank-*, etc.), all collapsed by default - Each group shows tag count and total occurrences across the vault
-
Per-tag: occurrence count, file count, rename input field, Delete button
-
#outheis-*tags are hidden (internal system use only)
Configuration Editor
Configuration Editor
The Configuration view provides a complete editor for ~/.outheis/human/config.json:
General Tab
-
User profile: Name, email, phone, language, timezone
-
Vaults: List of vault directories (primary + secondary)
Providers Tab
Three provider cards (Anthropic, OpenAI, Ollama):
- API key (password field, not stored in plain text in UI)
- Base URL (for custom endpoints or proxies)
- Status indicator (green dot when configured)
Models Tab
Model alias mapping:
fast → claude-haiku-4-5
capable → claude-sonnet-4-20250514
reasoning → claude-opus-4-5
Add/remove aliases with provider selection.
Agents Tab
Per-agent configuration:
| Agent | Name | Model | Enabled |
|---|---|---|---|
| relay | ou | capable | ✓ |
| data | zeno | capable | ✓ |
| agenda | cato | capable | ✓ |
| action | hiro | capable | ☐ |
| pattern | rumi | capable | ✓ |
| code | alan | capable | ☐ |
Each agent can use a different model alias (fast/capable/reasoning).
Signal Tab
Signal transport configuration:
- Enabled toggle
- Phone number (registered with signal-cli)
-
CLI path (default:
/usr/local/bin/signal-cli) -
Whitelist (phone numbers allowed to interact)
Scheduler
Scheduler
Manage scheduled tasks:
┌─ Task Type ─────────┬─ Times ──────────────┬─ Enabled ─┐
│ agenda_review │ 06:00 12:00 18:00 + │ ✓ │
│ shadow_scan │ 03:30 + │ ✓ │
│ pattern_nightly │ 04:00 + │ ✓ │
└─────────────────────┴──────────────────────┴───────────┘
-
+ button: Add another time (auto-increments by 1 hour)
-
× button: Remove a time (minimum one remains)
-
Checkbox: Enable/disable task
-
History tab: View past scheduler events from messages.jsonl
File Browser
File Browser
Memory, Skills, Rules, Agenda, and Codebase views share a file browser:
┌─ Files ───────┬─ Content ──────────────────────────────┐
│ common.md ✓ │ [Rendered] [Source] │
│ relay.md │ │
│ data.md │ # Common Skills │
│ │ │
│ │ ## Dates │
│ │ Always use ISO format (YYYY-MM-DD) │
│ │ │
└───────────────┴────────────────────────────────────────┘
-
Rendered: Markdown rendered as HTML (via marked.js)
-
Source: Raw text, editable (contenteditable)
-
Save: Writes changes back to disk
Live Updates
Live Updates
The Messages view uses WebSocket for real-time updates:
- Server watches
messages.jsonlfor changes - New lines are parsed and pushed to connected clients
- Messages appear instantly in the UI
Connection status shown in the status bar:
Connected— WebSocket activeDisconnected— Reconnecting in 3 secondsError— Connection failed
API Endpoints
API Endpoints
The server exposes REST endpoints:
Config
GET /api/config— Read config.jsonPOST /api/config— Write config.json
Status
GET /api/status— Dispatcher running, PID, agent count, messages today
Messages
GET /api/messages?limit=50— Recent messages from messages.jsonl
Files
-
GET /api/{type}— List files (type: memory, skills, rules, agenda, codebase) -
GET /api/{type}/{filename}— Read file content PUT /api/{type}/{filename}— Write file content
Tags
GET /api/tags— Tag scan results (cached, filtered, sorted lexically)POST /api/tags/scan— Queue tag_scan dispatcher task, returns conversation_idPOST /api/tags/rename— Rename tag across all vault filesPOST /api/tags/delete— Remove tag from all vault files
Vault Files
GET /api/vault/tree— Recursive tree of all configured vaultsGET /api/vault/file?path=— Read file (text/image/binary detection, wikilinks resolved for .md)PUT /api/vault/file— Write file contentDELETE /api/vault/file?path=— Delete fileGET /api/vault/raw?path=— Serve raw file (used for inline images and downloads)
Migration
GET /api/migration— List files in vault/Migration/GET /api/migration/{filename}— Read file contentPUT /api/migration/{filename}— Write file contentPOST /api/migration/create— Create vault/Migration directoryPOST /api/migration/upload— Upload file via multipart form
WebSocket
WS /ws— Live message stream
File Locations
File Locations
outheis-minimal/
└── webui/
├── server.py # FastAPI backend
├── index.html # HTML structure
├── style.css # Lexend Deca, light/dark mode
├── app.js # View routing, WebSocket, forms
└── assets/
├── logo.svg # outheis labs logo
└── logo.png # Fallback
Design Decisions
Design Decisions
Typography
Two font families, loaded locally as woff2:
- IBM Plex Sans — Body text, labels, inputs, navigation
- Inter — Logo
Color Modes
CSS variables support automatic light/dark mode via prefers-color-scheme. The logo inverts in dark mode.
No Authentication
The UI is localhost-only by design. No login, no sessions. If you can reach port 8080, you have full access.
Dependencies
Dependencies
Server-side:
fastapi— Web frameworkuvicorn— ASGI server
Client-side:
marked.js— Markdown rendering (CDN)- IBM Plex Sans + Inter — Typography (woff2, served locally)
No build step. No bundler. Plain files served directly.