A CLI for managing project templates and syncing common files across multiple projects.
- Template Sources: Use git repos or local directories as template sources
- Inheritance: Templates can extend other templates (CSS-like cascade)
- Prompts: Collect user input when creating projects with input, select, and confirm prompts
- Conditional Files: Include different files based on prompt answers (e.g., different LICENSE files)
- Commands: Run post-init commands (npm install, build, etc.) with cascading inheritance
- Sync: Keep common files (LICENSE, .gitignore, etc.) in sync across all your projects
- Conflict Detection: Smart handling of local modifications vs template updates
brew tap waynehaffenden/tap
brew install orbRequires Bun v1.0+
git clone https://github.com/waynehaffenden/orb.git
cd orb
bun install
bun run buildThe compiled binary will be at dist/orb.
# From a git repo
orb template add https://github.com/your-org/templates.git
# Or from a local directory
orb template add /path/to/templatesorb init my-projectcd existing-project
orb add# Sync all files
orb sync --all
# Sync specific file
orb sync LICENSE
# Dry run (preview changes)
orb sync --all --dry-run
# Sync and commit changes
orb sync --all --commit --message "update templates"templates/
├── orb.json # Manifest (required)
├── .orbignore # Files to ignore
├── base/ # Base template
│ ├── LICENSE.MIT # Conditional file variant
│ ├── LICENSE.Apache-2.0
│ ├── .gitignore
│ └── README.md # Can contain {{variables}}
├── node/ # Node.js specific (extends base)
│ ├── package.json
│ └── tsconfig.json
└── bun/ # Bun specific (extends node)
└── bunfig.toml
The manifest defines template metadata, inheritance, prompts, and conditional files:
{
"$schema": "https://raw.githubusercontent.com/waynehaffenden/orb/main/schemas/orb.json",
"name": "My Templates",
"version": "1.0.0",
"author": "Your Name",
"description": "Standard project templates",
"templates": {
"base": {
"description": "Base template with common files",
"prompts": [
{
"name": "description",
"message": "Project description:",
"type": "input"
},
{
"name": "author",
"message": "Author name:",
"type": "input"
},
{
"name": "license",
"message": "License:",
"type": "select",
"choices": ["MIT", "Apache-2.0", "GPL-3.0"],
"default": "MIT"
},
{
"name": "includeCI",
"message": "Include CI workflow?",
"type": "confirm",
"default": true
}
],
"conditionalFiles": {
"LICENSE": {
"source": "license",
"mapping": {
"MIT": "LICENSE.MIT",
"Apache-2.0": "LICENSE.Apache-2.0",
"GPL-3.0": "LICENSE.GPL-3.0"
}
}
}
},
"node": {
"extends": "base",
"description": "Node.js project template"
},
"bun": {
"extends": "node",
"description": "Bun project template"
}
}
}Prompts collect user input when creating a project. Three types are supported:
| Type | Description | Properties |
|---|---|---|
input |
Free text input | default (string) |
select |
Choose from options | choices (array), default (string) |
confirm |
Yes/no question | default (boolean) |
Prompt answers are available as variables in Handlebars templates.
Conditional files let you include different file variants based on prompt answers. For example, to offer multiple license options:
- Create file variants with a naming convention:
LICENSE.MIT,LICENSE.Apache-2.0 - Add a select prompt to ask which license to use
- Map prompt answers to file variants in
conditionalFiles
The output file (LICENSE) will contain the content from the selected variant.
Templates can define commands to run after project creation or sync. Commands cascade through inheritance - parent commands run first, then child template commands:
{
"templates": {
"base": {
"commands": [
{
"name": "install",
"run": "npm install",
"description": "Install dependencies"
}
]
},
"node": {
"extends": "base",
"commands": [
{
"name": "build",
"run": "npm run build",
"description": "Build the project"
}
]
}
}
}When creating a project from node, both commands run in order: npm install then npm run build.
By default, orb asks for confirmation before running commands. Use --run-commands to skip:
orb init my-project --run-commands
orb sync --all --run-commandsExclude files from being treated as templates:
# Comments are supported
tests/
*.test.ts
docs/
All template files are processed through Handlebars, so you can use {{variables}} in any file:
Built-in variables:
projectName- Project nametemplate- Template nameyear- Current year
Custom variables from prompts are also available (e.g., description, author, license).
| Command | Description |
|---|---|
orb init [name] [template] |
Create a new project (use --run-commands to auto-run commands) |
orb add [path] |
Add an existing project to the registry |
orb sync [file] |
Sync templates to projects (use --run-commands to auto-run commands) |
orb status |
Check sync status |
orb list |
List registered projects |
orb scan [path] |
Scan for orb.lock projects |
orb remove <name> |
Remove project from registry |
orb template list |
List template sources |
orb template add <url|path> |
Add a template source |
orb template update [name] |
Update template sources |
orb template remove <name> |
Remove a template source |
orb template init [path] |
Create a new template source |
orb config |
View or change project configuration |
orb sync [file] [options]
Options:
-a, --all Sync all template files
-p, --project <name> Sync to specific project only
-c, --commit Commit and push changes
-m, --message <msg> Custom commit message
-b, --branch <name> Create a branch for changes
-d, --dry-run Preview without making changes
--run-commands Run template commands without confirmationCreated in each project to track sync state:
{
"template": "node",
"source": "my-templates",
"version": "1.0.0",
"created": "2025-01-01T00:00:00.000Z",
"context": {
"projectName": "my-project",
"description": "My awesome project",
"license": "MIT"
},
"synced": {
"LICENSE": "a1b2c3d4e5f6",
".gitignore": "f6e5d4c3b2a1"
}
}Global configuration directory:
projects.json- Registry of all projectssources.json- Template source configurationsources/- Cloned git template sources
MIT