Managing one repository is easy. Managing twenty interconnected micro-repos—keeping their build scripts, OSS licenses, CI pipelines, and Git workflows synchronized across multiple languages—is a nightmare.
scaffold-repo is a Declarative Fleet Manager and build orchestrator for polyglot ecosystems. Instead of manually updating 20 different CMakeLists.txt or pyproject.toml files, you define your company's standards in a centralized Template Registry. With a single CLI command, scaffold-repo resolves dependency graphs, injects stack-specific build scripts, enforces license compliance, and orchestrates Git branching across your entire fleet.
Since scaffold-repo is a global fleet manager, it is highly recommended to install it using pipx so it is isolated but globally available on your command line.
# 1. Clone the orchestrator
git clone https://github.com/contactandyc/scaffold-repo.git
cd scaffold-repo
# 2. Install globally
pipx install .
# (Optional) If you are actively developing the templates or engine:
pip install -e .Verify the installation by running: scaffold-repo --help
1. Initialize your Workspace:
scaffold-repo --initThe dynamic wizard connects to your company's Template Registry, asks you for your default development environments (like your preferred Python version or CMake generator), and drops a .scaffoldrc.yaml into your workspace.
2. Create a Project:
scaffold-repo --create my-python-app- the-macro-library scaffold.yaml
- a-json-library scaffold.yaml
- a-json-sax-library scaffold.yaml
- a-json-schema-builder-library scaffold.yaml
- a-curl-library scaffold.yaml
- a-map-reduce-library scaffold.yaml
- a-memory-library scaffold.yaml
- sql-parser-library scaffold.yaml
- the-io-library scaffold.yaml
- the-lz4-library scaffold.yaml
The engine asks what stack you want (e.g., Python, C++), applies your organizational profile, generates the initial code, and locks the configuration into a local scaffold.yaml.
3. Build and Develop predictably:
cd my-python-app
./build.sh installThe generated build.sh provides a predictable, standardized contract for developers. However, the repository is 100% standalone. You can bypass the script entirely and run standard cmake, make, pip, or python commands directly. scaffold-repo is never required to build or run the generated code.
- Zero Vendor Lock-In: Repositories generated by
scaffold-repoare completely standalone units. They do not depend on the orchestrator to build, test, or run. The generated./build.shis simply a convenience wrapper to provide a unified interface across the fleet. - Fleet-Wide Aliases & Multi-Repo Execution: Define groups of repositories in
resources/aliases.yaml. Runscaffold-repo my-team-alias --updateto seamlessly clone, scaffold, and upgrade dozens of repositories concurrently. - The Ultimate Dry-Run (
--diff): When managing a massive fleet, blindly applying template updates is dangerous. Runscaffold-repo all --diffto get a unified, bird's-eye view of exactly how your templates have drifted, what licenses need updating, or what local files are dirty across your entire ecosystem before modifying a single file on disk. - ✨ Context-Aware Execution: Once you
cdinto a generated project,scaffold-repoautomatically detects yourscaffold.yaml. - Decentralized, Git-Native Resolution: Dependencies aren't locked in a proprietary package manager. The engine reads YAML
depends_onarrays that point to actual Git URLs, topologically sorts the graph, and automatically clones and builds external dependencies in the exact required order. - Automated OSS Compliance: Automatically translates and injects SPDX license headers into your code (
//for C++,#for Python). Supports multi-license repositories natively—apply Apache-2.0 to your core project, but seamlessly enforce BSD-3 headers for files insidesrc/third_party/.
A core philosophy of scaffold-repo is the strict separation of Implementation (the code) and Standardization (the templates).
While the global Template Registry dictates the rules of your ecosystem, the local scaffold.yaml file (sitting at the root of every generated repository) provides the context. This ensures that individual repositories maintain their own specific information and are never blindly tied to the orchestrator.
Furthermore, the depends_on array utilizes a Decentralized Graph. Notice that dependencies explicitly declare remote Git URLs or system packages, rather than relying on a proprietary internal registry:
Example scaffold.yaml:
project_title: A Map Reduce Library
version: 0.0.3
stack: c/cmake
date_created: 2025-08-01
# pulls profile from templates/profiles/default.yaml
profile: default
# 1. Bind to the centralized Template Registry
base_templates:
repo: https://github.com/contactandyc/scaffold-templates.git
ref: main
# 2. Decentralized, Git-native dependency linking
depends_on:
- https://github.com/contactandyc/the-io-library.git
- system/OpenSSL
# 3. Define inline, custom licenses for specific third-party files
licenses:
lz4_custom:
spdx: |
SPDX-License-Identifier: BSD-2-Clause
Portions © 2011–present Yann Collet
license_overrides:
"src/third_party/lz4/**": lz4_custom
# 4. Route sub-applications and examples dynamically
apps:
context:
dest: examples
depends_on:
- https://github.com/contactandyc/a-map-reduce-library.git
01_word_count:
binaries:
word_count:
- src/main.cBecause the repository retains its own source of truth, it remains a standard, portable Git repository. The orchestrator merely reads this manifest to compute linking requirements, auto-discover source/test files, inject custom inline licenses to specific files, and execute the build graph.
scaffold-repo actively manages your development lifecycle, enforcing a clean main -> dev-* -> feat/* branching topology.
Note: The examples below show running commands inside a single repository. You can run these exact same commands against dozens of repositories at once from your workspace root by providing an alias: scaffold-repo my-alias --update
1. Start a Feature
scaffold-repo --start-feature "add-auth"Automatically checks out the current integration branch (e.g.,
dev-v0.1.1) and creates the branchfeat/add-auth.
2. Compile & Iterate
scaffold-repo --build-deps --build3. Commit and Push
scaffold-repo --commit "feat: added auth module" --pushCommits changes to your feature branch and pushes to origin. (The engine blocks direct commits to
mainordev-*).
When the platform team updates a license or modifies a global template, you can sync the changes across your repositories effortlessly.
1. Preview the Fleet Drift
scaffold-repo --diffSafely inspect exactly what files the engine wants to update across your active projects.
2. Apply Template Updates
scaffold-repo --updatePulls down the latest templates and merges them with your code. Magic: If you are currently sitting on a protected
dev-*branch, the engine will automatically spawn achore/update-scaffoldingbranch for you!
3. Publish to Integration
scaffold-repo --publish-feature --pushMagic: Because you are on the
chore/update-scaffoldingbranch, the engine automatically detects the dirty tree, commits the changes for you, merges the code into thedev-*integration branch, and cleans up the working branches!
Once your features and updates are merged into the integration branch, cut the official release.
1. Release & Tag
scaffold-repo --publish-release --pushChecks out
main, merges thedevbranch, auto-tags the release based on yourscaffold.yamlversion, updates the registry, and pushes the tags to origin.
All of scaffold-repo's power comes from the Template Registry. The engine itself contains zero hardcoded opinions. By default, the engine connects to a central Base Registry that you dictate in your workspace configuration.
templates/
├── .scaffold-defaults.yaml # Global router: defines global variables, prompts, and packages
├── base/ # Universal repository defaults (e.g., .gitignore, AUTHORS)
├── stacks/ # The technical implementations (e.g., c/cmake, python/standard)
├── profiles/ # Organizational standards (author info, default licenses, tools)
├── mixins/ # Modular, optional Jinja templates (changie, jekyll-site)
├── libraries/ # The global dependency index (how to build/link external tools)
├── licenses/ # SPDX logic and NOTICE file generators
├── app-resources/ # Special templates looped per sub-application inside a repo
└── resources/ # Global assets like aliases.yaml or canonical license texts
If you are a Platform Engineer looking to write custom templates, configure organizational profiles, or define internal dependencies, please read the Template Authoring Guide.
Usage: scaffold-repo [PROJECTS...] [OPTIONS]
Arguments:
PROJECTS One or more projects/namespaces/aliases to scaffold or build.
(e.g., 'my-python-app', 'my-alias', 'all')
*Note: Omit if running inside a project directory!*
Workspace Options:
--init Initialize a .scaffoldrc workspace configuration (Interactive)
-C, --cwd PATH Run as if started in <PATH> (default: current dir)
--templates-dir PATH Override templates directory (auto-detects ./templates)
--start-feature NAME Start a feature branch off the integration dev branch
Scaffolding Options:
--create SLUG Create a new project in the workspace (Interactive)
--update Explicitly apply template updates to the targeted repositories
--diff Print unpaginated Git diffs for targeted repos
-y, --assume-yes Apply template updates without prompting
--show-diffs Print inline diffs before applying file updates
--no-prompt Do not prompt during SPDX license header fixups
Dependency Lifecycle:
--clone-deps Fetch external dependencies without compiling
--build-deps Fetch, compile, and install external dependencies
--clean-deps Wipe build caches for dependencies
Target Lifecycle (Your Code):
--clean Run './build.sh clean' on the targeted projects
--build Run './build.sh build' on the targeted projects
--install Run './build.sh install' on the targeted projects
Git Orchestration:
--commit MSG Commit changes (blocked on 'main' and 'dev-*')
--publish-feature Merge current feature branch into dev branch and delete feature
--drop-feature Discard current feature branch and uncommitted changes
--publish-release Merge dev branch into main, tag it, and update registry version
--push Push commits to origin