Skip to main content

Self-hosted web UI for spawning and managing Claude Code remote-control bridges on a remote host.

Project description

Clauster

A self-hosted web dashboard for spawning and managing Claude Code remote-control
bridges into any project directory on a remote host — then attach to them from
claude.ai/code or the Claude mobile app. No SSH session required.

CI Lint codecov Reviewed by Greptile OpenSSF Scorecard OpenSSF Best Practices

PyPI Python versions License: Apache-2.0 GHCR Ruff pre-commit

Spawn a Claude session from the Clauster dashboard — open a project's launch menu, trust the directory, and the session starts, then shows Running under Active sessions

Anthropic's first-party tooling assumes terminal access on the host to spawn a bridge in a given project directory. Clauster fills that gap: a browser-based dispatcher of claude remote-control instances on a remote machine (NAS, homelab box). You pick a project, start a bridge, and attach to it from claude.ai/code or the mobile app.

Status: pre-1.0, in active development. Loopback-only by default; password and reverse-proxy auth are available for networked deployments (see Auth & networking). No telemetry, ever — see Privacy & data at rest for what Clauster keeps locally.

Install now: curl -fsSL https://raw.githubusercontent.com/schubydoo/clauster/main/install.sh | bash

The full install recipes and verification steps are in the Installation guide.

Dashboard, light theme
Dark / light — theme toggle persists across reloads
Create or clone a project
Create or clone — SSRF-guarded, cloned code runs only on Start
Password login
Password login — for non-loopback / networked deploys
Every action is reactive — cards insert, badges flip, and clone progress
streams without a full-page reload. Self-hosted assets; no CDN, no trackers.

Features

Everything below is implemented and shipping. Items marked (opt-in) are gated behind a config flag and off by default — the flag is named inline so you can find it in clauster.yml.example.

Show all features

Projects & bridges

  • Project discovery — one card per directory under projects_root, with git / CLAUDE.md / trust badges.
  • Bridge lifecycle — start / stop / resume bridges; live status (Starting / Running / Stopped / Crashed / Error). A bridge that launches but never registers an environment is reported honestly as Error after a grace window, not a phantom Running.
  • Spawn controls — pick the spawn mode (same-dir / worktree / session), permission mode, and resume mode (Server Mode / Interactive Session true-resume, POSIX) per launch; claude.launch_mode is the pre-selected default. bypassPermissions is double-gated: a per-project config ceiling (projects.<name>.allow_bypass_permissions) and a type-the-project-name confirm in the UI.
  • Open in Claude — a deep link to the primary session plus a scannable QR code that opens it in the Claude app (claude.ai/code or mobile), attached to the running bridge. Bridges are cloud-visible; the experimental hosted live-view channel is local-only — it streams in the dashboard but is never attachable from the Claude app.
  • External session surfacing — sessions you started from a terminal or Desktop (not via Clauster) are discovered and shown with a distinct indicator.
  • Create / clone projects — make a new project or clone a git URL, with SSRF guards, transport lockdown, a size cap, and a "code runs on start" warning for cloned repos. Clones stream live progress over a WebSocket and never auto-spawn (they land discovered-but-stopped).

Visibility & editing

  • Live log tail — the bridge debug log streamed over a WebSocket, ANSI-stripped and ID-redacted (env_/session_/cse_ IDs, bare UUIDs, and secret-shaped tokens — API keys, bearer headers). Redaction is hybrid by default (verbatim on disk, redacted over the wire); logs.redact_session_url redacts on disk too.
  • CLAUDE.md editor — view/edit a project's CLAUDE.md from the dashboard (size-capped, lost-update-guarded, trust-gated, audit-logged).
  • Config editor — edit an allowlist of operational clauster.yml settings from the dashboard (GET/PUT /api/config). Only a Tier-A allowlist is exposed — auth, bind, secret, and structural fields are never editable or even read back to the browser. Writes are lost-update-guarded (a content hash from the read must still match on write), backed up, and applied atomically with your comments preserved; the running process keeps its startup config until restarted. See docs/configuration.md.
  • Per-project cost badge — approximate USD + token totals rolled up from a project's session transcripts. Token counts are exact (read from the transcript usage); the dollar figure is a ballpark — a hand-maintained USD price table (usage.py, as of 2026-05) that drifts as pricing changes, with unpriced models counting as 0. usage.mode selects what the badge shows — cost, tokens, or off (hide it for privacy / screen-share); usage.show_cost: false is a deprecated alias for off.

Safety

  • Workspace trust — starting a bridge in an untrusted directory prompts a just-in-time "trust the files in this folder?" confirm (an explicit checkbox) that writes the Claude workspace-trust flag and then spawns; trusted directories show a green shield by the project name and start with no prompt.
  • Auto-enable remote control — before the first spawn, Clauster marks remote control as acknowledged in the runtime user's ~/.claude.json so a detached-stdin bridge isn't stuck on the one-time interactive "Enable Remote Control?" prompt. On by default (claude.auto_enable_remote_control); set false to manage it yourself.

Opt-in extras

Show all opt-in extras
  • Conversation recap on restart (opt-in)claude remote-control restarts into a fresh, empty context, so a restarted bridge "forgets" the prior conversation. With claude.resume_recap enabled, Clauster installs a SessionStart hook in the runtime user's Claude settings that recaps the most recent prior transcript for that directory back into the new session.
  • Native true-resume / "Interactive Session" mode (opt-in, POSIX)claude.launch_mode: pty runs the claude --remote-control flag form under a PTY keeper sidecar, which genuinely restores prior conversation context on Resume (--continue) rather than recapping it. The keeper outlives a Clauster restart and is stopped by signal. Single-session (vs. the default multi-session server). The dashboard surfaces the resume mode per bridge and rediscovers a running pty bridge after a Clauster restart.
  • Ghost-environment reaper — find and archive/delete the server-side bridge environments that outlive their bridge and clutter the claude.ai/code "New session" selector. The CLI (clauster reap-environments) is always available; the dashboard UI is opt-in (reaper.ui_enabled) because it exposes a destructive first-party API in the browser. Archive is reversible; force-delete requires typing DELETE.
  • Background agents (experimental) — a dashboard panel that lists, dispatches, stops, and resumes Claude Code background sessions (claude --bg), backed by GET/POST/DELETE /api/agents plus POST /api/agents/{job_id}/resume. It rides Claude Code's agent-view research preview, so it's experimental and may change with the upstream CLI.
  • Outbound notifications & webhooks — get told when a bridge changes state. notifications push a human message (Slack/Discord/Telegram/email via Apprise, the notify extra) on a crash; webhooks deliver a JSON POST to your own endpoint on every spawn / ready / stop / crash transition (no extra dependency, http(s) only), plus three opt-in events — bg-settled, permission-needed, clone-done (default off; enable per-event under webhooks.events). Both are off by default, and a failing endpoint is always logged-and-swallowed so it never affects a bridge's lifecycle. See Operations → Crash alerts and Lifecycle webhooks.
  • Prometheus /metrics — opt into a read-only text-format scrape endpoint (observability.prometheus_enabled) exposing build info, bridge counts by status, a crash counter, and per-bridge CPU/RSS. It stays behind the auth guard unless you set observability.metrics_token_hash for token-based scraping. See Operations → Metrics.
  • Hosted live-view channel (opt-in, experimental) — an alternate substrate to the remote-control bridge. With claustrum.enabled: true, Clauster connect-or-spawns a single claustrum daemon per deployment and runs claude headless over its stream-json channel, streaming the session live in the browser (with permission prompts surfaced in the UI) instead of being driven from Claude Desktop / claude.ai. Off by default and fail-closed — an unreachable daemon surfaces in /healthz and never affects the bridge lifecycle. Requires the separate claustrum daemon binary, which is not yet publicly distributed — there is currently no public install or build recipe, so leave claustrum.enabled: false unless you already have the binary on your PATH.

Install

No Python needed — the install script grabs the signed standalone binary for your OS, verifies its checksum, and installs it to ~/.local/bin (Linux & macOS), printing a PATH hint if that directory isn't already on your PATH:

curl -fsSL https://raw.githubusercontent.com/schubydoo/clauster/main/install.sh | bash

On Windows, the PowerShell equivalent installs clauster.exe the same way:

irm https://raw.githubusercontent.com/schubydoo/clauster/main/install.ps1 | iex

Or pick another path — uv tool install clauster (recommended for a Python host), pip/pipx, Scoop on Windows (scoop bucket add clauster https://github.com/schubydoo/clauster && scoop install clauster), or Docker. Full recipes — including supply-chain verification — are in the Installation guide. To hack on Clauster itself, use the dev quick-start below.

Uninstall

  • Install script / standalone binary: remove ~/.local/bin/clauster on Linux or macOS; on Windows, delete %LOCALAPPDATA%\Programs\clauster\clauster.exe unless you set a custom install directory.
  • Python tools: run uv tool uninstall clauster, pipx uninstall clauster, or pip uninstall clauster, matching how you installed it.
  • Scoop: run scoop uninstall clauster.
  • Docker: stop and remove the container with docker rm -f clauster, then remove the image with docker rmi ghcr.io/schubydoo/clauster:latest (substitute the pinned tag you pulled, e.g. :0.5.0, if you used a specific release) if you no longer need it. Docker Compose users: run docker compose down from the directory containing compose.yaml (add -v to also delete named volumes).
  • Full purge: stop Clauster first, then remove your state_dir if you want local state/config gone too. See Privacy & data at rest and the Installation guide.

Quick start (dev)

Just running Clauster, not hacking on it? Follow the canonical Quickstart guide — it takes you from nothing to your first attachable bridge in a few minutes. The steps below are the from-source path for working on Clauster itself.

uv sync --extra dev
cp clauster.yml.example clauster.yml    # edit projects_root
uv run clauster

Then open http://127.0.0.1:7621. claude must be on your PATH (Clauster spawns it; it isn't vendored).

First bridge in 60 seconds

With the server running (above) and an authenticated claude on your PATH, spawning your first bridge is a handful of clicks — no terminal needed once it's started. Clauster spawns claude — it doesn't vendor it — and a spawned bridge inherits the host user's claude authentication, so claude must be logged in (interactive claude login or ANTHROPIC_API_KEY in the environment — either satisfies the check) before any bridge can connect. clauster doctor (step 2) confirms it; see the Quickstart prerequisites for the full list.

  1. Point Clauster at your code. Set projects_root in clauster.yml to a directory whose subfolders are projects (e.g. ~/code); each child directory becomes a card.
  2. Sanity-check the host (optional). clauster doctor confirms claude is found, new enough, and logged in (the bridge inherits this login), and that projects_root / the state dir are usable — fix any ✗ before spawning.
  3. Open the dashboard at http://127.0.0.1:7621. You'll see one card per project.
  4. Launch a bridge. On a project's card, click Run Claude here ▾, choose In claude.ai / Desktop, pick a permission mode, then Run. Clauster launches claude remote-control in that directory and the card flips to Running with a live status badge. (The spawn-mode and permission defaults are safe out of the box.)
  5. Attach from anywhere. Use the card's Open in Claude link — or scan its QR code — to pick the bridge up in claude.ai/code or the Claude mobile app. No SSH session.
  6. Stop or resume. Stop signals the bridge; Resume relaunches it (with claude.resume_recap or claude.launch_mode: pty it can carry the prior conversation forward — see Opt-in extras). For a deliberate fresh start, Forget the stopped session and launch again with Run Claude here.

Exposing this beyond loopback (e.g. on your LAN)? Read Auth & networking first — a non-loopback bind requires authentication.

Docker

Multi-arch images (linux/amd64, linux/arm64) are published to GHCR on each release. The image binds 0.0.0.0, so it requires enforced auth to start. First generate a password hash — this runs clauster inside the image, so you don't need it on the host:

docker run --rm -it ghcr.io/schubydoo/clauster:latest clauster hash-password

Copy the printed $argon2id$… hash, then start the server with auth enabled:

docker run -d --name clauster \
  -p 7621:7621 \
  -e PUID=1000 -e PGID=1000 \
  -e CLAUSTER_AUTH_ENABLED=true \
  -e CLAUSTER_AUTH_PASSWORD_REQUIRED=true \
  -e 'CLAUSTER_AUTH_PASSWORD_HASH=$argon2id$v=19$...' \
  -v /path/to/config:/config \
  -v /path/to/projects:/projects \
  ghcr.io/schubydoo/clauster:latest
  • The image binds 0.0.0.0, so it won't start without enforced auth — set CLAUSTER_AUTH_ENABLED=true and CLAUSTER_AUTH_PASSWORD_REQUIRED=true and a CLAUSTER_AUTH_PASSWORD_HASH (or configure reverse-proxy trust in /config/clauster.yml), or the container exits on start. Single-quote the hash env value — the argon2 hash contains $ that your shell would otherwise expand.
  • /config holds clauster.yml + state; /projects is your projects_root. PUID/PGID remap the runtime user to own bind-mounts.
  • claude is not baked in — tell Clauster where it is one of two ways: mount the binary somewhere on the container PATH (the default claude.binary: claude is resolved via PATH), or set CLAUSTER_CLAUDE_BINARY=/abs/path/to/claude (a.k.a. claude.binary) to an absolute path you've mounted anywhere. Either way, also mount the runtime user's ~/.claude credentials — or build a derived image that installs claude.
  • Logs are human text by default; set CLAUSTER_LOG_FORMAT=json for structured JSON (both redact session URLs / bearer ids). Health is at /healthz. Images are cosign-signed with build provenance + SBOM attestations.

Docker Compose

A ready-to-edit compose.yaml is included:

# 1. generate a password hash (runs inside the image)
docker compose run --rm clauster clauster hash-password
# 2. export it single-quoted, then edit the projects/claude volumes in compose.yaml
export CLAUSTER_AUTH_PASSWORD_HASH='$argon2id$v=19$...'
# 3. start (the image's HEALTHCHECK is inherited)
docker compose up -d

Auth & networking

Loopback (127.0.0.1) needs no auth. Binding to a non-loopback address is refused unless authentication is actually enforced — set auth.enabled: true (the master switch) together with either password login (auth.password_required + a hash from clauster hash-password) or reverse-proxy trust (peer-IP allowlist + HMAC header) — or, to opt out on a trusted LAN, auth.allow_unauthenticated_network. Sessions are signed cookies with server-side revocation ("log out everywhere"); WebSocket connections are authenticated before accept and origin-checked.

Configuration

All settings live in clauster.yml — see clauster.yml.example for the full, commented schema. Any scalar key is overridable by an environment variable of the form CLAUSTER_<UPPER_SNAKE_PATH>. The schema is additive-only — old configs always validate against newer versions.

Common flag Default What it does
host / port 127.0.0.1 / 7621 bind address (non-loopback needs auth)
projects_root directory whose children become project cards
auth.enabled false master auth switch — must be on for password / proxy auth to apply
auth.password_required false require login (clauster hash-password for the hash)
claude.resume_recap false recap the prior transcript into a restarted bridge
claude.launch_mode standard pty = native true-resume on Resume (POSIX); default for new bridges only — a bridge keeps the mode it launched with
reaper.ui_enabled false expose the ghost-environment reaper in the dashboard
claustrum.enabled false enable the hosted live-view channel (connect-or-spawn the claustrum daemon)
usage.mode cost per-project badge contents: cost (≈USD + tokens) · tokens (count only) · off (hide + skip the usage fetch). usage.show_cost: false is a deprecated alias for off
logs.redact_session_url false redact the session URL on disk too, not just over WS

CLI

clauster run                  # start the server (default)
clauster hash-password        # generate an argon2id hash for auth.password_hash
clauster hash-token           # mint an API token + hash for auth.api_token_hash
clauster hash-metrics-token   # mint a /metrics scrape token + hash for observability.metrics_token_hash
clauster doctor               # diagnose config / environment
clauster backup | restore | migrate
clauster install-service {systemd|launchd|windows}
clauster reap-environments    # reap ghost bridge environments (dry-run by default)
clauster keepers              # list or stop orphaned pty keepers
clauster usage <transcript>   # token + approximate cost for a session transcript
clauster config reconcile     # remove deprecated config keys, writing their replacements

Roadmap

Planned work, roughly in priority order — the public-facing companion to the in-repo scratch/TODO.md.

  • Public API — promote the existing /api/* routes to a documented, versioned OpenAPI contract so third parties can build their own dashboards (Bearer API tokens, distinct from the session cookie, already ship — see clauster hash-token).
  • Session naming — predictable/branded session display names instead of the random adjective-noun defaults; list active/resumable sessions in the UI.
  • v0.3 — multi-user — per-user accounts (OIDC via Authentik / Pocket-ID / Keycloak / Zitadel) and GDPR controller tooling (clauster user export / delete), on top of the SQLAlchemy + Alembic persistence layer that already ships.

Not planned: the UI is English-only and not localized — there is no i18n string extraction on the roadmap (re-scope only if a real translation contributor appears).

Shipped: the in-repo docs/ pages (setup, networking, config reference, security model) are published as a live docs site at schubydoo.github.io/clauster.

Stack

Python 3.11+ · FastAPI · Alpine.js + Jinja2 + Tabler · uv · pydantic. Developed and CI-gated on Linux; macOS / Windows are in the test matrix. Apache-2.0 licensed.

Support

Questions, bugs, and feature requests all go through GitHub Issues — Discussions are intentionally not enabled. See SUPPORT.md for how to get help, and SECURITY.md to report a vulnerability privately.

License

Apache License 2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

clauster-0.12.9.tar.gz (2.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

clauster-0.12.9-py3-none-any.whl (676.2 kB view details)

Uploaded Python 3

File details

Details for the file clauster-0.12.9.tar.gz.

File metadata

  • Download URL: clauster-0.12.9.tar.gz
  • Upload date:
  • Size: 2.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for clauster-0.12.9.tar.gz
Algorithm Hash digest
SHA256 cc351e49ab997c101f451275a524775d0b6d464f20b97a8788b5ad134c5c40ea
MD5 feff54b9ab310c5515317ad5dd0dbc36
BLAKE2b-256 c7c4579136fbee3838dccd9e657239d4609b5786b67c7c7bf70b48bb9ff72d62

See more details on using hashes here.

Provenance

The following attestation bundles were made for clauster-0.12.9.tar.gz:

Publisher: release.yml on schubydoo/clauster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file clauster-0.12.9-py3-none-any.whl.

File metadata

  • Download URL: clauster-0.12.9-py3-none-any.whl
  • Upload date:
  • Size: 676.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for clauster-0.12.9-py3-none-any.whl
Algorithm Hash digest
SHA256 79b2be357c5b8a22e4f0b13fa857fb3ccb1eac1f0b779bdcdb1d61c2cd424015
MD5 8f28a82edcc6f81f3b83732ef29aad6b
BLAKE2b-256 5697fb2eaf737dd5f0e7836ba82a994d94dcff46487adaed374541696e2e40e8

See more details on using hashes here.

Provenance

The following attestation bundles were made for clauster-0.12.9-py3-none-any.whl:

Publisher: release.yml on schubydoo/clauster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page