Skip to content

devx/sprout

openCenter Sprout

Sprout is an Apache-2.0, API-first bare-metal lifecycle platform for discovering, commissioning, provisioning, operating, and retiring physical infrastructure across one or more sites.

Status

This repository now contains the first headless MVP implementation:

  • sprout-api: Go HTTP control plane with OIDC auth, audit, workflows, and PostgreSQL persistence
  • sprout-site-agent: Go site-local worker with NATS assignment handling, iPXE/autoinstall rendering, and Redfish-first power-cycle support
  • sprout-cli: thin operator CLI for the supported MVP workflows

Why Sprout Exists

Existing bare-metal platforms usually force one of three tradeoffs:

  • restrictive or incompatible licensing
  • tightly coupled control planes with high operational complexity
  • weak separation between core lifecycle logic and site-local execution

Sprout is intended to take a different path:

  • Apache-2.0 licensing from day one
  • a small Go control-plane core with clean module boundaries
  • site-local agents for hardware-facing work
  • API and CLI first, with UI following later
  • optional integrations for metadata, secrets, and identity instead of baking those systems into the core

Product Principles

  • API-first: every operator workflow must be available through a stable public API.
  • Small core: inventory, lifecycle, workflow, audit, and policy stay in the control plane; hardware side effects stay behind adapters and agents.
  • Site-local execution: boot services, metadata delivery, BMC actions, and artifact caching run near the hardware when possible.
  • Business-friendly reuse: permissive licensing and integration boundaries matter as much as feature depth.
  • Security by default: human auth, workload identity, auditability, and external secrets integration are first-class design requirements.

Target Architecture

Sprout is designed around these core elements:

  • sprout-api: public control-plane API
  • sprout-site-agent: site-local execution agent
  • PostgreSQL: system of record for inventory, workflow, and audit state
  • NATS JetStream: asynchronous workflow and site-agent messaging
  • embedded netboot, node metadata, and Redfish-backed Day 2 execution inside the site agent for the MVP

Additional details live in:

Planned Scope

The initial product focus is deliberately narrow:

  • hardware inventory and lifecycle state
  • commissioning and provisioning workflows
  • site registration and delegated execution
  • audited operator actions
  • a limited Day 2 surface for safe operational tasks

Sprout explicitly avoids becoming:

  • a general-purpose CMDB
  • a full content or patch management stack
  • a hypervisor or VM lifecycle platform
  • a network fabric orchestration system
  • an OpenStack distribution

Repository Layout

api/                    OpenAPI contracts
cmd/                    API, agent, and CLI entrypoints
db/migrations/          PostgreSQL schema migrations
deploy/                 local development assets such as Keycloak realm import
docs/product/           product intent, requirements, scope, use cases
docs/architecture/      target architecture, security, deployment, ADRs
docs/plans/             MVP, phases, risks, team model
internal/               control-plane, agent, store, messaging, and CLI packages
README.md               project overview
SECURITY.md             vulnerability reporting and security baseline
CONTRIBUTING.md         contribution workflow
ROADMAP.md              delivery outlook

Getting Started

  1. Start the local dependencies:
make bootstrap
make dev-up
  1. Copy .env.example to .env and set SPROUT_SITE_ID once you have created a site.

  2. Run the API:

make run-api
  1. Use Keycloak on http://localhost:8082, obtain a token for the sprout-api client, and export it as SPROUT_API_TOKEN.

  2. Create a site with the CLI:

go run ./cmd/sprout-cli sites create --name "Lab A" --slug lab-a
  1. Start the site agent after setting SPROUT_SITE_ID:
make run-agent
  1. Create a provisioning network and a machine with a PXE-capable interface:
go run ./cmd/sprout-cli networks create --site-id <site-id> --name provisioning --cidr 192.0.2.0/24 --gateway 192.0.2.1 --dns 1.1.1.1,8.8.8.8 --range-start 192.0.2.10 --range-end 192.0.2.50 --purpose provisioning
go run ./cmd/sprout-cli machines create --site-id <site-id> --hostname node-01 --architecture x86_64 --interface id=iface-1,name=eth0,macAddress=52:54:00:12:34:56,pxeEnabled=true,networkName=provisioning
  1. Use the CLI for machine lifecycle and capacity actions:
go run ./cmd/sprout-cli artifacts create --ref ubuntu-cache --name "Ubuntu Cache" --backend filesystem --base-url http://localhost:8081/artifacts --prefix ubuntu/24.04
go run ./cmd/sprout-cli images create --ref ubuntu-24.04 --name "Ubuntu 24.04" --architecture x86_64 --artifact-ref ubuntu-cache --kernel-path vmlinuz --initrd-path initrd
go run ./cmd/sprout-cli profiles create --ref default --name "Default" --cloud-config-template '#cloud-config
hostname: {{ hostname }}'
go run ./cmd/sprout-cli machines commission <machine-id> --reason "commission for adoption"
go run ./cmd/sprout-cli machines provision <machine-id> --image-ref ubuntu-24.04 --profile-ref default --network-id <network-id>
go run ./cmd/sprout-cli ip-allocations list --machine-id <machine-id>
go run ./cmd/sprout-cli machines allocate --site-id <site-id> --count 2 --label role=worker --architecture x86_64 --min-memory-mib 16384 --min-disk-bytes 536870912000
go run ./cmd/sprout-cli machines image <machine-id> --media-url https://cache.example.com/ubuntu.iso --boot-source virtual-media
go run ./cmd/sprout-cli machines power-on <machine-id> --reason "restore service"
go run ./cmd/sprout-cli machines power-off <machine-id> --reason "maintenance window"
go run ./cmd/sprout-cli machines boot-source <machine-id> --boot-source pxe --reason "next boot from network"
go run ./cmd/sprout-cli day2-actions list
go run ./cmd/sprout-cli approvals create --machine-id <machine-id> --action release --decision approved --reason "approved maintenance"
go run ./cmd/sprout-cli machines reboot <machine-id> --approval-id <approval-id> --reason "restart after patch"
go run ./cmd/sprout-cli machines remote-task <machine-id> --approval-id <approval-id> --command uptime --reason "capture host state"
go run ./cmd/sprout-cli action-executions list --machine-id <machine-id>
go run ./cmd/sprout-cli action-executions evidence <execution-id>
go run ./cmd/sprout-cli policy-decisions list --machine-id <machine-id>
go run ./cmd/sprout-cli workflows events <workflow-id>
go run ./cmd/sprout-cli sync-jobs create --site-id <site-id> --artifact-ref ubuntu-cache --mode preseed
go run ./cmd/sprout-cli sync-jobs list --site-id <site-id>
go run ./cmd/sprout-cli integration-jobs create --name lab-a-export --site-id <site-id> --kind metadata-export --provider webhook --endpoint https://ops.example.com/hooks/sprout
go run ./cmd/sprout-cli integration-jobs run <job-id>
go run ./cmd/sprout-cli sites health <site-id>
go run ./cmd/sprout-cli discoveries list --site-id <site-id>
go run ./cmd/sprout-cli discoveries accept <discovery-id>
go run ./cmd/sprout-cli audit list

To inspect the API contract directly, see api/openapi.yaml.

Site-scoped RBAC groups can be expressed as sprout-site:<site-id>:viewer, sprout-site:<site-id>:operator, or sprout-site:<site-id>:admin.

For headless secret and transport hardening, the agent and API also accept:

  • SPROUT_VAULT_ADDRESS, SPROUT_VAULT_TOKEN, and SPROUT_SECRET_ENV_PREFIX for dev and Vault-backed secret resolution
  • SPROUT_TLS_ENABLED, SPROUT_TLS_CA_FILE, SPROUT_TLS_CERT_FILE, SPROUT_TLS_KEY_FILE, and SPROUT_WORKLOAD_TRUST_DOMAIN for optional mTLS and SPIFFE-style workload identities

Workflow assignments and artifact sync jobs are targeted to the most recent capable site agent and carry renewable lease metadata so reconnects and multi-agent sites can recover cleanly.

The API also exposes Prometheus-compatible metrics at /metrics, returns an X-Request-Id header on every response, and supports integration jobs for webhook or OpenMetadata export plus HTTP-based inventory import.

Infrastructure providers are selected per capability with SPROUT_<CAP>_PROVIDER=builtin|external. Builtin network/IPAM/allocation use PostgreSQL. Builtin DHCP and DNS use the site agent and require SPROUT_DHCP_BIND_INTERFACE, SPROUT_DHCP_BIND_ADDR, and SPROUT_DNS_BIND_ADDR. External providers use bearer-auth REST endpoints at SPROUT_<CAP>_EXTERNAL_URL, and provisioning DNS records default to SPROUT_PROVISIONING_DOMAIN=provisioning.sprout.local.

Language and Runtime Direction

Sprout is planned as:

  • Go for the control plane, site agents, and core services
  • TypeScript for a later web UI
  • Python only for narrow integration-heavy adapters where it has a clear advantage

Contributing and Security

License

Sprout is intended to be released under Apache-2.0.

About

Sprout is an Apache-2.0, API-first bare-metal lifecycle platform for discovering, commissioning, provisioning, operating, and retiring physical infrastructure across one or more sites.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors