- Rust 55.1%
- Shell 27.5%
- JavaScript 9.1%
- Makefile 3.6%
- HTML 3.1%
- Other 1.6%
|
Some checks failed
Build and Test / build (push) Failing after 1m14s
Removed silent `|| true` on critical copy steps (seed data, service TOMLs). Added file count validation after copy — build now fails if seed data or service configs are empty. Added dist validation step checking for required binaries and data before declaring success. Previously, copy failures were silently swallowed, producing images without service configs (hero_services_server can't find profiles) or seed data (no admin user, no context data). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| crates | ||
| data | ||
| deploy/single-vm | ||
| docker | ||
| docs | ||
| examples | ||
| scripts | ||
| services | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| bootstrap.sh | ||
| buildenv.sh | ||
| Cargo.toml | ||
| Dockerfile.pack | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
Hero Services
Service orchestrator for the Hero OS ecosystem.
Hero OS is a suite of ~15 services (hero_books, hero_biz, hero_redis, hero_auth, hero_foundry, hero_embedder, hero_osis, hero_indexer, hero_voice, hero_cloud, and more) orchestrated by zinit inside a Docker container, with a Dioxus WASM frontend that embeds them via iframes or native islands.
Hero Services manages the lifecycle of all these services — building, installing, starting, stopping, and monitoring them via a unified JSON-RPC interface over Unix sockets. The hero_proxy reverse proxy routes HTTP traffic to each service's Unix socket, and the hero_os_app WASM frontend provides a unified desktop-like UI with a dock toolbar for switching between services.
Architecture
hero_services_sdk (library: types + async Unix socket client)
↑ ↑ ↑ ↑
| | | |
server CLI ui examples
| Crate | Type | Purpose |
|---|---|---|
hero_services_sdk |
library | Types, RPC client, shared protocol |
hero_services_server |
binary | Daemon, JSON-RPC over Unix socket |
hero_services |
binary | CLI client using SDK |
hero_services_ui |
binary | Axum admin panel using SDK |
hero_services_examples |
examples | Example programs demonstrating SDK usage |
Quick Start
Full workspace (Docker build)
mkdir -p ~/hero/src/lhumina_code && cd ~/hero/src/lhumina_code
curl -sSfL https://forge.ourworld.tf/lhumina_code/hero_services/raw/branch/development/bootstrap.sh | bash
cd hero_services
make dist # compile all binaries → dist/
make pack # build Docker image
make push # push to registry
bootstrap.sh clones all 18 repos (hero_services + 17 service repos + zinit) into the sibling layout that build-local.sh expects. Re-running pulls latest — safe to use for updates.
Local development (single service)
git clone -b development https://forge.ourworld.tf/lhumina_code/hero_services.git
cd hero_services
make run
Make Targets
make run # Build release, install, and run via zinit
make rundev # Build debug, install, and run via zinit (debug logging)
make stop # Stop all services
make restart # Restart all services
make status # Show service status (zinit list)
make logs # Show server logs
make logs-ui # Show UI logs
make install # Build release and install to ~/hero/bin
make installdev # Build debug and install to ~/hero/bin
make build # Standalone binary with embedded services
make check # cargo check + clippy
make test # Run unit tests
make test-all # Full test pipeline (unit + integration)
make smoke # Run gateway smoke tests against herodev (or GATEWAY_URL)
make smoke-basic # Run basic smoke tests (health + UI pages)
Sockets
All Unix sockets are located in:
~/hero/var/sockets/
| Service | Socket |
|---|---|
| Server (JSON-RPC) | ~/hero/var/sockets/hero_services_server.sock |
| Admin UI (HTTP) | ~/hero/var/sockets/hero_services_ui.sock |
No services bind TCP ports directly.
Accessing the Admin UI
Option 1 — hero_inspector (recommended for development):
hero_inspector can open any socket-based UI in your browser by spawning a local TCP→socket reverse proxy on a free port:
# Install and run hero_inspector with its own HTTP UI
cd ../hero_inspector && make install
hero_inspector_ui --http --port 8802 --open
Then use the inspector UI at http://localhost:8802 to discover all running
services. Click Open on any web UI service (e.g. hero_services_ui) and
the inspector will proxy it to a localhost port automatically.
Programmatically via JSON-RPC:
curl --unix-socket ~/hero/var/sockets/hero_inspector_ui.sock \
-X POST http://localhost/rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"inspector.open_website","params":{"service_id":"hero_services_ui"}}'
Returns { "port": 9100, "url": "http://127.0.0.1:9100" } — open that URL.
Option 2 — hero_proxy (production):
hero_proxy (port 8805) auto-discovers all sockets and routes by path:
http://localhost:8805/hero_services/
Option 3 — curl directly (quick debugging):
curl --unix-socket ~/hero/var/sockets/hero_services_ui.sock http://localhost/
Service Configuration Format
Each service is defined in a single TOML file under services/{profile}/. A service has a [server] component (required) and an optional [ui] component. Each component specifies how to install it — either by downloading a pre-built binary or building from source.
Minimal example (build from source)
[service]
name = "hero_redis"
description = "Redis — in-memory data store"
[server]
exec = "__HERO_BIN__/hero_redis_server"
build = "ssh://git@forge.ourworld.tf/lhumina_code/hero_redis.git"
install = { method = "build", branch = "development" }
[env]
RUST_LOG = "info"
[profile]
description = "Redis — in-memory data store"
actions = ["install", "run", "health"]
Full example (server + UI, download + build, shared build options)
[service]
name = "hero_os"
description = "Hero OS — web UI and backend"
depends_on = ["hero_osis_server"]
# Shared build options (features, source_deps) — applies to all components
[build]
features = ["web"]
base_features = ["core"]
required_features = ["island-archipelagos", "island-settings"]
available_features = ["island-ai", "island-chat", "island-calendar"]
[server]
exec = "__HERO_BIN__/hero_os_server"
download = "https://releases.ourworld.tf/hero_os/{version}/hero_os-{os}-{arch}"
build = "ssh://git@forge.ourworld.tf/lhumina_code/hero_os.git"
install = { method = "build", branch = "development" }
[ui]
exec = "__HERO_BIN__/hero_os_ui"
ports = [8804]
kill_others = true
[env]
RUST_LOG = "info"
[profile]
description = "Hero OS — web UI and backend"
actions = ["install", "run", "health"]
Component fields
Each component ([server] or [ui]) supports:
| Field | Type | Description |
|---|---|---|
exec |
string | Command to run (required) |
download |
string | Release URL template with {version}, {os}, {arch} placeholders |
build |
string | Git repo URL for building from source |
install |
inline table | Install instructions (see below) |
ports |
array | TCP ports used |
kill_others |
bool | Kill processes on declared ports before starting |
env |
table | Component-specific environment variables |
oneshot |
bool | Run once and exit (for setup scripts) |
Install instructions
# Download a specific version
install = { method = "download", version = "0.3.14" }
# Build from a branch
install = { method = "build", branch = "development" }
# Build from a specific commit
install = { method = "build", commit = "abc123" }
UI with its own build
When the UI comes from a different repo than the server, give it its own build and install:
[server]
exec = "__HERO_BIN__/hero_indexer"
build = "ssh://git@forge.ourworld.tf/lhumina_code/hero_index_server.git"
install = { method = "build", branch = "development" }
[ui]
exec = "__HERO_BIN__/hero_indexer_ui"
build = "ssh://git@forge.ourworld.tf/lhumina_code/hero_indexer_ui.git"
install = { method = "build", branch = "development" }
When the UI shares the server's build (same repo produces both binaries), omit build and install from [ui].
Placeholders
| Placeholder | Resolves to |
|---|---|
__HERO_BIN__ |
~/hero/bin/ |
__HERO_VAR__ |
~/hero/var/ |
__HERO_ROOT__ |
~/hero/ |
__HERO_SRC__ |
~/hero/src/ (or $CODEROOT) |
Naming convention
At load time, the unified TOML expands into zinit services:
[server]→{name}_server(e.g.hero_redis_server)[ui]→{name}_ui(e.g.hero_redis_ui)
Cross-service dependencies use these expanded names:
depends_on = ["hero_redis_server", "hero_indexer_server"]
Services
User Profile
| Service | Socket / Port | Purpose |
|---|---|---|
| hero_redis | hero_redis.sock + port 3378 |
In-memory data store |
| hero_indexer | hero_indexer.sock |
Full-text search |
| hero_indexer_ui | hero_indexer_ui.sock |
Indexer admin panel |
| hero_embedder | hero_embedder.sock |
Text embedding service |
| hero_embedder_ui | hero_embedder_ui.sock |
Embedder admin panel |
| hero_osis | hero_osis.sock |
Object storage API |
| hero_foundry | hero_foundry.sock |
Code repositories |
| hero_auth | hero_auth.sock |
OAuth2 authentication |
| hero_books | port 8883 | Book management |
| hero_os | hero_os.sock |
Hero OS core |
| hero_proxy | port 8080 | Reverse proxy / API gateway |
Admin Profile
| Service | Socket / Port | Purpose |
|---|---|---|
| forgejo | forgejo.sock + port 3393 |
Git forge |
| forgejo_mcp | port 3395 | MCP interface for Forgejo |
| hero_compute_manager | hero_compute_manager.sock |
Compute resource manager |
| hero_embedder | hero_embedder.sock |
Text embedding |
| my_router_path | my_router_path.sock + port 2918 |
Path-based router |
Beta Profile
| Service | Socket / Port | Purpose |
|---|---|---|
| hero_aibroker | hero_aibroker.sock |
AI model broker |
| hero_claude | port 3780 | Claude AI interface |
| hero_runner | port 3391 | Task runner |
| hero_shrimp | hero_shrimp.sock |
Shrimp AI service |
| mycelium | port 3392 | Network mesh protocol |
CLI Commands
hero_services health # Check server health
hero_services list # List all services
hero_services start|stop|restart <name> # Control a service
hero_services logs [name] [-n LINES] # View logs
hero_services config [name] # Show configuration
hero_services install <name> # Install a service
hero_services install-all # Install all services
hero_services build-status # Show build progress
Runtime Directories
~/hero/
├── bin/ # Service binaries
├── src/ # Source code (for build method)
├── var/
│ ├── sockets/ # Unix domain sockets
│ │ ├── hero_services_server.sock
│ │ ├── hero_services_ui.sock
│ │ ├── hero_redis.sock
│ │ ├── hero_osis.sock
│ │ └── ...
│ └── hero_zero/
│ └── installed/ # Install tracking
└── cfg/zinit/ # Generated zinit configs
Docker — Build & Deploy
Compiles all 34 binaries inside rust:1.93-bookworm containers (correct glibc for Debian Bookworm), then packs into a thin runtime image.
# Full pipeline: compile → pack → push → deploy to herodev
make deploy
# Individual steps:
make dist # Compile all binaries → dist/ (~10 min incremental, ~25 min cold)
make dist-quick # Skip WASM + shrimp (faster iteration)
make pack # Pack dist/ into thin Docker image (~10 sec)
make push # Push :dev image to registry
make deploy # dist + pack + push + deploy to herodev
# Promote to demo:
make demo # Tag :dev as :demo, push to registry
# Deploy to a specific environment:
cd deploy/single-vm && make update ENV=herodev # Pull + restart on VM
cd deploy/single-vm && make update ENV=herodemo
cd deploy/single-vm && make setup ENV=herodev # Full VM setup (first time)
Environment variables
| Variable | Default | Description |
|---|---|---|
SKIP_WASM |
0 |
Set to 1 to skip WASM frontend builds |
SKIP_SHRIMP |
0 |
Set to 1 to skip hero_shrimp (Bun) build |
DIST_DIR |
./dist |
Output directory for compiled binaries |
How it works
docker/build-local.shrunscargo build --releaseinside Bookworm containers with volume-mounted source code and persistent cargo caches (Docker volumes)Dockerfile.packcopies the pre-built binaries into adebian:bookworm-slimruntime imagedeploy/single-vm/manages VM provisioning and container lifecycle via SSH
Deployment tiers
| Tier | Image tag | Container name | Port |
|---|---|---|---|
| dev | :dev |
herodev |
8805 |
| demo | :demo |
herodemo |
8806 |
| prod | :prod |
heroprod |
8805 |
Container names and ports are configured in deploy/single-vm/envs/<env>/app.env.
Requirements
- Docker (for container-based compilation and deployment)
- Git, Make
- Bun (for hero_shrimp build, optional with
SKIP_SHRIMP=1)
Add ~/hero/bin to your $PATH:
export PATH="$HOME/hero/bin:$PATH"
License
Apache-2.0