Refresh daemon docs and mark web UI experimental

internal/daemon/doc.go and ARCHITECTURE.md were written before the
subpackage extractions and still referenced old structure (in-progress
phrasing, missing opstate/dmsnap/fcproc/imagemgr/session/workspace,
mentions of opRegistry by its old name). Both now describe the current
shape: composition root + six leaf subpackages, lock ordering rooted
at vmLocks[id], and the one intra-package dependency (workspace →
session for ShellQuote + FormatStepError).

README.md and AGENTS.md mark the local web UI as experimental. It is
still enabled by default at 127.0.0.1:7777, but the docs now state
plainly that its surface is not stable or hardened and not intended for
anything beyond single-user localhost use. AGENTS.md also points at
ARCHITECTURE.md for the subpackage layout.

No code changes; tests still green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thales Maciel 2026-04-15 16:44:11 -03:00
parent 1d51370d26
commit ca4865447c
No known key found for this signature in database
GPG key ID: 33112E6833C34679
4 changed files with 99 additions and 43 deletions

View file

@ -5,7 +5,8 @@ Always run `make build` before commit.
## Project Structure ## Project Structure
- `cmd/banger` and `cmd/bangerd` are the main user entrypoints. - `cmd/banger` and `cmd/bangerd` are the main user entrypoints.
- `internal/` contains the daemon, CLI, RPC, storage, Firecracker integration, guest helpers, and web UI. - `internal/` contains the daemon, CLI, RPC, storage, Firecracker integration, guest helpers, and the experimental web UI.
- `internal/daemon/` is the composition root; pure helpers live in its subpackages (`opstate`, `dmsnap`, `fcproc`, `imagemgr`, `session`, `workspace`). See `internal/daemon/ARCHITECTURE.md`.
- `scripts/` contains explicit manual helper workflows for rootfs and kernel preparation. - `scripts/` contains explicit manual helper workflows for rootfs and kernel preparation.
- `build/bin/` is the canonical source-checkout build output. - `build/bin/` is the canonical source-checkout build output.
- `build/manual/` is the canonical source-checkout location for manual rootfs/kernel artifacts. - `build/manual/` is the canonical source-checkout location for manual rootfs/kernel artifacts.

View file

@ -1,6 +1,6 @@
# banger # banger
`banger` manages Firecracker development VMs with a local daemon, managed image artifacts, and a localhost web UI. `banger` manages Firecracker development VMs with a local daemon, managed image artifacts, and an experimental localhost web UI.
## Requirements ## Requirements
@ -152,12 +152,17 @@ If you want reusable orchestration primitives instead of the `vm run` convenienc
`vm session attach` is currently exclusive and same-host only. The daemon exposes a local Unix socket bridge using `stdio_mux_v1`, so only one active attach is allowed at a time. Pipe-mode sessions keep enough guest-side state for the daemon to rebuild that bridge after a daemon restart. `vm session attach` is currently exclusive and same-host only. The daemon exposes a local Unix socket bridge using `stdio_mux_v1`, so only one active attach is allowed at a time. Pipe-mode sessions keep enough guest-side state for the daemon to rebuild that bridge after a daemon restart.
## Web UI ## Web UI (experimental)
`bangerd` serves a local web UI by default at: `bangerd` serves an experimental local web UI by default at:
- `http://127.0.0.1:7777` - `http://127.0.0.1:7777`
The UI is convenient for local observability but is **not a stable or
supported interface**. Its endpoints, layout, and behaviour may change
without notice, and it has not been hardened for anything beyond single-user
localhost use. Do not expose the listen address to a shared network.
See the effective URL with: See the effective URL with:
```bash ```bash

View file

@ -1,13 +1,12 @@
# `internal/daemon` architecture # `internal/daemon` architecture
This document captures the current (pre-refactor) layout of the daemon This document describes the current daemon package layout: the `Daemon`
package and the lock ordering its callers must respect. It is the baseline composition root, the subpackages that own stateless helpers and shared
against which the phased split described in primitives, and the lock ordering every caller must respect.
`~/.claude/plans/fluffy-seeking-teapot.md` is executed.
## Composition ## Composition
`Daemon` is the composition root. Subsystem state and locks have moved onto `Daemon` is the composition root. Subsystem state and locks live on their
owning types: owning types:
- Layout, config, store, runner, logger, pid — infrastructure handles. - Layout, config, store, runner, logger, pid — infrastructure handles.
@ -16,18 +15,37 @@ owning types:
+ guest IP allocation window). + guest IP allocation window).
- `imageOpsMu sync.Mutex` — serialises image-registry mutations - `imageOpsMu sync.Mutex` — serialises image-registry mutations
(`BuildImage`, `RegisterImage`, `PromoteImage`, `DeleteImage`). (`BuildImage`, `RegisterImage`, `PromoteImage`, `DeleteImage`).
- `createOps opRegistry[*vmCreateOperationState]` — in-flight VM create - `createOps opstate.Registry[*vmCreateOperationState]` — in-flight VM
operations, owns its own lock. create operations; owns its own lock.
- `imageBuildOps opRegistry[*imageBuildOperationState]` — in-flight image - `imageBuildOps opstate.Registry[*imageBuildOperationState]` — in-flight
build operations, owns its own lock. image build operations; owns its own lock.
- `tapPool tapPool` — TAP interface pool; owns its own lock. - `tapPool tapPool` — TAP interface pool; owns its own lock.
- `sessions sessionRegistry` — active guest session controllers; owns its - `sessions sessionRegistry` — active guest session controllers; owns
own lock. its own lock.
- `listener`, `webListener`, `webServer`, `webURL`, `vmDNS` — networking. - `listener`, `webListener`, `webServer`, `webURL`, `vmDNS` — networking.
- `vmCaps` — registered VM capability hooks. - `vmCaps` — registered VM capability hooks.
- `imageBuild`, `requestHandler`, `guestWaitForSSH`, `guestDial`, - `imageBuild`, `requestHandler`, `guestWaitForSSH`, `guestDial`,
`waitForGuestSessionReady` — injectable seams used by tests. `waitForGuestSessionReady` — injectable seams used by tests.
## Subpackages
Pure helpers have moved into subpackages so the daemon package itself stays
focused on orchestration. Each subpackage takes explicit dependencies
(typically a `system.Runner`-compatible interface) and holds no global
state beyond small test seams.
| Subpackage | Purpose |
| --------------------------------- | ---------------------------------------------------------------------- |
| `internal/daemon/opstate` | Generic `Registry[T AsyncOp]` for async-operation bookkeeping. |
| `internal/daemon/dmsnap` | Device-mapper COW snapshot create/cleanup/remove. |
| `internal/daemon/fcproc` | Firecracker process primitives (bridge, tap, binary, PID, kill, wait). |
| `internal/daemon/imagemgr` | Image subsystem pure helpers: validators, staging, build script gen. |
| `internal/daemon/session` | Guest-session helpers: state paths, scripts, parsing, utilities. |
| `internal/daemon/workspace` | Workspace helpers: git inspection, copy prep, guest import script. |
`workspace` imports `session` for `ShellQuote` and `FormatStepError`; all
other subpackages are leaves (no other intra-daemon subpackage imports).
## Lock ordering ## Lock ordering
Acquire in this order, release in reverse. Never acquire in the opposite Acquire in this order, release in reverse. Never acquire in the opposite
@ -37,9 +55,9 @@ direction.
vmLocks[id] → {createVMMu, imageOpsMu} → subsystem-local locks vmLocks[id] → {createVMMu, imageOpsMu} → subsystem-local locks
``` ```
Subsystem-local locks (tapPool.mu, sessionRegistry.mu, opRegistry.mu, Subsystem-local locks (`tapPool.mu`, `sessionRegistry.mu`,
guestSessionController.attachMu/writeMu) are leaves. They do not contend `opstate.Registry` mu, `guestSessionController.attachMu` /
with each other. `writeMu`) are leaves. They do not contend with each other.
Notes: Notes:
@ -62,3 +80,9 @@ Only `internal/cli` imports this package. The surface is:
All other `*Daemon` methods are reached only through the RPC `dispatch` All other `*Daemon` methods are reached only through the RPC `dispatch`
switch in `daemon.go` and are free to move/rename during refactoring. switch in `daemon.go` and are free to move/rename during refactoring.
## Web UI
The optional web UI served at `web_listen_addr` is experimental. It is
enabled by default for local observability but is not considered a stable
or supported interface. Set `web_listen_addr = ""` in config to disable.

View file

@ -1,61 +1,87 @@
// Package daemon hosts the Banger daemon process. // Package daemon hosts the Banger daemon process.
// //
// The daemon exposes a JSON-RPC endpoint over a Unix socket and, optionally, // The daemon exposes a JSON-RPC endpoint over a Unix socket and, optionally,
// a local web UI. It owns VM lifecycle, image management, guest sessions, // an experimental local web UI. It owns VM lifecycle, image management,
// host networking bootstrap, and state persistence via internal/store. // guest sessions, host networking bootstrap, and state persistence via
// internal/store.
// //
// The package is organised into cohesive groups. A phased refactor is // The package is organised into cohesive groups. Pure stateless helpers for
// splitting each group into a subpackage; file names below reflect the // each group have been lifted into subpackages; orchestrator methods
// current (in-progress) grouping. // (Daemon receivers) stay here and compose them.
// //
// VM lifecycle: // Subpackages:
//
// internal/daemon/opstate Generic Registry[T AsyncOp] for async
// operations (VM create, image build).
// internal/daemon/dmsnap Device-mapper COW snapshot lifecycle.
// internal/daemon/fcproc Firecracker process helpers: bridge/tap,
// binary resolution, PID lookup, wait/kill.
// internal/daemon/imagemgr Image subsystem helpers: path validation,
// artifact staging, guest provisioning script
// generator, metadata.
// internal/daemon/session Guest-session helpers: state paths, runner
// / inspect / signal scripts, state snapshot
// parsing, launch helpers, ShellQuote,
// FormatStepError.
// internal/daemon/workspace Workspace helpers: git repo inspection,
// shallow copy prep, guest-side import,
// finalize script generation.
//
// VM lifecycle (in this package):
// //
// vm_create.go CreateVM and create-time disk provisioning // vm_create.go CreateVM and create-time disk provisioning
// vm_lifecycle.go Start/Stop/Restart/Kill/Delete // vm_lifecycle.go Start/Stop/Restart/Kill/Delete
// vm_set.go SetVM mutation // vm_set.go SetVM mutation
// vm_stats.go stats, health, ping, stale reaper // vm_stats.go stats, health, ping, stale reaper
// vm_disk.go system overlay, work disk provisioning // vm_disk.go system overlay, work disk provisioning
// vm_authsync.go per-VM authorized_key, git identity, and auth file sync // vm_authsync.go per-VM authorized_key, git identity, auth file sync
// vm_create_ops.go async begin/status/cancel registry for create // vm_create_ops.go async begin/status/cancel (uses opstate.Registry)
// vm_locks.go vmLockSet: per-VM mutex set
// vm.go fcproc forwarders, DNS helpers, small utilities
// capabilities.go pluggable capability hooks executed at VM start // capabilities.go pluggable capability hooks executed at VM start
// preflight.go prereq validation for VM start // preflight.go prereq validation for VM start
// snapshot.go device-mapper COW snapshot helpers // snapshot.go dmsnap forwarders + dmSnapshotHandles type alias
// ports.go port forwarding inspection // ports.go port forwarding inspection
// //
// Image management: // Image management (in this package):
// //
// images.go register, promote, delete, find, list // images.go register, promote, delete, find, list
// imagebuild.go build via firecracker build VM // imagebuild.go orchestrates the transient firecracker build VM
// image_build_ops.go async begin/status/cancel registry for build // image_build_ops.go async begin/status/cancel (uses opstate.Registry)
// image_seed.go managed work-seed fingerprint refresh // image_seed.go managed work-seed SSH fingerprint refresh
// //
// Guest interaction: // Guest interaction (in this package):
// //
// guest_sessions.go long-lived guest commands, attach, logs // guest_sessions.go dialGuest, waitForGuestSSH, refresh/inspect
// session_lifecycle.go Start/Stop/Kill/Get/List/signal orchestrators
// session_attach.go BeginGuestSessionAttach + bridge/forward/watch
// session_stream.go GuestSessionLogs, SendToGuestSession
// session_controller.go guestSessionController, sessionRegistry
// ssh_client_config.go daemon-managed SSH client key material // ssh_client_config.go daemon-managed SSH client key material
// workspace.go materialising host repos into guest // workspace.go ExportVMWorkspace, PrepareVMWorkspace
// opencode.go opencode host-side helpers // opencode.go opencode host-side helpers
// //
// Host bootstrap: // Host bootstrap (in this package):
// //
// nat.go NAT prereq registration // nat.go NAT prereq registration
// dns_routing.go systemd-resolved per-interface routing // dns_routing.go systemd-resolved per-interface routing
// tap_pool.go TAP interface pool // tap_pool.go TAP interface pool (state in tapPool type)
// //
// Core: // Core (in this package):
// //
// daemon.go Daemon struct, Open/Close/Serve, dispatch // daemon.go Daemon struct, Open/Close/Serve, dispatch
// dashboard.go dashboard metrics aggregation // dashboard.go dashboard metrics aggregation
// doctor.go host diagnostics // doctor.go host diagnostics
// logger.go slog configuration // logger.go slog configuration
// runtime_assets.go paths to bundled companion binaries // runtime_assets.go paths to bundled companion binaries
// web.go embedded web UI server // web.go experimental local web UI server
// //
// Lock ordering: // Lock ordering:
// //
// vmLocks[id] → {createVMMu, imageOpsMu} → subsystem-local locks // vmLocks[id] → {createVMMu, imageOpsMu} → subsystem-local locks
// //
// Subsystem-local locks live on the owning type (tapPool.mu, // Subsystem-local locks live on their owning type (tapPool.mu,
// sessionRegistry.mu, opRegistry.mu, guestSessionController.attachMu/writeMu) // sessionRegistry.mu, opstate.Registry mu, guestSessionController.attachMu /
// and do not contend with each other. See ARCHITECTURE.md for details. // writeMu) and do not contend with each other. See ARCHITECTURE.md for
// details.
package daemon package daemon