Project Actions lets you define local CLI workflows in YAML, similar to GitHub Actions but for your own project. Users install a ./project script into their project root and run commands like ./project setup or ./project test.
This page is optimized for automated consumers. Full documentation: https://project-actions.org/docs
Run in the project root:
curl -fsSL https://project-actions.org/install.sh | bash
The installer:
After installing, download starter commands for the project framework:
./project init laravel # Laravel PHP
./project init django # Django Python
./project init nextjs # Next.js
./project init rails # Ruby on Rails
./project init node # Generic Node.js
./project init python # Generic Python
./project init docker # Docker Compose (add-on, combine with any framework)
Run without arguments to list all available templates:
./project init
.project/ commands/ <- YAML command files (committed to source control) setup.yaml test.yaml .runtime/ <- runner binary and cache (gitignored) runner.sh command-runner-darwin-arm64 project <- wrapper script (committed to source control)
Each file in .project/commands/ defines one command. Filename becomes the command name.
help: short: Set up the project # shown in ./project command listing long: | # optional, shown with –help Installs dependencies and prepares the environment. order: 1 # controls sort order in ./project listing
steps:
Primitives use shorthand syntax — the YAML key is the step type. Always available, no action: wrapper needed.
Executes a shell command. Fails the step if the command exits non-zero.
- run: npm install
- run: php artisan migrate
@$ interpolation: Replace @$ with all positional CLI arguments.
- run: @$ # ./project run foo bar → foo bar
- run: php @$ # ./project run artisan migrate → php artisan migrate
- run: ./vendor/bin/@$ # ./project run phpunit --filter=FooTest
Error if @$ is present but no arguments given: no arguments given — usage: ./project run <script> [args...]
Context-aware routing: When the command declares context: inside-container:<service>, run: steps route through docker-compose exec <service> sh -c "..." automatically when the runner is outside the container.
# .project/commands/run.yaml
context: inside-container:web
steps:
- run: @$
Usage: ./project run artisan migrate, ./project run composer install
Prints a message to stdout.
- echo: "Dependencies installed"
Checks that a CLI tool is available. Exits with an error message if not found.
- check-for: composer
if-missing: "Composer is required. See https://getcomposer.org"
Runs the nested then: steps only if a file or directory does not exist.
- if-missing: .env
then:
- run: cp .env.example .env
Runs the nested then: steps only if a CLI flag was passed by the user.
- if-option: production
then:
- run: php artisan config:cache
Inverse of if-option – runs steps only when the flag is NOT present.
- if-no-option: skip-tests
then:
- run: php artisan test
Built-in actions are shipped with the runner and invoked via the action: key.
Starts Docker Compose services.
- action: compose-up
- action: compose-up
detached: true
Stops running services without removing containers.
- action: compose-stop
Stops and removes containers. Optionally removes volumes.
- action: compose-down
- action: compose-down
volumes: true
Executes a command inside a running container.
- action: compose-exec
service: web
command: php artisan migrate
- action: compose-exec
service: web
command: bash
interactive: true
./project # list all available commands
./project <name> # run a command by name
./project <name> --help # show full help for a command
./project <name> --<flag> # pass an option flag to a command
./project init # list available starter templates
./project init <name> # download a starter template
./project actions list # list all external action sources in use
A full setup command that checks dependencies, installs, and prepares the environment:
help: short: Set up the project order: 1
steps: