Introduction
curo: /ˈkuː.roː/, [ˈkuːroː]
- to arrange, see to, attend to, take care of, look after, ensure, tend to
- to heal, cure
- to govern, command, preside over
curo is a command-line tool for managing development environments, both on local machines as well as inside CI/CD systems. It provides a set of standard build, test, and management commands ("verbs"), such as build, test, and deploy, so you don’t need to invent your own script names or targets. Think of curo as similar to tools like Make, Just and Please, but with hints of what build tools like Bazel, Pants and all have also created through the years.
The main takeaway of curo is that it does not force a particular toolchain for the language(s) you are developing in. You set up the environment, but once you have, curo is there to make sense of the separate parts.
Why would I use curo?
There are many tools that exist to run commands and structure codebases. The philosophy behind curo is to standardize the language used when building code projectsand to reduce complexity in managing different environments.
Key Benefits
- Consistent Commands: Everyone on your team runs
curo build,curo test, etc.—no more “what do I run here?”. - Portable Configuration: All logic lives in a single
curo.tomlfile, alongside your code. And you see what the actual commands are. - No Language Lock-in: You aren’t tied to any specific toolchain; you define how commands run.
- Smooth for CI/CD: The same commands work in dev and CI without extra glue scripts.
# Build all components
curo build
# Run unit tests
curo test
# Deploy your project
curo deploy
Project configuration (in curo.toml):
[dev]
build = "go build -o bin/myapp ."
test = "go test ./..."
Installation
Run the following command in your terminal:
curl -sfL "https://gitlab.com/scottlindeman/public/-/raw/main/01_projects/curo/install" | bash
This will install the latest curo version. If you want a specific version, use the following bash syntax
bash -s -- -v "0.93.0"
Additionally, the script will install curo into /usr/local/bin. If another directory is preferable, use the following bash syntax
bash -s -- -i "~/bin"
Example:
curl -sfL "https://gitlab.com/scottlindeman/public/-/raw/main/01_projects/curo/install" | bash -s -- -v "0.93.0" -i "/usr/local/bin"
This will install the curo binary to /usr/local/bin.
Usage
Once installed, curo provides a simple, unified CLI for common development workflow tasks. Typical commands are:
curo build # Build your project or component(s)
curo test # Run tests
curo deploy # Deploy built artifacts
You can always see the available commands by running:
curo --help
Common Workflow
-
Install project dependencies
curo install -
Build the project
curo build -
Run tests
curo test -
Start your project
curo start
Command Structure
Most commands follow this structure:
curo [options] <command> [command-options] [component ...]
options: Usecuro --helpto see all available flags (e.g.--env,--all,--exclude, etc.).<command>: One of the standard verbs such asbuild,test,lint, etc.command-options: Options for the specific command, such as passing arguments or chaining commands[component ...]: Optionally target specific components.
Examples
Build a specific component:
curo build cli
Run in CI/CD environment:
curo build --env cicd
Chaining Commands
You can chain commands:
curo format --and lint --and build --and test
Supplying Extra Arguments
Some commands accept extra arguments:
curo lint -D "--lang py" python_project
Configuration
curo uses a curo.toml file at the root of your repository to define your project settings and the commands available for each environment.
Below is an example curo.toml that covers common scenarios:
curo_toml_version = "0.60.0"
[about]
name = "cli"
version = "{{ inherit }}"
description = "A command line tool for building projects."
code_dir = "."
[dev]
build = [
"mkdir -p build-output",
"go build -v -o build-output/testcuro"
]
deploy = "cp build-output/testcuro $REPO_BIN/testcuro"
generate = [ "argbash -i .curo/actions/cicd.build.sh" ]
[dev.test]
unit = "go test -v -run TestUnit curo curo/common curo/commands/actions curo/commands/general curo/tui curo/core"
integration = "go test -v -run TestIntegration curo curo/common curo/commands/actions curo/commands/general curo/tui curo/core"
functional = "poetry run py.test -vvvv tests/functional {{ args }}"
Sections
curo_toml_version: Specifies the version of the configuration format.[about]: Basic information about the project.name: Project name.version: Project version (use"{{ inherit }}"to match the main version).description: Short description.code_dir: Root code directory.
[dev]: Commands for the development environment.build: List or string of shell commands to build your project.deploy: How to deploy built artifacts locally.generate: Example of code generation or scripts.
[dev.test]: Defines test categories.unit: Unit test command(s).integration: Integration test command(s).functional: Functional test command(s).
Editing & Extending
- Add or update commands for other project verbs supported by
curo, such aslint,format, etc. - You can use arrays for multi-step shell scripts or strings for single-step commands.
- Environment variables and command-line arguments are supported (see Advanced Usage).
Tip: Don’t forget to run curo init > curo.toml to generate a starter file! You can also give your curo.toml files prefixes, such as myproject.curo.toml
Example
Suppose your project has this structure:
src
├── backend
│ ├── database
│ └── server
└── frontend
├── lib
└── ui
Each bottom-level component (ui, lib, server, database) can be started on its own.
1. Initialize the Project
From your repo root, run:
curo init > curo.toml
This generates a curo.toml` in your root directory.
2. Top-level curo.toml
Open the root curo.toml. For this layout:
curo_toml_version = "0.93.0"
[about]
name = "node-monorepo"
description = "Full-stack monorepo with Node.js frontend/backend and PostgreSQL database"
code_dir = "src"
[dev]
format = "prettier --write ."
lint = "eslint ."
components = ["frontend", "backend"]
code_dir = "src"tells curo all code lives insrc/.componentslists first-level folders insrc/.
3. src/frontend/curo.toml
Create src/frontend/curo.toml with curo init:
curo_toml_version = "0.93.0"
[about]
name = "frontend"
code_dir = "."
components = ["ui", "lib"]
4. src/backend/curo.toml
In src/backend/curo.toml:
curo_toml_version = "0.93.0"
[about]
name = "backend"
code_dir = "."
components = ["server", "database"]
5. Bottom-level curo.tomls
For src/frontend/ui/curo.toml:
curo_toml_version = "0.93.0"
[about]
name = "ui"
code_dir = "."
[dev]
install = "npm install"
start = "npm run start"
For src/frontend/lib/curo.toml:
curo_toml_version = "0.93.0"
[about]
name = "lib"
code_dir = "."
[dev]
install = "npm install"
build = "npm run build"
For src/backend/server/curo.toml:
curo_toml_version = "0.93.0"
[about]
name = "server"
code_dir = "."
[dev]
install = "npm install"
start = "npm run start"
For src/backend/database/curo.toml:
curo_toml_version = "0.93.0"
[about]
name = "database"
code_dir = "."
[dev]
start = "docker-compose up db"
6. Example Usage
- Install everything:
curo install - Format all code:
curo format - Lint all code:
curo lint - Start just the server:
curo start backend server - Start the UI:
curo start frontend ui - Start only the database:
curo start backend database - Start everything:
curo start
Advanced Usage
Curo provides powerful options and flags to help you target, customize, and compose complex workflows:
Commands
Passing Arguments to Commands (-D)
Use -D (--args) to pass additional arguments to a component’s command.
Note: Can only be used with one component at a time.
curo lint -D "--fix" frontend ui
This passes --fix to the lint command when running on the frontend ui component.
Running Top-Level (Global) Commands for a Component (-g, --global)
Use -g/--global to apply the top-level definition of a command to a specific component (even if that component has its own command).
curo --global lint frontend ui
This forces the top-level lint command (from the repo root) to run for frontend ui, instead of any lint command defined in that component’s own curo.toml.
Running Local Commands from a Component Directory (-l, --local)
If you’re inside a component’s folder, use -l to run its commands without typing the full path.
cd src/frontend/ui
curo -l start
This will run the start command for the frontend ui component.
Selecting the Environment (-e, --env)
You can specify which environment’s commands to run. The default is dev
curo -e cicd deploy
Runs the deploy command for the cicd environment (e.g., for CI/CD purposes).
Running Specific Test Types
If you have multiple test commands, you can specify which to run.
curo test unit backend server
curo test functional frontend ui
This will only run the specified type of tests (e.g., unit, functional) for that component. Without specifying the level of testing, the default is to run all defined levels.
Excluding Components (-x, --exclude)
Skip specific components or subcomponents.
curo build -x "frontend lib"
This will build everything except frontend lib.
Running a Command for All Components (-a, --all)
By default, top-level commands shadow component commands. Use -a to run the specified command for every component that defines it.
curo -a install
Runs install for every component with its own install command (not just the top-level).
General
Navigation
You can use curo find [component] to help navigate through your project. The find command will produce an absolute path to the referenced component.
cd $(curo find frontend lib)
cd $(curo find /) # To go back to the project root
Info
You can view your project structure by running curo info. Add, -v or more vs to see more information.
curo info
public
├── shdx
│ ├── shdx
│ └── installer
├── pydx
├── shaddo
│ ├── cli
│ └── installer
├── curo
│ ├── cli
│ ├── installer
│ └── docs
├── nenya
├── ansible-runner
├── browser-plugins
│ ├── farc
│ ├── confluence
│ ├── gitlub
│ └── productivity
└── cicd-runtime
curo -vv info
public [A collection of open source tools and libraries.]
├── dev
│ ├── install
│ ├── format
│ ├── lint
│ └── generate
├── cicd
│ ├── install
├── shdx
│ ├── shdx
│ │ ├── dev
│ │ │ ├── build
│ │ │ └── generate
│ │ └── cicd
│ │ ├── build
│ │ └── publish
│ └── installer [0.87.0 - A convenient installer to pull a release version …]
│ ├── dev
│ │ ├── build
│ │ ├── generate
│ │ └── run
│ └── cicd
│ ├── build
│ └── publish
├── pydx [A collection of libraries for python that are hel…]
│ └── dev
│ └── test
│ └── unit
├── shaddo [0.5.2 - A cli tool to bundle shell and bash scripts into …]
│ ├── cli [0.5.2 - The actual cli tool]
│ │ ├── dev
│ │ │ ├── build
│ │ │ ├── generate
│ │ │ ├── test
│ │ │ │ └── functional
│ │ │ └── deploy
│ │ └── cicd
│ │ ├── build
│ │ └── publish
│ └── installer [0.5.2 - A convenient installer to pull a release bin of s…]
│ ├── dev
│ │ ├── build
│ │ ├── generate
│ │ └── run
│ └── cicd
│ ├── build
│ └── publish
├── curo [1.0.0 - A command line tool for building projects.]
│ ├── cli [1.0.0 - A command line tool for building projects.]
│ │ ├── dev
│ │ │ ├── build
│ │ │ ├── generate
│ │ │ ├── test
│ │ │ │ ├── unit
│ │ │ │ ├── integration
│ │ │ │ └── functional
│ │ │ └── deploy
│ │ └── cicd
│ │ ├── build
│ │ └── publish
│ ├── installer [1.0.0 - A convenient installer to pull a release bin of c…]
│ │ ├── dev
│ │ │ ├── build
│ │ │ ├── generate
│ │ │ └── run
│ │ └── cicd
│ │ ├── build
│ │ └── publish
│ └── docs [1.0.0 - The documentation website for CURO]
│ ├── dev
│ │ ├── build
│ │ └── run
│ └── cicd
│ ├── build
│ └── deploy
├── nenya [0.44.0 - A js library that enhances mithriljs.]
│ ├── dev
│ │ ├── install
│ │ ├── build
│ │ └── test
│ │ └── unit
│ └── cicd
│ └── build
├── ansible-runner [1.1.0 - A Dockerfile for an image that has a very easy in…]
│ ├── dev
│ │ ├── build
│ │ └── run
│ └── cicd
│ ├── build
│ └── publish
├── browser-plugins [Plugins for browsers, mostly Firefox.]
│ ├── farc [0.2.0 - A browser experience inspired by Arc.]
│ │ ├── dev
│ │ │ ├── build
│ │ │ └── test
│ │ │ └── unit
│ │ └── cicd
│ │ └── build
│ ├── confluence [2.1.0 - Make Confluence look nice.]
│ │ └── cicd
│ │ └── build
│ ├── gitlub [2.1.0 - Style Github and Gitlab readmes and code.]
│ │ └── cicd
│ │ └── build
│ └── productivity [1.2.1 - Removes some unproductive things from websites]
│ └── cicd
│ └── build
└── cicd-runtime [1.2.0 - The image used by the public cicd pipelines for b…]
├── dev
│ ├── build
│ └── run
└── cicd
├── build
└── publish
Caveats
While curo aims to provide a simple and flexible command runner for your projects, there are some important caveats and limitations to keep in mind:
One Level of Component Discovery per curo.toml
Each curo.toml only defines components one level deeper. Hierarchies are built by placing separate curo.toml files in subcomponent directories. Curo does not recursively search for components in nested directories unless each has its own config. Curo also has a 3 depth max as well. Root, first component and sub component.
Passing Command Arguments (-D)
- The
-D/--argsflag only works if you specify a single component. It cannot be used with multiple components at once. - These additional arguments are simply appended after the defined command; ensure your component’s script or tool will handle them as expected.
Global and Local Options
- The
--globalflag forces curo to run the top-level command for a specified component, ignoring any local overrides. - The
--localflag only works when you are inside a component’s directory. It cannot be used from outside the project/component subtree.
Component Command Precedence
By default, if both the top-level and the component define a command (like build), curo runs only the top-level version unless you use the -a/--all flag.
Environment Variable Expansion
Curo executes commands via the shell, so environment variables (like $PATH, $PWD, etc.) behave as they do in your shell. However, if your command depends on specific environment setup, make sure it is available via your shell or set in the command explicitly.
Command Chaining
Chaining commands with -n/--and does not support -D/--args.
Environment Switching (-e/--env)
Be sure that your curo.toml files actually define the requested environment (like [cicd]), otherwise you may see errors or no commands executed when using that environment.
Exclusions and Globs
The -x/--exclude flag can be used multiple times, but must exactly match a component path as curo discovers them. Pattern matching or globs are not currently supported.
Cross-Platform Considerations
Curo runs your specified shell commands as-is. If you are working in a cross-platform team (Windows, macOS, Linux), ensure your commands are portable or conditionally written.
Dependency Assumptions
Curo does not manage or install any system or language dependencies for you in your project. That is for you to set up and understand.