Multi-user development session and Linux account management across node fleets.
  • Rust 59.8%
  • JavaScript 20.2%
  • HTML 11.5%
  • Shell 6.2%
  • CSS 2.3%
Find a file
despiegk 9999b31c56
Some checks failed
lab publish / publish (push) Failing after 5m44s
Update services_multiuser_spec.md
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-07 11:59:19 +02:00
.forgejo/workflows ci: install lab onto PATH from ~/.local/bin in the publish workflow 2026-05-29 15:42:15 -04:00
crates chore: rename herolib_derive to herolib_macros 2026-06-06 21:29:21 +02:00
docs Update services_multiuser_spec.md 2026-06-07 11:59:19 +02:00
schema feat: rename service.toml keys to canonical names and add oschema definitions 2026-05-31 22:52:43 +02:00
scripts codescalers: drop user.adopt + hero-group prerequisite 2026-05-20 15:29:27 +02:00
.gitignore chore: remove Cargo.lock and update gitignore 2026-06-06 08:05:29 +02:00
Cargo.toml chore: rename herolib_derive to herolib_macros 2026-06-06 21:29:21 +02:00
Cargo.toml.hero_builder_backup chore: downgrade rust-version to 1.95.0, add builder backup, use path_var_dir for data dir 2026-06-01 13:23:06 +02:00
CLAUDE.md chore: rename HERO_SOCKET_DIR→PATH_SOCKET, FORGEJO_TOKEN→FORGE_TOKEN; drop legacy env overrides 2026-05-26 12:31:37 +02:00
PURPOSE.md chore: rename HERO_SOCKET_DIR→PATH_SOCKET, FORGEJO_TOKEN→FORGE_TOKEN; drop legacy env overrides 2026-05-26 12:31:37 +02:00
README.md chore: rename HERO_SOCKET_DIR→PATH_SOCKET, FORGEJO_TOKEN→FORGE_TOKEN; drop legacy env overrides 2026-05-26 12:31:37 +02:00

hero_codescalers

Multi-user development session management for Linux servers, built on the Hero OS stack.

Overview

hero_codescalers manages Linux user accounts and SSH sessions across a fleet of nodes. State (nodes, admins, groups) is stored in a local sled embedded database. The dashboard UI is reachable over the mycelium overlay network.

Components

Binary Role
hero_codescalers_server JSON-RPC 2.0 backend (Unix socket rpc.sock)
hero_codescalers_admin Web dashboard (Unix socket admin.sock + optional HTTP)
hero_codescalers CLI — lifecycle management and direct API calls

Prerequisites — lab flow driver

The codescalers daemon runs as the driver Unix account. That account, plus its passwordless sudo entry, comes from lab's host bootstrap. Once per host (as any account that can sudo):

curl -sSfL https://forge.ourworld.tf/.../lab/install.sh | bash # lab binary in ~/hero/bin
lab flow driver # creates driver + /etc/sudoers.d/driver

The daemon then runs as driver. Every privileged operation (useradd, setfacl, btrfs subvolume, chown, …) shells out via lab's internal sudo helpers — the NOPASSWD entry makes them instantaneous.

Per-user sockets are reachable because lab sets /home/<user> and ~/hero/var/sockets/ to mode 0755 at user-create time. The driver's connect() traversal succeeds without any ACL or group machinery. Per-file modes (0600 on ssh_key.ed25519, hero_cfg.toml, …) still protect user secrets.

The dashboard surfaces a yellow banner if /etc/sudoers.d/driver is missing — pointing at lab flow driver as the fix.

Pre-existing accounts that were created with the old chmod 700 mode are fixed on their next user.reset or by a one-shot sudo chmod 0755 /home/<user>.


Quick start

# One-time: build and install binaries
lab service codescalers --install

# One-time: set the shared KVS secret (any passphrase)
proc secret set SECRET_CODESCALERS "my shared passphrase"

# Start the service (instance 0, port 5000, mycelium auto-detected)
lab service codescalers --start

# Check status
lab service codescalers --status

# Start as root (for user.create / user.delete)
sudo lab service codescalers --install
sudo lab service codescalers --start

Multi-instance support

Multiple instances can run side-by-side on the same machine — useful for staging/testing, or when you need isolated namespaces with different KVS secrets.

Port assignment

Ports are assigned automatically — no manual configuration needed:

Instance HTTP port Override
0 5000 hero_codescalers --port 9090 --start
1 5001 hero_codescalers --instance 1 --port 9091 --start
N 5000+N --port <explicit>

Unix socket directories

Each instance gets its own socket directory under $PATH_SOCKET (default: ~/hero/var/sockets/):

Instance Socket directory Paths inside
0 hero_codescalers/ rpc.sock, admin.sock
1 hero_codescalers_1/ rpc.sock, admin.sock
N hero_codescalers_N/ rpc.sock, admin.sock

hero_proc names

Instance Service name Server action UI action
0 hero_codescalers hero_codescalers_server hero_codescalers_admin
1 hero_codescalers_1 hero_codescalers_server_1 hero_codescalers_admin_1
N hero_codescalers_N hero_codescalers_server_N hero_codescalers_admin_N

Example: two instances side-by-side

# Instance 0 — primary (port 5000)
hero_codescalers --start

# Instance 1 — secondary (port 5001)
hero_codescalers --instance 1 --start

# Status
proc service status hero_codescalers
proc service status hero_codescalers_1

# Stop secondary
hero_codescalers --instance 1 --stop

Mycelium network integration

All instances attach to the mycelium overlay network automatically when the mycelium daemon is reachable. The UI HTTP listener binds to the node's mycelium IPv6 address so the dashboard is accessible from any node on the overlay — not just localhost.

  • Detection is attempted for every instance, regardless of --root.
  • The mycelium address is in the 400::/7 range; the script validates this.
  • If the daemon is unreachable, the service starts in Unix-socket-only mode (no HTTP listener). Pass --address <ipv6> to override.
# Auto-detect mycelium (recommended)
hero_codescalers --start

# Explicit address override
hero_codescalers --address 4f8:306f:d514:7dbd:: --start

# Explicit address + custom port
hero_codescalers --address 4f8:306f:d514:7dbd:: --port 5099 --start

UI Access Control

The admin dashboard HTTP listener can be restricted to a whitelist of Mycelium IPv6 addresses. The whitelist is stored in hero_proc secrets under the key ADMIN_SECRETS (context core) as a comma-separated list.

Unix-socket connections are always trusted — hero_router and local tooling are never blocked. Only direct TCP connections (from the Mycelium overlay) are subject to the whitelist.

If hero_proc is not running the whitelist feature is disabled and all TCP connections are allowed.

Managing the whitelist

Via the admin UI (recommended)

Open the dashboard → Admin tab → UI Access Control section.

Via the CLI

# Add an address
proc secret set ADMIN_SECRETS "4f8:306f:d514:7dbd:b27c:28aa:d12d:bdb6"

# Add multiple addresses (comma-separated, no spaces around commas)
proc secret set ADMIN_SECRETS "4f8:306f:d514:7dbd:b27c:28aa:d12d:bdb6,4f9:1234:abcd::1"

# View current whitelist
proc secret get ADMIN_SECRETS

# Disable enforcement (clear the list)
proc secret set ADMIN_SECRETS ""

CLI direct calls

The hero_codescalers binary proxies commands directly to the server:

hero_codescalers health
hero_codescalers stats
hero_codescalers user-list
hero_codescalers user-create alice --forge-token TOKEN
hero_codescalers user-delete alice
hero_codescalers session-list
hero_codescalers session-kill alice

# Query a non-default instance
hero_codescalers --instance 1 health
hero_codescalers --instance 1 user-list

# Or point at a specific socket
hero_codescalers --server ~/hero/var/sockets/hero_codescalers_1/rpc.sock health

Lifecycle via the CLI

hero_codescalers --start # instance 0, port 5000
hero_codescalers --instance 1 --start # instance 1, port 5001
hero_codescalers --instance 1 --stop

Building and installing

lab service codescalers --install # build + install all binaries to ~/hero/bin
lab service codescalers --start # register with hero_proc and start
lab service codescalers --stop # stop all binaries
lab service codescalers --status # show status

# For root/driver instances (user.create / user.delete require root actor)
sudo lab service codescalers --install
sudo lab service codescalers --start

Developer checks (no install needed):

cargo check --workspace # fast type-check
cargo fmt --all # format
cargo clippy --workspace --all-targets # lint
cargo test --workspace --lib # unit tests

Smoke testing

SOCK=~/hero/var/sockets/hero_codescalers/rpc.sock

# Health
curl -s --unix-socket $SOCK http://localhost/health | jq .

# OpenRPC doc
curl -s --unix-socket $SOCK http://localhost/openrpc.json | jq '.methods[].name'

# JSON-RPC health call
curl -s --unix-socket $SOCK -X POST http://localhost/rpc \
 -H 'Content-Type: application/json' \
 -d '{"jsonrpc":"2.0","id":1,"method":"health","params":{}}'

Environment variables

Variable Default Description
PATH_SOCKET ~/hero/var/sockets Base directory for Unix sockets
HERO_CODESCALERS_SOCK_NAME hero_codescalers Socket subdirectory name
HERO_CODESCALERS_DATA_DIR ~/hero/var/hero_codescalers/db sled database directory
HERO_CODESCALERS_ADDRESS UI HTTP bind address (IPv4 or IPv6)
HERO_CODESCALERS_PORT 9911 UI HTTP port