Skip to content

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:

  1. Authorization: Bearer <token>
  2. the xun_web_token cookie (written by the login page, or when you visit /chat/ with ?token=; HttpOnly + SameSite=Strict, plus Secure over HTTPS)
  3. 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>/:

  • key is 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.0 exposes 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