Skip to content

OctalMesh/Commodore

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.

Overview

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.

Installation

Using the bootstrap Admiral script

# Linux / macOS
bash admiral.sh

# Windows (PowerShell)
.\admiral.ps1

Build from source

go build -o commodore ./cmd/commodore

Go install

go install github.com/OctalMesh/Commodore/cmd/commodore@latest

Admiral

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

Commands

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

Global Flags

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

Environment Variables

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

  1. Built-in script defaults
  2. .env.example
  3. .env
  4. Custom file passed via --env/-e
  5. CLI flags (-n/--name, -s/--src, -o/--out, -d/--dir)

Build target resolution

Admiral looks for main.go in this order:

  1. <src>/main.go - single-binary project
  2. <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.

Usage examples

# 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 lint

Run locally

Linux / macOS:

bash admiral.sh

Windows (PowerShell):

.\admiral.ps1

Run from the network

Linux / macOS (requires curl):

curl -fsSL https://raw.githubusercontent.com/OctalMesh/Commodore/refs/heads/release/admiral.sh | bash

Windows (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.

Configuration

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.

Squadron

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 maneuver
Squadron 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

Unit

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

Environment Variable Cascading

Variables are inherited top-down with lower levels taking precedence:

Fleet level               (squadron root)
    └── Squadron level    (overrides fleet)
          └── Unit level  (highest priority - always wins)

CLI Reference

commodore [command] [flags]

Global 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

Commands

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

up

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 backend

down

Stops all reactors in reverse DAG order, ensuring clean teardown without breaking dependent services.

commodore down

doctor

Validates 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 backend

Example 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

status

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 service

Column 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

tree

Prints the discovered subordinate hierarchy as a tree, showing local IDs and fully qualified node IDs in parentheses. Nothing is started.

commodore tree

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

modules

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

Maneuvers

Maneuvers 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 lint

Maneuvers defined at the squadron level execute the action in the squadron's context. Maneuvers at the unit level execute inside that unit.

signal - Recursive Navigation

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 lint

Tip

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

Go SDK

Commodore exposes a public Go SDK at pkg/sdk for embedding orchestration logic directly into your own Go binaries.

Add as dependency

go get github.com/OctalMesh/Commodore@latest

Project layout

Admiral 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

import "github.com/OctalMesh/Commodore/pkg/sdk"

Quickstart

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)
  }
}

Reactors

A reactor is the runtime backend that powers a node. Commodore currently ships two reactor adapters:

tilt

Uses Tilt for live-reload orchestration. Reads a Tiltfile per environment blueprint.

reactor:
  provider: tilt
  blueprints:
    - env:  dev
      path: ./dev/Tiltfile

native

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

Examples

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


OctalMesh

Telegram   YouTube   TikTok   Instagram   X   Reddit
• • •

This project is licensed under the MIT License

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

About

✦ Role-driven CLI engine and SDK for building and orchestrating OctalMesh projects

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Contributors