xuns · Web service¶
Use the same agent in a browser: chat interface, event stream, collapsible tool-activity blocks, file panel and multi-session switching.
xuns . # all sessions share the current directory
xuns # one temporary working directory per session
xuns . --host 0.0.0.0 --port 18960 --base-path /xun
Parameters¶
| Parameter | Form | Default | Description |
|---|---|---|---|
workdir |
positional, optional | empty | working directory shared by all sessions; when omitted or empty, each session gets its own temporary directory (cleaned up on exit) |
--host |
string | localhost |
listen address; with 0.0.0.0 the startup message additionally prints the aka localhost form |
--port |
integer | 18960 |
port; 0 means the system assigns a random port, and the actual port is printed |
--token |
string | empty | access token; an empty value is auto-generated with secrets.token_urlsafe(24) |
--base-path |
string | empty | URL prefix for sub-path deployments; must not contain empty segments, . or .. |
--manage-sessions / --no-manage-sessions |
boolean flag | on | whether sessions may be created/deleted in the interface |
The corresponding Python API:
from xun import web_session
web_session(workdir=".", host="localhost", port=18960, token="", base_path="", manage_sessions=True)
Once started it prints a direct URL for each session (the token is already included in the query string):
Agents are available at the following URLs:
http://localhost:18960/chat/?session=/&token=...
Tokens and login¶
--token is the access credential; the server compares it with hmac.compare_digest and accepts three ways of supplying it:
Authorization: Bearer <token>- the
xun_web_tokencookie (written by the login page, or when you visit/chat/with?token=;HttpOnly+SameSite=Strict, plusSecureover HTTPS) - the
?token=<token>query string
Unauthenticated page requests are answered with a 303 redirect to the login page at --base-path/login; unauthenticated API requests return 401 {"detail":"Not authenticated"}; unauthenticated WebSockets are closed with 1008. The documentation site /docs/ needs no login, so the manual stays easy to browse.
Route overview¶
All paths below carry the --base-path prefix (empty when it is not set).
| Path | Description |
|---|---|
/ |
redirects to /chat/ |
/chat/ |
the front-end interface (static assets, built from web/) |
/docs/ |
bilingual Chinese/English documentation site (packaged in src/xun/assets/docs), public access |
/login |
login page, supports ?next= |
/api/sessions |
session list, creation and deletion (POST /api/sessions/create, /remove) |
/session/, /session/<uuid>/ |
the backend display instance of each session (WebSocket /ws, /api/events, /api/prompts, /api/files/...) |
/session/<path>/srv/<key>/ |
temporary static directory hosting, see below |
Session state is reported by the list endpoint as idle / running / waiting (waiting = a prompt is awaiting an answer). The last remaining session cannot be deleted; with --manage-sessions turned off, the create/remove endpoints return 405.
File panel¶
Sessions started by xuns enable expose_files, which provides directory browsing, PDF/full-screen preview, syntax highlighting, inline editing and directory upload (the result notification lists every file and then disappears automatically). All file operations are restricted to the agent's working directory; anything outside it returns 400, and symbolic links are skipped.
Serving static directories /srv/¶
If the working directory ends up containing a generated static site (for example this project's site/), you can mount it in the interface as GET /session/<path>/srv/<key>/:
keyis a random token, the link itself is the credential (this path needs no token)- it expires after 1 hour by default (
SERVE_TTL_SECONDS = 3600), and at most 16 may be served at a time (exceeding the limit returns 429) - the working directory root itself cannot be served
Deployment notes¶
- The interface and the backend communicate over WebSocket, so a reverse proxy must allow upgrade requests and preserve
X-Forwarded-Host/X-Forwarded-Proto. - Sub-path deployment only needs
--base-path; all assets and language-switcher links are relative paths, so any prefix works. --host 0.0.0.0exposes the service on every network interface — combine it with a firewall or reverse-proxy authentication.
Front-end development (Vite + Vue DevTools):
cd web && npm install && npm run dev # http://127.0.0.1:5173