Reason
Maintaining a simple JSON file with all the available tasks allows for easy customization of deployment, release, cleaning, and other project-specific actions. This ensures that everyone on the team can use, edit, and add tasks on a project level.
Quick look
Drop a .robin.json in your project:
Then run any task by name:
That's it. Read on for templates, variables, sequences, and more.
Features
- Define and run project-specific scripts via
.robin.json - Support for both single commands and command sequences
- Interactive mode with fuzzy search
- List all available commands
- Add new commands easily
- Cross-platform support
- Template initialization for different project types
- Variable substitution with default values
- Enum validation for variables
- Environment variable substitution with defaults (
${VAR:-default}) - Automatic
.envfile loading - Optional per-task descriptions (shown in
--listand interactive mode) - Reference other tasks from a sequence with
@task - Optional desktop notification on completion with
--notify
Installation
# From crates.io
# From source
Usage
Initialize a new project
This creates a .robin.json file in your current directory with some template scripts.
Using templates
# Initialize with a specific template
Each template comes with a curated set of useful commands for that specific platform or framework. For example:
- Android: Gradle commands, testing, linting (ktlint), and deployment
- iOS: Xcode build, CocoaPods, testing, SwiftLint, and Fastlane commands
- Flutter: Build, test, dependency management, and platform-specific commands
- Rails: Server, console, database tasks, testing, and code generation
- Node.js: Development, testing (Jest), TypeScript, linting (ESLint), and formatting (Prettier)
- Python: Virtual env, testing (pytest), linting (flake8), formatting (black), and type checking (mypy)
- Rust: Cargo commands for building, testing, linting (clippy), formatting, and documentation
- Go: Build, test, linting (golangci-lint), formatting, and dependency management
If a .robin.json file already exists, you'll be prompted to confirm before overriding it.
List all commands
Interactive mode
Add a new command
Remove or rename a command
Run a command
Robin looks for .robin.json in the current directory and walks up the parent
directories until it finds one — so you can run commands from anywhere inside
your project, just like git or cargo. (robin init always writes to the
current directory.)
Preview a command with --dry-run
Prints the fully-resolved commands — with @task references expanded and all
variables substituted — without executing anything. The flag works before or
after the task name.
Run a task in another directory with --cwd
Runs the task's commands in the given directory instead of the current one —
handy in monorepos where a root-level task should act on a subproject. Like the
other flags, it also accepts the --cwd=DIR form after the task name.
Get notified when a task finishes with --notify
Sends a desktop notification when the task completes, reporting success or
failure along with the total execution time — useful for long-running builds or
deployments you don't want to babysit. Like the other flags, it works before or
after the task name. Notifications are off by default and only fire when
--notify is passed.
Configuration
The .robin.json file supports both single commands and command sequences:
When using command sequences (arrays):
- Commands are executed in order
- Each command is echoed (prefixed with
▶) as it runs, so you can follow along - If any command fails, the sequence stops
- Environment variables and working directory are preserved between commands
- With
--notify, a desktop notification reports the total execution time when the sequence finishes
Task descriptions
Any task can carry a description by switching to the object form. The command
itself goes under cmd (a string or an array), and desc is shown in
robin --list and the interactive picker:
The plain string and array forms keep working — descriptions are entirely
optional. To add the desc scaffolding to every task in an existing file, run:
This rewrites .robin.json so each task uses the { "cmd": ..., "desc": "" }
form, ready for you to fill in the descriptions.
Referencing other tasks
Inside a command sequence, an entry that starts with @ runs another task by
name instead of a shell command. References are expanded recursively, so tasks
compose without duplication:
Running robin ship executes clean, then build, then the deploy step.
Reference cycles are detected and reported as an error.
Editor autocomplete (JSON Schema)
A JSON Schema for .robin.json is published at:
https://raw.githubusercontent.com/cesarferreira/robin/refs/heads/main/schema/robin.schema.json
robin init and robin migrate add a $schema key pointing at it, so editors
like VS Code offer autocomplete and validation out of the box. You can also add
it to any existing file yourself:
The $schema key is preserved when robin rewrites the file (via add,
remove, rename, or migrate).
External Configuration
Robin supports including external configuration files, which is particularly useful for monorepos or sharing common scripts across projects:
Monorepo Example
Here's a typical monorepo structure using shared scripts:
monorepo/
├── common/
│ └── robin.base.json # Shared scripts for all projects
├── frontend/
│ ├── .robin.json # Frontend-specific scripts
│ └── package.json
├── backend/
│ ├── .robin.json # Backend-specific scripts
│ └── package.json
└── mobile/
├── .robin.json # Mobile-specific scripts
└── pubspec.yaml
common/robin.base.json:
frontend/.robin.json:
mobile/.robin.json:
Scripts from included files are merged with local scripts, where local scripts take precedence. This allows you to:
- Share common development workflows across projects
- Maintain consistent CI/CD scripts
- Override shared scripts when needed
- Keep project-specific scripts separate from shared ones
Variable Substitution
Basic Variables
Use {{variable}} in your scripts and pass them as --variable=XXX when running the command:
Then run:
Default Values
You can specify default values for variables using {{variable=default}} syntax:
Using default values:
# Override defaults:
Enum Validation
You can restrict variable values to a specific set using {{variable=[value1, value2, ...]}} syntax:
Using enum validation:
# Simple validation
# Build modes
# Multiple validations
--env=staging \
--track=beta
Variables work in both single commands and command sequences:
Environment Variables with Defaults
In addition to the {{...}} syntax (which reads from --variable= arguments), you can
read values from the environment using Docker Compose-style ${VAR:-default} syntax:
PORT=9000
Two forms are supported (defaults only):
| Syntax | Behavior |
|---|---|
${VAR:-default} |
Use $VAR if it is set and non-empty, otherwise default. |
${VAR-default} |
Use $VAR if it is set (even if empty), otherwise default. |
A bare ${VAR} (with no default) is left untouched and expanded by the shell at run
time, exactly as before.
.env files
If a .env file sits next to your .robin.json, robin loads it automatically
before running a task, so both the ${VAR:-default} substitution above and your
shell commands can use those values:
# .env (next to .robin.json)
PORT=9000
NAMESPACE=production
Variables already present in the environment take precedence over the file, and
loading can be disabled by setting ROBIN_NO_DOTENV.
Development Environment
Doctor Command
The doctor command helps verify your development environment is properly set up:
This will check:
- 📦 Required Tools
- Cargo and Rust
- Ruby and Fastlane
- Flutter
- Node.js and npm
- 🔧 Environment Variables
- ANDROID_HOME
- JAVA_HOME
- FLUTTER_ROOT
- 📱 Platform Tools
- Android Debug Bridge (adb)
- Xcode Command Line Tools
- CocoaPods
- 🔐 Git Configuration
- user.name
- user.email
Example output:
)
Update Development Tools
To update all development tools to their latest versions:
This will update:
- Rust (via rustup)
- Flutter
- Fastlane (via gem)
- Global npm packages
- CocoaPods repositories
Update Notifications
Robin checks crates.io for newer releases and prints a short notice when your installed version is out of date:
➜ A new version of robin is available: 1.5.0 (you have 1.0.2).
Update with: cargo install robin_cli_tool
The check is throttled to at most once per day (the result is cached under your
OS cache directory), so it never slows down day-to-day usage. To disable it
entirely, set the ROBIN_NO_UPDATE_CHECK environment variable.
License
MIT © Cesar Ferreira