Dano is a P0 web LLM chat app. It provides a browser UI backed by a server-side Pi runtime, using HTTP POST for commands and EventSource/SSE for streaming assistant events.
The browser never receives LLM credentials. API keys are loaded only by the
server process through environment variables, .env, or Docker-style secret
files.
apps/dano Dano server, browser UI, and Pi runtime application
deploy/nginx nginx reverse proxy config for container deployment
deploy/runtime-defaults
Source defaults copied into the runtime workspace on startup
This repo intentionally does not include the old Pi extension target or Electron target.
- Node.js
>=22.19.0 - pnpm
- Docker Compose or Podman Compose
- A server-side LLM credential for the selected model provider
Shipped Pi defaults are defined in
deploy/runtime-defaults/settings.json
and are used only to initialize a missing settings.json in the Agent Config
Directory. Existing deployments keep the persistent settings.json selected by
PI_CODING_AGENT_DIR; edit that file to change their model settings. The
headless web bridge treats /model as normal chat text.
The default assistant instruction lives in
deploy/runtime-defaults/SYSTEM.md. On
startup the container copies it to /tmp/dano/.pi/SYSTEM.md only when that
runtime file does not already exist:
- answer in a detailed and friendly tone
- proactively use tools to help users handle OA-related workflows
Edit deploy/runtime-defaults/SYSTEM.md to change the source default for new
runtime workspaces. Edit /tmp/dano/.pi/SYSTEM.md inside the persistent runtime
workspace to change an already initialized deployment.
Copy the example file for local runs:
cp .env.example .envSet only server-side credentials in .env, for example:
XIAOMI_TOKEN_PLAN_CN_API_KEY=...Supported environment names include:
AGENT_WORLD_API_KEY
OPENAI_API_KEY
ANTHROPIC_API_KEY
DEEPSEEK_API_KEY
GOOGLE_API_KEY
GOOGLE_GENERATIVE_AI_API_KEY
GROQ_API_KEY
OPENCODE_API_KEY
OPENROUTER_API_KEY
XAI_API_KEY
XIAOMI_API_KEY
XIAOMI_TOKEN_PLAN_CN_API_KEY
Docker secret-style file variables are also supported for:
OPENAI_API_KEY_FILE
ANTHROPIC_API_KEY_FILE
DEEPSEEK_API_KEY_FILE
Install dependencies:
pnpm installRun checks:
pnpm run check
pnpm run test
pnpm run buildRun the Dano app after building:
pnpm run build
pnpm run start -- --host 127.0.0.1 --port 8080Open:
http://127.0.0.1:8080
For Svelte-only UI development:
pnpm run dev:webDeployment details live in deploy/README.md.
Docker:
pnpm run deploy:upPodman:
DANO_COMPOSE=podman pnpm run deploy:upThe nginx browser port defaults to 80. .env.example uses 18082 for local
smoke runs. Override it with DANO_NGINX_PORT:
DANO_NGINX_PORT=18082 pnpm run deploy:upOpen:
http://127.0.0.1:18082
Stop:
pnpm run deploy:stopRemove the stopped containers and Compose network with pnpm run deploy:down.
Production servers should prefer pulling a prebuilt image instead of building with pnpm on the target host:
DANO_IMAGE=ghcr.io/your-org/dano:latest pnpm run deploy:upThe published app is HTTP-only unless you put TLS in front of it. Use
http://host/ directly, or terminate HTTPS at a reverse proxy/load balancer.
Health:
curl -s http://127.0.0.1:18082/api/healthCreate client:
curl -s -X POST http://127.0.0.1:18082/api/clients \
-H 'Content-Type: application/json' \
-d '{}'Open events:
curl -N http://127.0.0.1:18082/api/clients/<clientId>/eventsSend command:
curl -s -X POST http://127.0.0.1:18082/api/clients/<clientId>/messages \
-H 'Content-Type: application/json' \
-d '{"type":"command","payload":{"id":"smoke-1","type":"get_state"}}'SSE message types:
response
event
: heartbeat
- Enter sends the message.
- Shift+Enter inserts a newline.
- The composer starts as one line and grows automatically for multiline input.
- Empty messages are blocked.
- Assistant and user messages render Markdown, including tables, highlighted fenced code blocks, and Mermaid diagrams.
- Runtime tool calls and tool results render as inline expandable blocks.
- LLM failures show a visible error state and retry control.
- Requests for business actions remain chat-only; no external workflow is executed by P0.
Known-good verification used for the P0 implementation:
pnpm run check
pnpm run test
pnpm run build
DANO_NGINX_PORT=18082 pnpm run deploy:up
curl -s http://127.0.0.1:18082/api/health
DANO_SMOKE_BASE_URL=http://127.0.0.1:18082 pnpm run smoke:deployExpected health response:
{"status":"ok"}The deployment path supports Docker Compose and Podman Compose. For production,
prefer a prebuilt image through DANO_IMAGE so the target server does not build
with pnpm.