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.
This repository now contains the first headless MVP implementation:
sprout-api: Go HTTP control plane with OIDC auth, audit, workflows, and PostgreSQL persistencesprout-site-agent: Go site-local worker with NATS assignment handling, iPXE/autoinstall rendering, and Redfish-first power-cycle supportsprout-cli: thin operator CLI for the supported MVP workflows
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
- 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.
Sprout is designed around these core elements:
sprout-api: public control-plane APIsprout-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:
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
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
- Start the local dependencies:
make bootstrap
make dev-up-
Copy
.env.exampleto.envand setSPROUT_SITE_IDonce you have created a site. -
Run the API:
make run-api-
Use Keycloak on
http://localhost:8082, obtain a token for thesprout-apiclient, and export it asSPROUT_API_TOKEN. -
Create a site with the CLI:
go run ./cmd/sprout-cli sites create --name "Lab A" --slug lab-a- Start the site agent after setting
SPROUT_SITE_ID:
make run-agent- 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- 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 listTo 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, andSPROUT_SECRET_ENV_PREFIXfor dev and Vault-backed secret resolutionSPROUT_TLS_ENABLED,SPROUT_TLS_CA_FILE,SPROUT_TLS_CERT_FILE,SPROUT_TLS_KEY_FILE, andSPROUT_WORKLOAD_TRUST_DOMAINfor 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.
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
- Contribution guidelines: CONTRIBUTING.md
- Security process: SECURITY.md
- Delivery outlook: ROADMAP.md
Sprout is intended to be released under Apache-2.0.