Commodore is a role-driven CLI engine and Go SDK for building and
orchestrating OctalMesh projects from a .commodore
configuration. It models your infrastructure as a naval fleet - squadrons
recursively orchestrate subordinates, units execute atomic processes - all
wired together by a DAG-based boot order with health checks, environment
cascading, and live TUI feedback.
Commodore solves the problem of orchestrating complex, multiservice projects where services have strict startup dependencies, heterogeneous runtimes, and environment-specific configurations.
| Concept | Description |
|---|---|
| Squadron | A recursive orchestrator node. Manages other squadrons or units, cascades environments, defines boot order via a manifest |
| Unit | An atomic execution leaf. Defines how a single service is built, started, and kept healthy |
| Reactor | The runtime backend powering a node (tilt or native) |
| Maneuver | A named, executable action (lint, test, deploy, ...) defined per node and exposed as a CLI subcommand |
| DAG | Directed Acyclic Graph computed from after: dependencies - guarantees correct startup and shutdown order |
Note
Commodore reads .commodore[.yaml|.yml] from the current directory by
default. Override with --config.
# Linux / macOS
bash admiral.sh
# Windows (PowerShell)
.\admiral.ps1go build -o commodore ./cmd/commodorego install github.com/OctalMesh/Commodore/cmd/commodore@latestAdmiral is the universal build and install script for Commodore and any custom CLI built on top of the Go SDK. It handles cross-platform builds, binary installation, alias linking, and automatic PATH management on Linux, macOS, and Windows.
| Command | Description |
|---|---|
install |
Build and install a CLI binary, with optional aliases |
build |
Cross-compile binaries for all platforms to an output directory |
uninstall |
Remove an installed binary and its aliases |
lint |
Run golangci-lint via go tool from the module root |
help |
Show usage information |
| Flag | Short | Env var | Description |
|---|---|---|---|
--env <path> |
-e |
- | Load a custom dotenv file |
--name <name> |
-n |
ADMIRAL_BINARY_NAME |
Binary name override |
--src <path> |
-s |
ADMIRAL_SOURCE_DIR |
Source path override |
--out <path> |
-o |
ADMIRAL_BUILD_DIR |
Build output directory |
--dir <path> |
-d |
ADMIRAL_INSTALL_DIR |
Install directory override |
| Variable | Default | Description |
|---|---|---|
ADMIRAL_BINARY_NAME |
commodore |
Primary binary name |
ADMIRAL_SOURCE_DIR |
current directory | Default source path |
ADMIRAL_BUILD_DIR |
./build |
Cross-build output directory |
ADMIRAL_INSTALL_DIR |
~/.local/bin |
Destination directory |
Variables can be set in .env or .env.example at the project root. Flag
values always take the highest priority.
Value precedence (lowest -> highest):
- Built-in script defaults
- .env.example
- .env
- Custom file passed via --env/-e
- CLI flags (-n/--name, -s/--src, -o/--out, -d/--dir)
Admiral looks for main.go in this order:
<src>/main.go- single-binary project<src>/cmd/<name>/main.go- standard multi-command layout
Important
The --name value (or ADMIRAL_BINARY_NAME) must match the directory name
under cmd/. This is how Admiral locates what to build.
# Install with default settings (reads .env / .env.example)
admiral install
# Install with a custom name and aliases
admiral install --name myapp --alias app
# Uninstall binary and aliases
admiral uninstall --name myapp --alias app
# Cross-compile for all platforms into ./dist
admiral build --name myapp --out ./dist
# Lint from module root
admiral lintLinux / macOS:
bash admiral.shWindows (PowerShell):
.\admiral.ps1Linux / macOS (requires curl):
curl -fsSL https://raw.githubusercontent.com/OctalMesh/Commodore/refs/heads/release/admiral.sh | bashWindows (PowerShell):
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/OctalMesh/Commodore/refs/heads/release/admiral.ps1)))Tip
Running from the network is the recommended onboarding flow for custom CLIs - ship your own Admiral URL in your project's README and users get a one-liner install.
Commodore discovers configuration by looking for .commodore[.yaml|.yml]
in the working directory. A project hierarchy is built by
nesting squadron configs that reference subordinate paths.
A squadron is a recursive orchestrator - it manages other squadrons or units
via a manifest.
Squadron .commodore.yaml example
# ============================================================================ #
# Squadron Commander #
# ============================================================================ #
# Role: squadron | The recursive orchestrator node. #
# Manages tactical groups and inter-unit synchronization. #
# ============================================================================ #
role: squadron # Defines the role of this config as a squadron commander
id: root-division # Unique identifier for this squadron (must be unique across the manifest)
binary: custom # Optional: Custom binary for this squadron to execute (defaults to 'commodore')
# ============================================================================ #
# Reactor Configuration #
# ============================================================================ #
# Defines the reactor provider and its configuration for live updates, #
# orchestration, and environment management across the squadron. #
# ============================================================================ #
reactor:
provider: tilt # Specifies Tilt as the reactor provider for live updates and orchestration
network: commodore-mesh # Optional: Custom network for inter-unit communication
context: ./ # Optional: Build context for the reactor
# Optional: Define the reactor configuration, such as the path to the Tiltfile
# and any additional settings needed for the reactor to function properly.
blueprints:
- env: dev # Optional: Name of the environment this blueprint applies to
path: ./dev/Tiltfile # Path to the configuration file
- env: staging
path: ./staging/Tiltfile
# Optional: Define environment variables for the whole squadron, accessible to
# all units and sub-squadrons.
environments:
- name: dev # Name of the environment
files: # Optional: Load environment variables from a file for this environment
- ./dev/.env
variables: # Optional: Define environment variables specific to this environment
- LOG_LEVEL=DEBUG
- SOME_VAR=some_value
- name: staging
files:
- ./staging/.env
variables:
- LOG_LEVEL=INFO
- SOME_VAR=some_other_value
# ============================================================================ #
# Fleet Manifest #
# ============================================================================ #
# The Manifest defines the hierarchy. Every path leads to another config. #
# No explicit roles needed here, each subordinate declares itself. #
# ============================================================================ #
manifest:
- id: sqd-frontend # Unique identifier for the subordinate squadron
path: ./modules/frontend # Points to a squadron directory (can also point to .yaml, without certain folder)
# Optional: Define tags for this squadron, which can be used for grouping
# and dependency management across the manifest.
tags:
- "frontend"
- "client"
# Optional: Define dependencies for this squadron, ensuring it starts after
# specified subordinates are healthy and running.
after:
- $tag-backend # Wait for all units tagged with 'backend' to be healthy before starting this squadron
- svc-auth
- svc-notification
# Optional: Define a health check for this squadron
healthcheck:
test: [ "curl", "-f", "http://localhost:3000/health" ] # Health check command for this squadron
interval: 30s # Interval for running the health check
timeout: 5s # Timeout for the health check command
retries: 3 # Number of retries before marking as unhealthy
- id: app-desktop # Unique identifier for the subordinate unit
path: ./apps/desktop # Points to a unit directory
tags: [ "client" ]
after: [ "sqd-frontend" ]
- id: svc-auth
path: ./services/auth
tags: [ "backend" ]
healthcheck:
test: [ "curl", "-f", "http://localhost:8080/health" ]
interval: 30s
timeout: 5s
retries: 3
- id: svc-notification
path: ./services/notification
tags: [ "backend" ]
healthcheck:
test: [ "curl", "-f", "http://localhost:8081/health" ]
interval: 30s
timeout: 5s
retries: 3
# ============================================================================ #
# Maneuvers #
# ============================================================================ #
# Maneuvers are the executable actions that this squadron performs. #
# ============================================================================ #
maneuvers:
- call: deploy # Unique identifier for this maneuver, used for invocation
description: "Deploy the entire squadron to the staging environment" # A brief description of what this maneuver does
action: [ "bash", "./scripts/deploy.sh", "staging" ] # The command to execute for this maneuverSquadron field reference
| Field | Type | Required | Description |
|---|---|---|---|
role |
string |
✔ | Must be squadron |
id |
string |
✔ | Unique identifier across the entire manifest |
binary |
string |
- | Custom binary to invoke (defaults to commodore) |
reactor.provider |
string |
✔ | tilt or native |
reactor.network |
string |
- | Custom inter-unit network name |
reactor.context |
string |
- | Build context path |
reactor.blueprints[].env |
string |
- | Environment name this blueprint applies to |
reactor.blueprints[].path |
string |
- | Path to reactor config file (e.g. Tiltfile) |
reactor.environments[].name |
string |
✔ | Environment name |
reactor.environments[].files |
[]string |
- | .env files to load |
reactor.environments[].variables |
[]string |
- | Inline KEY=VALUE pairs |
manifest[].id |
string |
✔ | Subordinate identifier |
manifest[].path |
string |
✔ | Path to subordinate directory or config file |
manifest[].tags |
[]string |
- | Grouping labels, usable as $tag-<name> selectors |
manifest[].after |
[]string |
- | IDs or $tag-<name> to wait for before starting |
manifest[].healthcheck.test |
[]string |
- | Command array for health probe |
manifest[].healthcheck.interval |
duration |
- | How often to run the probe |
manifest[].healthcheck.timeout |
duration |
- | Max time per probe |
manifest[].healthcheck.retries |
int |
- | Failures before marking unhealthy |
maneuvers[].call |
string |
✔ | CLI subcommand name |
maneuvers[].description |
string |
- | Help text shown in --help |
maneuvers[].action |
[]string |
✔ | Command to execute |
A unit is an atomic leaf - it defines a single service's lifecycle.
Unit .commodore.yaml example
# ============================================================================ #
# Unit Designation #
# ============================================================================ #
# Role: unit | The atomic execution unit of the Commodore fleet. #
# Handles the lifecycle, metadata, and identity of a single process. #
# ============================================================================ #
role: unit # Defines the role of this config as a standalone execution unit
id: svc-auth # Unique identifier (must match the ID in the Squadron manifest)
# ============================================================================ #
# Reactor Configuration #
# ============================================================================ #
# Defines how the unit is powered (virtualized/orchestrated). #
# The reactor handles the environment, ports, and build context. #
# ============================================================================ #
reactor:
provider: tilt # Specifies Tilt as the reactor provider [tilt | native]
context: ./ # Optional: Build context for the reactor
# Define the reactor configuration, such as the path to the Tiltfile and any
# additional settings needed for the reactor to function properly.
blueprints:
- env: dev # Optional: Name of the environment this blueprint applies to
path: ./dev/Tiltfile # Path to the configuration file
- env: staging
path: ./staging/Tiltfile
# Native provider blueprint example:
- env: dev
action: [ "docker", "build", "-t", "svc-auth:dev", "." ] # Command to build the service for the dev environment
# Optional: Define environment variables for the unit, accessible to the
# process and its sub-processes.
environments:
- name: dev # Name of the environment
files: # Optional: Load environment variables from a file for this environment
- ./dev/.env
variables: # Optional: Define environment variables specific to this environment
- LOG_LEVEL=DEBUG
- SOME_VAR=some_value
- name: staging
files:
- ./staging/.env
variables:
- LOG_LEVEL=INFO
- SOME_VAR=some_other_value
# ============================================================================ #
# Maneuvers #
# ============================================================================ #
# Maneuvers are the executable actions that this squadron performs. #
# ============================================================================ #
maneuvers:
- call: deploy # Unique identifier for this maneuver, used for invocation
description: "Deploy the service to the staging environment" # A brief description of what this maneuver does
action: [ "bash", "./scripts/deploy.sh", "staging" ] # The command to execute for this maneuver
- call: lint
description: "Run linters and static analysis on the codebase"
action: [ "npm", "run", "lint" ]
- call: test
description: "Execute unit tests with coverage reporting"
action: [ "npm", "test", "--", "--coverage" ]Unit field reference
| Field | Type | Required | Description |
|---|---|---|---|
role |
string |
✔ | Must be unit |
id |
string |
✔ | Must match the ID declared in parent squadron manifest |
reactor.provider |
string |
✔ | tilt or native |
reactor.context |
string |
- | Build context path |
reactor.blueprints[].env |
string |
- | Target environment |
reactor.blueprints[].path |
string |
- | Path to reactor config (Tiltfile) |
reactor.blueprints[].action |
[]string |
- | Direct command for native provider |
reactor.environments[].name |
string |
✔ | Environment name |
reactor.environments[].files |
[]string |
- | .env files to load |
reactor.environments[].variables |
[]string |
- | Inline KEY=VALUE pairs |
maneuvers[].call |
string |
✔ | CLI subcommand name |
maneuvers[].description |
string |
- | Help text |
maneuvers[].action |
[]string |
✔ | Command to execute |
Variables are inherited top-down with lower levels taking precedence:
Fleet level (squadron root)
└── Squadron level (overrides fleet)
└── Unit level (highest priority - always wins)
commodore [command] [flags]
| Flag | Short | Default | Description |
|---|---|---|---|
--config <path> |
-c |
.commodore[.yaml|.yml] |
Path to Commodore configuration file |
--env <name> |
-e |
dev |
Execution environment (dev, staging, ...) |
--tags <tags> |
-t |
- | Filter operations to nodes matching these tags |
--help |
-h |
- | Help for any command |
--version |
-v |
- | Version information |
| Command | Description |
|---|---|
up |
Start node and all subordinates in DAG order |
down |
Stop node and subordinates in reverse DAG order |
doctor |
Validate DAG, environments, and maneuvers |
status |
Show status for node and selected descendants |
tree |
Show discovered subordinate structure |
signal |
Delegate command to subordinate or broadcast to direct subordinates |
modules |
Manage git submodules |
Starts the current node and all its subordinates respecting the DAG dependency order. Launches an interactive TUI - spinner during environment checks, then streams reactor output into a scrollable viewport with a live status bar.
commodore up
commodore up --env staging
commodore up --tags backendStops all reactors in reverse DAG order, ensuring clean teardown without breaking dependent services.
commodore downValidates the entire configuration tree and prints a per-node diagnostic table. Exits non-zero if any check fails - safe to use in CI.
commodore doctor
commodore doctor --env staging
commodore doctor --tags backendExample output:
doctor: env=dev tags=
┌────────────────────────┬───────────┬──────┬──────────────────────────────────────┐
│SCOPE │CHECK │STATUS│DETAILS │
├────────────────────────┼───────────┼──────┼──────────────────────────────────────┤
│global │topology │ok │dependency graph resolved │
│global │environment│ok │effective env built for dev │
│octalweb │node │ok │role=squadron reactor=tilt maneuvers=0│
│octalweb-console │node │ok │role=squadron reactor=tilt maneuvers=0│
│octalweb-console-app-web│node │ok │role=unit reactor=tilt maneuvers=0 │
│octalweb-console-svc-gw │node │ok │role=unit reactor=tilt maneuvers=0 │
│octalweb-design │node │ok │role=squadron reactor=tilt maneuvers=0│
│octalweb-links │node │ok │role=squadron reactor=tilt maneuvers=0│
│octalweb-shop │node │ok │role=squadron reactor=tilt maneuvers=0│
│octalweb-shop-app-web │node │ok │role=unit reactor=tilt maneuvers=0 │
│octalweb-shop-svc-gw │node │ok │role=unit reactor=tilt maneuvers=0 │
└────────────────────────┴───────────┴──────┴──────────────────────────────────────┘
✓ doctor check passed for octalweb
Column descriptions:
| Column | Description |
|---|---|
SCOPE |
global for fleet-wide checks, qualified node ID for per-node checks |
CHECK |
topology - DAG integrity · environment - variable resolution · node - role, reactor, maneuvers |
STATUS |
ok or fail |
DETAILS |
Human-readable summary of what was checked |
Shows the full node tree with runtime metadata for each discovered node. Renders as an interactive table in the TUI.
commodore status
commodore status --env staging
commodore status --tags serviceColumn descriptions:
| Column | Description |
|---|---|
NODE |
Full qualified node ID (root · squadron · local-id) |
LOCAL |
Local ID as declared in the config (id:) |
ROLE |
Node role - squadron or unit |
REACTOR |
Reactor provider - tilt or native |
BINARY |
Custom binary override (binary: field), - for units |
HC |
Health check defined - yes / no |
TAGS |
Tags assigned to this node |
PATH |
Absolute path to the node config |
Prints the discovered subordinate hierarchy as a tree, showing local IDs and fully qualified node IDs in parentheses. Nothing is started.
commodore treeExample output:
octalweb
|- console (octalweb-console)
| |- app-web (octalweb-console-app-web)
| `- svc-gw (octalweb-console-svc-gw)
|- design (octalweb-design)
|- links (octalweb-links)
`- shop (octalweb-shop)
|- app-web (octalweb-shop-app-web)
`- svc-gw (octalweb-shop-svc-gw)
The format is <local-id> (<qualified-id>). Qualified IDs are the addresses
used with signal for deep delegation.
Manages Git submodules across the project. Supports subcommands:
commodore modules status # Show submodule status
commodore modules init # Initialize submodules
commodore modules update # Update submodules to tracked commits
commodore modules sync # Sync submodule URLs from .gitmodulesManeuvers are user-defined actions declared in each node's config and
automatically exposed as CLI subcommands. They appear alongside built-in
commands in --help.
# Run a maneuver on the current node
commodore test
commodore deploy --env staging
commodore lintManeuvers defined at the squadron level execute the action in the squadron's
context. Maneuvers at the unit level execute inside that unit.
Delegates a command or maneuver down the hierarchy. Target a specific subordinate by its qualified ID, or omit the ID to broadcast to all direct subordinates of the current node.
commodore signal [subordinate-id] [command-or-maneuver] [args...] [flags]# Run a maneuver on a direct unit
commodore signal svc-auth test
# Bring up a sub-squadron
commodore signal sqd-frontend up
# Broadcast to ALL direct subordinates (omit ID)
commodore signal doctor
# Deep delegation - chain signal calls across levels
commodore signal sqd-frontend signal app-web lintTip
Qualified IDs from commodore tree are the addresses used here.
Deep chains let you target any node in the hierarchy without cd.
Flags for signal:
| Flag | Short | Description |
|---|---|---|
--env <name> |
-e |
Execution environment passed down to the target |
--tags <tags> |
-t |
Filter which subordinates receive the signal |
--config <path> |
-c |
Path to Commodore configuration file |
--help |
-h |
Help for signal |
Commodore exposes a public Go SDK at pkg/sdk
for embedding orchestration logic directly into your own Go binaries.
go get github.com/OctalMesh/Commodore@latestAdmiral expects your custom binary entry point at cmd/<binary-name>/main.go.
This matches standard Go project conventions and is how Admiral resolves what
to build and install.
my-cli/
├── cmd/
│ └── my-cli/
│ └── main.go <- SDK entry point, picked up by Admiral
├── .commodore.yaml <- squadron or unit config
└── go.mod
Important
The directory name under cmd/ must match the Binary field in
sdk.Options - Admiral uses it to locate and build the binary.
import "github.com/OctalMesh/Commodore/pkg/sdk"package main
import (
"os"
"github.com/OctalMesh/Commodore/pkg/sdk"
)
// Version info injected at build time.
var Version = "v1.0.0"
func main() {
// 1. Initialize the Commander Engine
engine := sdk.NewCommander(sdk.Options{
Version: Version,
Binary: "custom", // Default binary name of custom CLI
})
// 2. Custom Commands
// While configuration allows defining shell 'maneuvers', sometimes you need
// complex, interactive, or purely Go-based logic.
engine.AddCommand(&sdk.Command{
Use: "seed",
Short: "Seed the platform database with initial test data",
RunE: func(context sdk.Context) error {
context.Log().Info("Connecting to PostgreSQL...")
// Your custom Go logic here...
context.Log().Success("Database successfully seeded.")
return nil
},
})
// 3. Execution
// Execute parses os.Args, resolves the manifest DAG, and runs the requested
// command.
if err := engine.Execute(); err != nil {
engine.Logger().Error("Fleet execution failed: %v", err)
os.Exit(1)
}
}A reactor is the runtime backend that powers a node. Commodore currently ships two reactor adapters:
Uses Tilt for live-reload orchestration. Reads a Tiltfile
per environment blueprint.
reactor:
provider: tilt
blueprints:
- env: dev
path: ./dev/TiltfileExecutes a command directly via the OS process runner. Useful for non-containerised services or custom build steps.
reactor:
provider: native
blueprints:
- env: dev
action: [ "docker", "build", "-t", "svc-auth:dev", "." ]Tip
Both providers honour the environments block for variable injection. You can
mix providers across nodes in the same squadron.
The examples/ directory contains ready-to-use reference
configurations:
| Example | Description |
|---|---|
examples/configuration/ |
Full squadron + unit YAML templates with every field documented |
examples/sdk/ |
Minimal Go binary built with the Commodore SDK |
- Feel free to use this project for any purpose, including commercial applications.
- You are permitted to modify, distribute, and include this project in any form, as long as the original copyright notice is retained.
- If you share or publish modified versions, attribution to the original GitHub repository is appreciated.
- This software is provided "as is", without any warranties or guarantees, as detailed in the license terms.
- Feel free to use this project for any purpose, including commercial applications.
- You are permitted to modify, distribute, and include this project in any form, as long as the original copyright notice is retained.
- If you share or publish modified versions, attribution to the original GitHub repository is appreciated.
- This software is provided "as is", without any warranties or guarantees, as detailed in the license terms.