Explore Nession Pages — an independently designed, read-only project site introducing Nession and showing public AI workflow Agent activity, active engineering work, repository metrics, and evidence-source metadata. Pages (pages/) is separate from the authenticated product Web workspace (web/); it does not reuse its design system or runtime components.
Generated every 4 hours from main · rolling 7d / 30d · raw metrics
Agent workflow telemetry · rolling 7d / 30d · aggregate JSON · immutable raw runs under raw/workflows/ on the metrics branch
An intelligent workspace for continuous work across devices, environments, and compute nodes.
Nession connects local machines, remote servers, cloud environments, terminals, coding agents, and other execution contexts into one continuous working experience. The infrastructure may be distributed and complex; the product should remain coherent, quiet, and extensible.
Product direction and design decisions are governed by two repository-level documents:
VISION.md— what problem Nession exists to solve and where the product is going.PRINCIPLE.md— the durable design principles used to decide how Nession should grow.
In short: Nession should absorb infrastructure complexity instead of exposing it, organize the experience around the work rather than a feature catalog, let relevant capabilities emerge from context, and reveal deeper complexity progressively. The two documents above are the canonical source when this summary and lower-level design documents diverge.
Today, Nession provides distributed tmux session management across many machines. A central server tracks every agent (one per node), and clients attach to live sessions from the Web UI or CLI — over a relay through the server, or peer-to-peer directly to an agent for lower latency.
Browser / CLI
│ ws:// (or wss://)
▼
nession-server ── SQLite ── registry (agents, sessions)
│ ws:// ▲
▼ │ heartbeat + session sync
nession-agent ── tmux ─────┘
│
▼
tmux sessions (per-node)
Connection modes
- Relay — Browser/CLI → Server → Agent. Works anywhere the server is reachable.
- P2P — Browser/CLI → Agent directly, using the agent address returned by the attach response. Lower latency.
- Central registry — agents register on connect and heartbeat; the server persists agents and sessions in SQLite.
- Web dashboard — React + xterm.js UI to browse agents, create/kill sessions, and open a live terminal (light, on the same ground as the chrome).
- Interactive CLI — attach to a session in a raw terminal, list agents/sessions, create and kill sessions.
- Two transports — relay through the server or P2P directly to the agent.
- Container-ready — multi-arch (amd64/arm64) Docker images and Kubernetes manifests (kustomize base + staging/production overlays).
- Prebuilt binaries — released for Linux and macOS on every version bump.
Downloads the release binaries matching your OS and architecture:
curl -fsSL https://github.com/BestNathan/nession/releases/latest/download/install.sh | shOptions:
# custom install directory and subset of binaries (add --version for a pinned release)
./scripts/install.sh --dir ~/.local/bin --bins nession
# -v, --version <ver> version to install (default: latest)
# -d, --dir <path> install dir (default: /usr/local/bin → ~/.local/bin fallback)
# -b, --bins <list> comma-separated: nession,nession-agent,nession-serverEnvironment overrides: NESSION_VERSION, NESSION_INSTALL_DIR, NESSION_BINS, and GITHUB_TOKEN (to avoid API rate limits).
Requires Rust 1.96+ (pinned in rust-toolchain.toml) and Node.js 20+ for the web UI.
git clone https://github.com/BestNathan/nession.git
cd nession
cargo build --release # binaries in target/release/Produces three binaries: nession (CLI), nession-agent, nession-server.
nession-server # reads ./config.toml if present, else uses defaultsWithout a config it listens on 127.0.0.1:8080 with no auth and stores its DB under ~/.nession/. The Vite dev server proxies /ws to 19090, not 8080 — so a config-less server is reachable by the CLI but not by the UI. Either pass a config that sets listen_address = "127.0.0.1:19090", or expect to log in and see "disconnected" with no other clue.
To customize, create a config.toml:
listen_address = "0.0.0.0:8080"
tls_cert_path = "" # set both to enable wss://
tls_key_path = ""
auth_token = "your-secret-token"
heartbeat_interval_secs = 10
heartbeat_timeout_secs = 30
# db_path defaults to ~/.nession/server/server.db (or under NESSION_HOME)Copy and edit agent-config.toml:
agent_id = "agent-local"
server_url = "ws://127.0.0.1:8080/ws"
auth_token = "your-secret-token"
listen_address = "0.0.0.0:8080" # internal WS server for P2P
heartbeat_interval_secs = 10
session_poll_interval_secs = 5
# advertise_address / connect_url — optional, for how clients reach this agent (P2P)nession agent start --config agent-config.toml --foregroundThe nession CLI can also manage the agent/server lifecycle as background processes:
nession agent start # background, writes a PID file under ~/.nession/
nession agent status
nession agent stop
nession server start|status|stopCLI (targets the central server; override with --server-url / --auth-token, or set NESSION_SERVER_URL / NESSION_AUTH_TOKEN):
nession agents list
nession sessions list [--agent-id <id>]
nession sessions create --agent-id <id> --name dev
nession sessions attach --session-id <agent_id>:<session_name> [--mode p2p|relay]
nession sessions kill --session-id <agent_id>:<session_name> [--force]--auth-token is convenient for a one-off command, but a value passed as a
flag is visible in shell history and in process listings while the command
runs. For repeatable operation, put the token in the config file — the
auth_token key, which nession config agent set auth_token <token> writes
with private permissions — or in NESSION_AUTH_TOKEN. A background
nession agent start never passes its resolved token to the child process as
an argument; the credential goes over a private pipe instead.
Remote commands resolve one target, in this order: the explicit global flag,
NESSION_SERVER_URL / NESSION_AUTH_TOKEN, the legacy NENSION_SERVER_URL /
NENSION_AUTH_TOKEN aliases (kept so an existing environment keeps working;
the canonical name wins if both are set), then ws://127.0.0.1:8080 with an
empty token. Agent and Server daemon configs do not override this CLI target.
Web UI — see Web dashboard below.
cd web
npm ci
npm run dev # Vite dev server on http://localhost:13000, proxies /ws → :19090Open http://localhost:13000, connect to the server, then browse agents and open terminals. For production, npm run build emits static assets to web/dist/ (served by nginx in the Docker/K8s images).
Terminal font metrics come from the Web/App Experience design tokens
(design/generated/terminal.ts), not fixed device scaling percentages.
The terminal engine includes a FontSizeManager with pixel-size bounds,
but the current Session-first Terminal surface does not expose the
older +/-/reset toolbar controls. Do not assume an interactive zoom UI exists
solely because the lower-level engine supports font size changes.
A Session's history is xterm's own scrollback — the wheel stays in the browser
and never enters tmux copy mode — and attaching (or reloading) fills it from
the Session, so context is available when the terminal mounts. That holds on
the default attach transport; attach_mode = "plain" is a fallback, and
docs/design/terminal/scrollback-bootstrap.md
states exactly what it does and does not give you.
nession/
├── crates/ # Rust workspace (10 crates; see Cargo.toml)
│ ├── nession-common/ # shared configuration, paths and utilities
│ ├── nession-protocol/ # versioned wire contracts
│ ├── nession-protocol-codegen/ # TypeScript / JSON Schema generation
│ ├── nession-runtime/ # reusable runtime primitives
│ ├── nession-client/ # reusable client library
│ ├── nession-server/ # broker, registry, SQLite, WebSocket + TLS
│ ├── nession-agent/ # per-node tmux, server and P2P lifecycle
│ ├── nession-cli/ # interactive CLI and process lifecycle
│ ├── nession-git/ # Git capability / protocol
│ └── nession-claude-code/ # Claude Code capability / protocol
├── web/ # React + Vite + TypeScript + shadcn/ui + xterm.js
├── deploy/ # docker-compose + entrypoints + nginx template
├── design/ # design tokens + executable UI contracts (`design/generated/` is codegen output)
├── e2e/ # shared Runner, Cases, Scenarios, Playwright regressions
├── gates/ # invariant checks and suite catalog
├── scripts/ # tooling, acceptance, metrics, gitops writer, install.sh
├── Dockerfile.* # server/agent/ui build variants
└── Cargo.toml # workspace root (version lives here, and in web/package.json)
Deployment desired state — the kustomize base, per-environment overlays and the
ArgoCD app-of-apps — lives on the gitops orphan branch, not on main
(issue #592). See "Deploying to Kubernetes" in the root CLAUDE.md.
# Rust
cargo build
cargo test
cargo fmt --all -- --check
cargo clippy -- -D warnings # must pass with 0 warnings; #[allow(clippy::*)] is forbidden
# Web (in web/)
npm run dev # dev server :13000
npm run build # production build → dist/
npm run lint # ESLint (--max-warnings 0; eslint-disable is forbidden)
npm test # Vitest
npx tsc --noEmit # type checkSee CLAUDE.md for the full contributor workflow, coding conventions, and branch/PR rules.
Never develop on
main. Create a feature branch:git checkout -b feat/<slug>.
# full builds (Rust + UI)
docker build -f Dockerfile.server -t nession-server .
docker build -f Dockerfile.agent -t nession-agent .Published multi-arch images (on version bumps via CI):
ghcr.io/bestnathan/nession:server-<version>ghcr.io/bestnathan/nession:agent-<version>ghcr.io/bestnathan/nession:ui-<web-version>
deploy/docker-compose.yml wires server + agent + UI together for local runs.
The Kubernetes Kustomize base, environment overlays and ArgoCD desired state
are maintained on the gitops branch,
not at k8s/ in main or staging. Check out that branch and follow
its current overlay paths before applying manifests.
The deployment nginx listener serves the UI and /health endpoint
(container port 10080), proxying /ws to the configured Rust WebSocket
listener. Rust listener ports and external service ports are configuration,
not fixed Kubernetes constants. CI publishes multi-arch images and promotes
versioned image tags through the gitops workflow on version changes
(see .github/workflows/release.yml).
Pushing a version bump (Cargo.toml / web/package.json) to main triggers CI to:
- Lint + test (Rust and web).
- Build & push multi-arch Docker images.
- Build native binaries for Linux (amd64/arm64) and macOS (Intel/Apple Silicon).
- Publish a GitHub Release
v<version>with tarballs namednession-<version>-<os>-<arch>.tar.gz, each containingnession,nession-agent, andnession-server.
The installer consumes these release assets.