`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

sh
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.

text
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 launcher

Command Surface

CommandPurpose
listList 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

sh
homeboy rig list

Lists every rig config currently visible under the Homeboy config directory.

show

sh
homeboy rig show studio

Prints the resolved rig spec. This is the fastest way to inspect a package-installed rig without opening the linked source file manually.

materialize

sh
homeboy rig materialize ./packages/example/rigs/example/rig.json
homeboy rig materialize ./custom/rig.json --source-root ./custom

materialize is the public read-only contract for package tooling that needs Homeboy’s canonical inheritance behavior. Its JSON result has this stable shape:

json
{
  "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

sh
homeboy rig up studio

Runs 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:

sh
homeboy --runner homeboy-lab rig up script-matrix --dry-run

The 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

sh
homeboy rig check studio

Runs 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

sh
homeboy rig lint studio
homeboy rig lint ./packages/studio --id studio
homeboy rig lint ./packages --all
homeboy rig lint ./packages/studio/rigs/studio/rig.json

Runs 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

sh
homeboy rig down studio

Runs 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

sh
homeboy rig repair studio

Repairs 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 classCoverage
symlinksRepaired. Creates missing links and relinks drifted ones. A real file or directory at the link path is reported blocked, never removed.
shared_pathsRepaired 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.
servicesRepaired 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.pathsReported. Present paths are unchanged; missing ones are skipped — repair does not create paths whose shape the rig never described.
resources.portsReported skipped. Port ownership is declarative; repair does not bind, probe, or reclaim ports.
resources.process_patternsReported skipped. Repair does not signal matched processes.
resources.exclusiveReported skipped. Exclusive tokens are lease-scoped; repair does not adjust rig leases.
lifecycle_snapshotsReported. 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:

StatusMeaningExit code
repairedDrift this rig owned and corrected.0
unchangedAlready healthy.0
skippedDeclared, but outside what repair manages. The detail says what to run instead.0
blockedDrift 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

sh
homeboy rig status studio

Reports service PIDs, stale service state, and last recorded up / check timestamps from the rig state directory.

Package Lifecycle

install

sh
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 --all

Installs 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

sh
homeboy rig update studio
homeboy rig update --all

Updates 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.

sh
homeboy rig sources list
homeboy rig sources refresh
homeboy rig sources refresh example-org-homeboy-rigs
homeboy rig sources remove example-org-homeboy-rigs

sources 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

sh
homeboy rig sync studio
homeboy rig sync studio --dry-run

rig 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.

jsonc
{
  "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.

jsonc
{
  "pipeline": {
    "up": [
      { "kind": "stack", "component": "studio", "op": "sync" },
      { "kind": "stack", "component": "playground", "op": "sync" }
    ]
  }
}

Active-Run Locks

sh
homeboy rig release-lock studio

Releases 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

sh
homeboy rig app install studio
homeboy rig app update studio --dry-run
homeboy rig app uninstall studio

rig 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

jsonc
{
  "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.json records service PIDs, shared-path ownership markers, and last up / check timestamps.
  • logs/<service-id>.log captures 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