`homeboy rig`
Manage local dev rigs: reproducible multi-component environments that can start services, prepare checkouts, sync combined-fixes stacks, run health checks, and install desktop launchers.
Synopsis
homeboy rig <COMMAND>Overview
A rig is a named environment spec. Local rig configs live at ~/.config/homeboy/rigs/<id>.json; package-installed rigs are linked or copied into that same flat config path so every command uses one lookup model.
Use rigs for local environments that otherwise become wiki runbooks: Studio plus Playground, WordPress core plus Gutenberg, a sandbox plus tunnel, or any setup where multiple repositories and services must be moved together.
rig package / local spec
|
v
~/.config/homeboy/rigs/<id>.json
|
+-- rig sync -> declared component stacks
+-- rig up -> services, git/build/patch/check steps, symlinks
+-- rig check -> health/preflight report
+-- rig down -> teardown
+-- rig app -> optional desktop launcherCommand Surface
| Command | Purpose |
|---|---|
list | List declared rigs. |
show <id> | Print one rig spec as JSON. |
materialize <rig.json> | Resolve a rig’s local inheritance chain as machine-readable JSON. |
up <id> | Run the rig’s up pipeline and materialize the environment. |
check <id> | Run the rig’s check pipeline and report all failures. |
lint <target> | Lint a rig ID, package path, or rig.json without touching the environment. |
package <target> | Validate rig package artifacts without touching the environment. |
down <id> | Run the rig’s down pipeline and stop managed services. |
repair <id> | Repair safe declared drift without running the full up pipeline. |
sync <id> | Sync every stack declared by the rig’s components. |
run <id> | Refresh, sync, check, and benchmark a rig profile end-to-end. |
status <id> | Show running services and last up / check state. |
runs <id> | List persisted observation runs for the rig. |
release-lock <id> | Release a stuck active-run rig lease after verifying no owner is active. |
install <source> | Install rigs from a local package path or git URL. |
update [id] | Pull and refresh git-backed installed rig packages. |
sources ... | Inspect, refresh, or remove installed rig source packages. |
app ... | Install, update, or remove a rig’s desktop launcher. |
All subcommands support --output <path> for structured JSON output in addition to stdout.
Local Lifecycle
list
homeboy rig listLists every rig config currently visible under the Homeboy config directory.
show
homeboy rig show studioPrints the resolved rig spec. This is the fastest way to inspect a package-installed rig without opening the linked source file manually.
materialize
homeboy rig materialize ./packages/example/rigs/example/rig.json
homeboy rig materialize ./custom/rig.json --source-root ./custommaterialize is the public read-only contract for package tooling that needs
Homeboy’s canonical inheritance behavior. Its JSON result has this stable shape:
{
"variant": "materialize",
"payload": {
"command": "rig.materialize",
"rig": { "id": "example" }
}
}payload.rig is normalized JSON after recursive extends, deep object merge,
$append, and $merge_by processing. It has no extends field or merge
directives. The default source root for the standard rigs/<id>/rig.json
package layout is the package root, so package-level templates resolve without
an extra flag. For any other layout, the default is the rig.json directory;
pass --source-root to select a wider permitted boundary. Inherited templates
must stay inside that source root.
Library consumers can use homeboy::core::rig::materialize_rig_spec_with_default_source_root
for the same default-root policy, or materialize_rig_spec when their caller
supplies an explicit boundary. The CLI JSON envelope is the public
machine-readable interchange contract; downstream rig-package tooling still
needs to migrate to this command or core API.
up
homeboy rig up studioRuns the up pipeline. Mutating rig commands acquire a resource lease first when the rig declares resources, so two active rig commands cannot mutate the same declared paths, ports, process patterns, or exclusive tokens at once.
rig up also participates in resource-policy warnings. If the machine is
already warm or hot, Homeboy warns on stderr before adding more load. The warning
is advisory only; use global --placement local when the extra pressure is expected.
rig up is intentionally local-only for Lab offload: the pipeline can manage local
services, leases, ports, and declared filesystem paths that are not portable
through the current single-workspace runner snapshot.
For command-only rigs, agents can ask Homeboy for a portable runner plan instead of materializing the rig locally:
homeboy --runner homeboy-lab rig up script-matrix --dry-runThe plan emits equivalent homeboy runner exec <runner-id> ... commands for each
kind: "command" step. It refuses rigs with services, declared resources,
symlinks, shared paths, or typed pipeline steps so local service stacks still stay
on the local rig up path.
The pipeline can start services, run typed git / build / extension / stack steps, apply idempotent local patches, create symlinks/shared paths, run declared lifecycle phases, and run checks.
A kind: "lifecycle" step executes one phase of a declared
homeboy/lifecycle-contract/v1 — that is how a rig provisions a disposable
workload and gets back a handle to it. Captured handles land in rig state, so a
later step or a teardown step in the down pipeline can address the
environment the runtime created. See lifecycle.
check
homeboy rig check studioRuns the check pipeline and reports every failing step instead of stopping at the first failure. Use this as the preflight for a local environment.
lint
homeboy rig lint studio
homeboy rig lint ./packages/studio --id studio
homeboy rig lint ./packages --all
homeboy rig lint ./packages/studio/rigs/studio/rig.jsonRuns env-independent rig package lint only: conflict markers, JSON validity, and
extends template materialization, plus materialized rig-spec contract checks.
It does not run requirements, component checkout probes, services, or live
check steps, so CI can validate rig packages before a full environment exists.
Use --all for a local package directory that contains multiple rigs.
down
homeboy rig down studioRuns the down pipeline, cleans rig-owned shared paths, and stops declared services. external services are adopted rather than spawned, so down can recycle stale daemons that were started by another tool.
repair
homeboy rig repair studioRepairs safe declared drift without running the full up pipeline. Use it after
rig check reports fixable local drift and you do not want to start services,
run builds, or execute the full materialization sequence.
repair is narrower than up: it applies only repairs the rig engine classifies
as safe and declared by the rig spec, and it refuses broader environment
materialization. check remains read-only; repair is the middle path for safe
state correction; up is the full mutating setup pipeline.
Every repair is ownership-checked. Repair never removes a file, directory, or symlink this rig did not create, and never signals a process it did not start.
| Declared class | Coverage |
|---|---|
symlinks | Repaired. Creates missing links and relinks drifted ones. A real file or directory at the link path is reported blocked, never removed. |
shared_paths | Repaired through the declared ensure / cleanup ops. Recreates a missing link, relinks or removes a link this rig owns, drops stale ownership records. A symlink this rig does not own, or a missing shared target, is reported blocked. |
services | Repaired for stale state only — a PID this rig recorded that is no longer alive. Running services are left alone. Repair does not start services (that is up), and adopted external services are reported, never signalled. |
resources.paths | Reported. Present paths are unchanged; missing ones are skipped — repair does not create paths whose shape the rig never described. |
resources.ports | Reported skipped. Port ownership is declarative; repair does not bind, probe, or reclaim ports. |
resources.process_patterns | Reported skipped. Repair does not signal matched processes. |
resources.exclusive | Reported skipped. Exclusive tokens are lease-scoped; repair does not adjust rig leases. |
lifecycle_snapshots | Reported. A live handle a declared lifecycle step still owns is skipped; a handle no declared step owns any more is blocked. Repair never deletes a handle record — the handle is opaque, so dropping it would strand a live environment rather than reap it. Reaping is the declared teardown step’s job (homeboy rig down), or homeboy runs resources --cleanup-plan. |
Each entry in the report carries a status and a detail explaining what
happened:
| Status | Meaning | Exit code |
|---|---|---|
repaired | Drift this rig owned and corrected. | 0 |
unchanged | Already healthy. | 0 |
skipped | Declared, but outside what repair manages. The detail says what to run instead. | 0 |
blocked | Drift that needs manual attention — repair refuses to act. | 1 |
The report totals each status (repaired, unchanged, skipped, blocked).
success is false, and the command exits 1, only when something is blocked.
status
homeboy rig status studioReports service PIDs, stale service state, and last recorded up / check timestamps from the rig state directory.
Package Lifecycle
install
homeboy rig install https://github.com/example-org/homeboy-rigs.git//packages/studio --id studio
homeboy rig install ./packages/studio
homeboy rig install ./packages/studio --reinstall
homeboy rig install https://github.com/example-org/homeboy-rigs.git//packages --allInstalls rigs from a local directory or git-backed package. Package discovery accepts either a single rig.json or a package layout with rigs/<id>/rig.json. If the selected package also contains stacks/*.json, those stack specs are installed alongside the rig. Existing stack specs with different content are treated as user-owned config and are left in place instead of being overwritten.
Use --reinstall when the intent is to explicitly refresh an existing matching rig install from the same package source. rig install still refuses user-owned conflicts, such as an existing rig config that declares a different ID or an existing stack spec with different content. --force is accepted as a reinstall alias for users who reach for overwrite wording; --placement local remains a separate global resource-policy choice and does not control install replacement behavior.
Git sources may include a Terraform-style repo.git//subpath selector. Homeboy clones the package root, records source metadata, and discovers rigs from the selected subpath. Local package sources are linked in place and are updated outside Homeboy.
update
homeboy rig update studio
homeboy rig update --allUpdates git-backed package sources with git pull, then refreshes the installed rig and stack config links. Local linked sources are skipped by --all and error for single-rig updates because the source is already the editable checkout.
If the user replaced an installed config file with their own file, update preserves that user-owned config and reports it as skipped instead of overwriting it.
sources
package
Validates rig package artifacts without touching the live environment.
sync
Synchronizes the stacks declared by a rig’s components.
run
Refreshes, synchronizes, checks, and benchmarks a rig profile end-to-end.
release-lock
Releases a stale active-run lock after the holder is gone or its TTL has expired.
app
Installs, updates, or removes the rig’s desktop app launcher.
artifact
Registers local command-step evidence with the enclosing rig run.
homeboy rig sources list
homeboy rig sources refresh
homeboy rig sources refresh example-org-homeboy-rigs
homeboy rig sources remove example-org-homeboy-rigssources list groups managed rigs and stacks by package source, package path, revision, content identity, and ownership. Managed groups carry source_status: "managed"; package_present and stack component_path_present are independent availability observations. The JSON report also includes orphaned_stacks for installed stack configs that have no source metadata. These rows are reported as legacy_missing_metadata, include a content identity and the adopt_package_source recovery action (homeboy rig install <authoritative-package-source> --all --reinstall), and never infer provenance from filenames or modify the spec during inspection.
sources refresh pulls recorded git-backed package paths, refreshes Homeboy-owned installed rig and stack specs, and reports source, before/after revisions, installed config path, and source spec path. sources remove removes Homeboy-owned config links and metadata for one source package; it also removes cloned git packages, while linked local package directories are left in place.
Stack Sync
homeboy rig sync studio
homeboy rig sync studio --dry-runrig sync finds every component with a stack field and delegates to homeboy stack sync <stack-id>. This is the rig-level entry point for keeping combined-fixes branches current before a local environment is brought up. The rig component path must resolve to the same checkout as the referenced stack’s component_path; mismatches fail before branch rewriting starts.
{
"components": {
"studio": {
"path": "~/Developer/studio",
"stack": "studio-combined"
},
"playground": {
"path": "~/Developer/wordpress-playground",
"stack": "playground-combined"
}
}
}rig up does not sync stacks implicitly. If stack sync should be part of an up pipeline, add an explicit stack pipeline step.
{
"pipeline": {
"up": [
{ "kind": "stack", "component": "studio", "op": "sync" },
{ "kind": "stack", "component": "playground", "op": "sync" }
]
}
}Active-Run Locks
homeboy rig release-lock studioReleases a stuck active-run lock for a rig lease so a new local run can proceed.
Use it only after verifying the recorded owner process or runner is no longer
active; normal up, check, down, and repair flows release their own locks.
App Launchers
homeboy rig app install studio
homeboy rig app update studio --dry-run
homeboy rig app uninstall studiorig app manages an optional desktop launcher declared in app_launcher. It can generate a macOS .app wrapper or a Linux .desktop file that runs rig preflight, runs rig up, and opens the target app when the rig is ready. Use --dry-run to preview generated paths without writing or deleting files.
Minimal Example
{
"id": "studio",
"description": "Studio + Playground dev environment",
"components": {
"studio": {
"path": "~/Developer/studio",
"stack": "studio-combined"
}
},
"resources": {
"ports": [9724],
"process_patterns": ["wordpress-server-child.mjs"]
},
"services": {
"tarballs": {
"kind": "http-static",
"cwd": "${components.studio.path}/dist/packages-for-self-hosting",
"port": 9724,
"health": { "http": "http://127.0.0.1:9724/", "expect_status": 200 }
},
"studio-daemon": {
"kind": "external",
"discover": { "pattern": "wordpress-server-child.mjs" }
}
},
"pipeline": {
"up": [
{ "kind": "service", "id": "tarballs", "op": "start" },
{ "kind": "service", "id": "tarballs", "op": "health" }
],
"check": [
{ "kind": "service", "id": "tarballs", "op": "health" },
{
"kind": "check",
"label": "daemon newer than CLI bundle",
"newer_than": {
"left": { "process_start": { "pattern": "wordpress-server-child.mjs" } },
"right": { "file_mtime": "${components.studio.path}/dist/cli/index.js" }
}
}
],
"down": [
{ "kind": "service", "id": "studio-daemon", "op": "stop" },
{ "kind": "service", "id": "tarballs", "op": "stop" }
]
}
}State
Rig runtime state lives at ~/.config/homeboy/rigs/<id>.state/:
state.jsonrecords service PIDs, shared-path ownership markers, and lastup/checktimestamps.logs/<service-id>.logcaptures stdout/stderr for rig-managed services.
Package source metadata lives next to Homeboy’s rig and stack config directories so rig update and rig sources can tell which files are Homeboy-owned.
State is ephemeral. Deleting it makes the next command re-probe the environment; it is not the source of truth for the rig spec.
See Also
- rig-spec.md – full spec schema reference.
- stack.md – combined-fixes branch specs used by
rig sync. - bench.md – rig-pinned benchmark runs.
- rig-matrix-axis-composition.md – future design for derived rig variants.
- fleet.md – remote multi-project equivalent; rigs are local, fleets are remote.