- Rust 54.7%
- Shell 27.9%
- JavaScript 9%
- Makefile 3.7%
- HTML 3.1%
- Other 1.6%
|
Some checks failed
Build and Test / build (push) Failing after 1m14s
- Fix false positives: skip hero_cloud_ui (intentionally inactive), accept 303 for hero_auth_ui (redirect to setup is valid) - Add section 10: books library verification (3 libraries, books > 0) - Add make verify: deploy + wait + smoke test in one command - Add make smoke-demo: test herodemo2 directly - Update default URLs from gent02 to gent04 - Add WAIT_SECS support for post-deploy settling - Update docs/ops/deployment.md with full workflow reference 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