# Build Prompt — VeilCLI Dashboard (Frontend GUI + CLI Command)

## What You Are Building

A browser-based GUI for VeilCLI — a local autonomous AI agent runtime with a REST API. The goal is a clean, functional interface that exposes every meaningful feature of the API. Think of it as a developer dashboard / agent dashboard: you can chat with agents, monitor tasks, browse sessions, manage memory, trigger daemons, and watch the live event stream.

This is not a demo page — it needs to be genuinely usable as a day-to-day control surface for someone running VeilCLI in production.

---

## Read the API Docs First

Before writing a single line of code, read the full API reference:

```
/home/ixi/khacloud/drive/Plugins/VeilCli/docs/
```

The `api/` subfolder has one file per API area. The `guide/` subfolder explains concepts (agents, sessions, tasks, daemons, memory, tools, permissions). Read both. Do not guess field names or endpoint shapes — they are all documented.

Also read the existing CLI entry point to understand how to add the new command:
```
/home/ixi/khacloud/drive/Plugins/VeilCli/cli/index.js
```

---

## Deliverables

### 1. Frontend — `ui/` folder

Create a `ui/` folder at the root of the VeilCLI repo:
```
/home/ixi/khacloud/drive/Plugins/VeilCli/ui/
```

This folder is served as-is by a static file server. No build step. No compilation. The AI agent running this opens `index.html` in a browser and it works immediately.

Tech choices are yours — vanilla JS, React via CDN, Vue via CDN, whatever produces the cleanest result. The constraint is: **no build pipeline required**. If you use a framework, load it from a CDN. Use Tailwind via CDN for styling if you want fast, clean UI without writing raw CSS.

### 2. New CLI command — `veil dashboard`

Add a `dashboard` command to the existing CLI (`cli/index.js`). When invoked, it starts a lightweight static file server that serves the `ui/` folder.

Behavior:
- Default port: **5077**
- Accepts a `--port` flag to override
- Prints the URL to the console on startup (e.g. `Dashboard available at http://localhost:5077`)
- Serves `ui/index.html` for all routes (SPA-style fallback)
- No auth on the dashboard server itself — it's local-only

---

## Connection Screen

The very first thing the user sees when opening the dashboard (no prior config, or after clearing) is a connection screen with:
- **Server URL** field — e.g. `http://localhost:5050`
- **Secret token** field — optional, shown as password input
- A **Connect** button that tests the connection by calling `GET /health` before proceeding
- If the connection fails, show a clear error with the actual response or network error

Once connected, persist the URL and secret in `localStorage` so the user doesn't re-enter them on reload. Provide a way to disconnect / switch server from anywhere in the app (a small "connected to X" indicator that's clickable).

---

## Feature Coverage

Cover all of the following. Each area should be a distinct view/section in the UI.

---

### Agents

The central entity. This view should be the default home screen after connecting.

- List all agents with their name, model, enabled modes, and description
- Select an agent to open its detail panel
- Agent detail: show full config (model, modes, tools, description), with options to:
  - **Edit** — update the agent config (PUT /agents/:name)
  - **Delete** — with a confirmation step
  - **Reload** — hot-reload from disk (POST /agents/:name/reload)
- **Create new agent** — a form for the essential fields (name, model, modes, description). Check the agent schema for what fields are valid and required. Do not create a form that produces invalid JSON.
- From agent detail, navigate directly into: Chat, Tasks, Sessions, Skills for that agent

---

### Chat

A real chat interface, not a form.

- Select an agent and start chatting
- Messages rendered in a conversation layout (user right, assistant left, or whatever feels natural)
- **SSE streaming**: connect with `sse: true` and render tokens as they arrive — do not wait for the full response before displaying
- **Tool calls**: when the SSE stream emits tool events (`tool.start`, `tool.end`), display them inline in the conversation as a collapsible block (tool name, input, output, duration)
- **Session continuity**: the chat view uses a `sessionId` and sends it with each message so the conversation continues correctly
- Show token usage per response (input tokens, output tokens, cost if available)
- Button to start a fresh session (clears the view and drops the sessionId)
- Optionally: show the current session ID and allow pasting one to resume a specific session

---

### Tasks

Async task management.

- List all tasks (paginated if many) with status, agent name, created time, and a truncated input preview
- Color-code by status: pending (grey), processing (blue/animated), finished (green), failed (red), waiting (yellow), canceled (muted)
- Task detail view:
  - Full input, full output
  - Status, iterations, token counts, cost, duration
  - **Event timeline**: render `GET /tasks/:id/events` as a chronological log — status changes, tool calls (with name + result), limit.reached events
  - If status is `waiting`: show a text input and **Respond** button (`POST /tasks/:id/respond`)
  - If status is `processing` or `pending`: show a **Cancel** button
  - **Stream view**: button to open `GET /tasks/:id/stream` (SSE) and watch a running task live
- Create new task: pick an agent, enter input, optional priority and token budget

---

### Sessions

- List sessions with agent name, status, message count, created time
- Session detail: render full message history with roles, token counts per message, and cost
- **Reset** button (clears messages, keeps session)
- **Delete** (soft and hard options)
- Pagination on messages if the history is long

---

### Daemons

- List active daemon schedulers with agent name, schedule (cron), next run time if available
- Per daemon: **Start**, **Stop**, **Trigger** (manual immediate tick) buttons
- After triggering, show the resulting task ID and link to task detail

---

### Memory

Two sections: agent memory and global memory.

- For each agent: list its memory files (`GET /agents/:name/memory`), open a file for viewing/editing, save changes (`PUT /agents/:name/memory/:file`), delete a file
- Global memory: same CRUD operations on `GET /memory` and `PUT /memory/:file`
- The editor should handle markdown — at minimum a `<textarea>` with monospace font; optionally a simple markdown preview

---

### Settings

- Show current settings at the `merged` level — what the server is actually running with
- Toggle to show `project` level only (what's in the workspace settings.json)
- Inline editing of safe fields with a **Save** button (`PUT /settings`)
- API keys must be displayed as redacted (treat any field path containing `api_key` as sensitive)

---

### Models

- List all models from `GET /models` — show name, provider, context length, pricing
- Search/filter by name or provider
- **Refresh** button (`POST /models/refresh`) to re-fetch from OpenRouter
- Click a model to see full detail

---

### Live Event Feed

A real-time view connected to the WebSocket (`ws://host:port/ws`).

- Scrolling log of all events as they arrive
- Each event shows its type, timestamp, and relevant data (task ID, agent name, status, etc.)
- Filters by event type (task events, chat events, daemon events)
- Pause/resume button
- Auto-scroll to latest (with a way to lock scroll for reading)

---

## UX Requirements

- **Navigation**: sidebar or top nav with all sections. Current agent context (if any) should be visible globally.
- **Responsiveness**: doesn't need to be mobile-friendly, but should work at common desktop widths (1280px+)
- **Error handling**: every API call that fails should show a useful error message — not just "Error" but the actual response body. The user is a developer; show them everything.
- **Loading states**: spinners or skeletons on async operations — do not leave the user staring at a blank panel
- **Empty states**: when there are no agents, no tasks, no sessions, say so clearly with a prompt to create one
- **Dark mode**: preferred, but not mandatory if it complicates the build significantly

---

## What NOT to Do

- Do not hardcode `localhost:5050` anywhere — all API calls must go through the configured server URL from the connection screen
- Do not require a build step
- Do not implement authentication within the dashboard itself — the secret is just passed as a header on every API call
- Do not create a read-only dashboard — all write operations (create, edit, delete, trigger) must be available
- Do not skip error display to "keep the UI clean"

---

## File Structure Suggestion

```
ui/
├── index.html          ← entry point, loads everything
├── app.js              ← main app logic / router
├── api.js              ← API client (all fetch calls, secret header injection, error handling)
├── views/
│   ├── connection.js
│   ├── agents.js
│   ├── chat.js
│   ├── tasks.js
│   ├── sessions.js
│   ├── daemons.js
│   ├── memory.js
│   ├── settings.js
│   ├── models.js
│   └── feed.js
└── style.css           ← global styles (if not using Tailwind CDN)
```

This is a suggestion, not a requirement. Organize it however makes sense for your implementation. If you prefer a single-file approach for simplicity, that is acceptable as long as the code stays readable.
dont forget to save secret and url:port to localStorage with a logout button to clear them
