- Rust 82.6%
- TypeScript 15.4%
- CSS 0.6%
- Shell 0.6%
- PLpgSQL 0.6%
- Other 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
Some checks failed
Backend CI / Format, lint and test (push) Failing after 2s
Backend CI / Migrations apply to an empty database (push) Failing after 1s
Security / Advisories, licences and sources (push) Failing after 2s
Security / No secrets or placeholder credentials committed (push) Failing after 2s
Security / Frontend dependency audit (push) Failing after 32s
The customer image catalogue lives only in memory (services::live_inventory) and forgets everything on a panel restart; nothing previously asked a freshly (re)connected agent to report in, so a customer's "Operating system" list stayed empty after any panel or agent restart until an operator happened to click "Refresh" or pull a new image. Confirmed live: a rebuilt agent reconnected fine, but the wizard's OS and the admin Images page both showed nothing until manually refreshed. Dispatches a NodeRefreshInventory operation right after every successful handshake, same as the existing manual admin button and the automatic post-pull refresh - all three now share one services::operations::dispatch_inventory_refresh helper instead of each building an OperationRequest by hand. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
| .github/workflows | ||
| agent | ||
| backend | ||
| crates | ||
| deploy | ||
| docs | ||
| frontend | ||
| migrations | ||
| scripts | ||
| .editorconfig | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| clippy.toml | ||
| deny.toml | ||
| full2.svg | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| rust-toolchain.toml | ||
| rustfmt.toml | ||
Bee.host Cloud Control Panel
A multi-node Incus management platform: a Rust control plane, a Rust node agent, and a React operator/customer interface.
Status: Phase 1 of 6. The foundation is complete and every gate passes. Real Incus inventory, power operations and provisioning land in Phases 2–4. See Phase status for exactly what works today.
What this is
Three components:
| Component | Binary | Runs on | Responsibility |
|---|---|---|---|
| Control plane | bee-panel |
Your infrastructure | Identity, ownership, permissions, desired state, operations, audit |
| Node agent | incus-agent |
Every Incus host | Talks to the local runtime, reports observed state, executes commands |
| Web interface | — | Browser | Operator app at /admin, customer app at / |
Browser ──HTTPS/WSS──▶ bee-panel ──WSS (agent dials out)──▶ incus-agent ──unix socket──▶ Incus
│
▼
PostgreSQL
Design commitments
These shaped most of the code, and are worth stating plainly:
- The panel never touches a node directly. No SSH, no remote Incus API, no mounted sockets. Agents dial out to the panel, so nodes need no inbound port and work behind NAT.
- The panel does not assume a command succeeded. Every long-running action
becomes a durable
operationsrow before a node is contacted, and observed state is reconciled against desired state rather than presumed to match. - There is no remote shell. The agent's command set is a closed Rust enum. Adding a variant that runs arbitrary host commands would be a deliberate, reviewable change — and should not happen.
- Customers never see infrastructure. Customer and operator DTOs are separate types, so exposing a node id to a customer requires adding a field to a customer struct. A test walks every customer payload looking for infrastructure vocabulary.
- Tenancy is a property of queries, not of handlers. Customer reads join
through
project_members. There is no "fetch globally, then filter" path to forget a check in.
Quick start
Prerequisites
- Rust 1.95 (pinned by
rust-toolchain.toml) - Node 22 and pnpm 9+
- Docker with Compose v2, or a local PostgreSQL 15+
- An Incus host — only needed from Phase 2 onward
Run everything
git clone <repository-url> bee-host
cd bee-host
pnpm install
./scripts/dev.sh
That starts PostgreSQL, the control plane and the frontend dev server. The panel applies its own migrations and seeds roles and permissions on first boot.
- Frontend — http://localhost:5173
- API — http://localhost:8080/api/v1/health
Run the pieces separately
# PostgreSQL only
docker compose -f deploy/docker-compose.dev.yml up postgres
# Control plane
cp deploy/examples/backend.env.example .env # then edit it
cargo run -p bee-panel
# Frontend
pnpm --filter @bee-host/frontend dev
# Node agent — on an actual Incus host, not in a container
cargo run -p incus-agent -- --config ./agent-dev.toml
docs/development.md covers the development administrator, the mock-agent
path, and what to do without an Incus host.
Repository layout
backend/ bee-panel: Axum control plane
src/api/ HTTP and websocket handlers — parse, authorise, delegate
src/services/ Orchestration; owns multi-step workflows
src/repositories/ Every SQL statement in the backend
src/domain/ Types and invariants, storage- and transport-independent
src/auth/ Sessions, permissions, the Actor every handler receives
agent/ incus-agent: one per Incus host
src/connection/ Handshake, connection loop, reconnect backoff
src/collectors/ Host metrics from /proc
src/state/ The command journal that makes reconnects safe
crates/
core/ Typed ids, permissions, lifecycle enums, error codes
agent-protocol/ The versioned panel ⇄ agent wire protocol
incus-client/ Typed client for the Incus Unix socket
runtime/ Runtime-neutral abstraction; Incus is the first backend
api-types/ HTTP DTOs — customer and operator types are separate
test-support/ MockRuntime and fixtures
frontend/ React + Vite + TypeScript
migrations/ SQL migrations, embedded into the binary at compile time
deploy/ Dockerfiles, compose stacks, systemd unit, nginx config
docs/ Architecture, protocol, permissions, security, operations
Development commands
# Rust
cargo test --workspace --all-features
cargo clippy --workspace --all-targets --all-features
cargo fmt --all -- --check
cargo run -p bee-panel
cargo run -p incus-agent -- --config ./agent-dev.toml --check
# Frontend
pnpm typecheck
pnpm lint
pnpm test
pnpm build
# Database
DATABASE_URL=postgres://... ./scripts/migrate.sh run
DATABASE_URL=postgres://... ./scripts/migrate.sh check # against a scratch DB
Phase status
Phase 1 is complete. The table is deliberately specific, because a page that looks finished and is not is worse than one that says so.
| Delivered | |
|---|---|
| Phase 1 ✅ | Workspace, migrations, config validation, error model, structured logging, Argon2 sessions, RBAC, agent registration and the authenticated agent websocket, login page, both application shells, both route trees |
| Phase 2 | Typed Incus socket client wired to real inventory, node list and detail, global instance list, stale-node detection, reconciliation |
| Phase 3 | Power operations, the operation state machine end to end, audit logging, realtime streaming, customer instance views |
| Phase 4 | Create-instance wizard, placement scheduler, plans, SSH keys, cloud-init, snapshots, console proxy, metrics |
| Phase 5 | Reconciliation workers, credential rotation, node drain, operation timeouts, retention, API documentation |
| Phase 6 | Responsive polish, command palette, accessibility and performance review, end-to-end suite |
Pages whose backend does not exist yet render an explicit notice naming the phase and what it is waiting on. Endpoints that are not implemented are not mounted, so nothing 404s where a control implies it should work.
Working today: sign in and out, session listing and revocation, /me and
/me/permissions, health/readiness/version, node registration, and the full
agent handshake with heartbeats.
Testing
cargo test --workspace --all-features # 568 tests
pnpm test # 8 tests
The Rust tests concentrate on the things that are expensive to get wrong: permission scope widening, the operation state machine's terminal states, instance-name validation against traversal and shell metacharacters, protocol round-trips and rejection of unknown fields, challenge-response authentication including replay and node-substitution attempts, reconnect backoff, and duplicate-command suppression across an agent restart.
Documentation
| Document | Contents |
|---|---|
| architecture.md | Components, data flow, why the split is where it is |
| agent-protocol.md | Envelope, handshake, commands, console |
| incus-integration.md | Socket client, response envelopes, the CLI fallback |
| permissions.md | Roles, permissions, scoping, tenancy |
| operations.md | The operation lifecycle and reconciliation |
| development.md | Local setup, seeded accounts, testing |
| deployment.md | Production install, TLS, agents, upgrades |
| security.md | The security model, and its known limitations |
Licence
Proprietary. © Bee.host.