Writing Commands

Learn to write YAML command files โ€” steps, conditionals, actions, and more.

Command Basics

Commands are YAML files in your .project/ directory. The filename determines the command name.

File Naming: setup.yaml becomes ./project setup

Minimal Command

.project/hello.yaml
# .project/hello.yaml
help:
  short: Say hello

steps:
  - echo: "Hello, World!"

Complete Structure

.project/command-name.yaml
help:
  short: One-line description
  long: |
    Multi-line detailed description.
    Explain usage, options, and examples.
  order: 10

context: outside-container

steps:
  - echo: "Starting..."
  - run: "npm install"
  - echo: "โœ“ Complete"

Help Metadata

The help section defines how your command appears in listings and when users run --help.

Order Guidelines

1โ€“10: Setup

Installation, initialization

11โ€“50: Development

Daily development commands

51โ€“89: Maintenance

Less frequent tasks

90โ€“99: Cleanup

Teardown, removal

Documenting Options

.project/deploy.yaml
help:
  short: Deploy the application
  long: |
    Deploy the application to specified environment.

    Options:
      --production  Deploy to production
      --staging     Deploy to staging
      --dry-run     Show what would happen
  order: 90

Conditional Logic

Option-Based Conditionals

command.yaml
steps:
  - echo: "Building..."

  - if-option: production
    then:
      - echo: "Production build"
      - run: "npm run build:prod"

  - if-no-option: production
    then:
      - echo: "Development build"
      - run: "npm run build:dev"

OR Logic

Use pipe (|) to check multiple options:

command.yaml
steps:
  - if-option: debug|trace|verbose
    then:
      - echo: "Detailed logging enabled"
      - run: "export DEBUG=*"

File-Based Conditionals

command.yaml
steps:
  - if-missing: node_modules
    then:
      - echo: "Installing dependencies..."
      - run: "npm install"

  - if-missing: .env
    then:
      - run: "cp .env.example .env"
      - echo: "โš ๏ธ  Please configure .env"

Nested Conditionals

command.yaml
steps:
  - if-option: production
    then:
      - echo: "Production deployment"

      - if-missing: dist
        then:
          - echo: "Building first..."
          - command: build

      - run: "./deploy.sh production"

Command Options

Users pass options with --flag syntax:

terminal
$ ./project deploy --production --verbose
$ ./project build --watch
$ ./project test --unit --coverage

Example: Test Command

.project/test.yaml
# .project/test.yaml
help:
  short: Run tests
  long: |
    Run the test suite with various options.

    Options:
      --watch      Watch for changes
      --coverage   Generate coverage report
      --unit       Run only unit tests
      --e2e        Run only E2E tests
  order: 30

steps:
  - echo: "๐Ÿงช Running tests..."

  - check-for: npm

  - if-option: unit
    then:
      - run: "npm run test:unit"

  - if-option: e2e
    then:
      - run: "npm run test:e2e"

  - if-no-option: unit|e2e
    then:
      - run: "npm test"

  - if-option: coverage
    then:
      - run: "npm run test:coverage"

  - echo: "โœ… Tests complete"

Docker Workflows

Project Actions has built-in Docker Compose support for container-based development.

Starting Services

.project/up.yaml
# .project/up.yaml
help:
  short: Start the project
  long: |
    Start all services using docker-compose.

    Options:
      --fresh    Reset database and run migrations
      --build    Rebuild images before starting
  order: 10

context: outside-container

steps:
  - check-for: docker
    if-missing: "Install Docker from https://docker.com"

  - if-option: build
    then:
      - echo: "Building images..."
      - run: "docker-compose build"

  - action: compose-up

  - echo: "โณ Waiting for services..."
  - run: "sleep 3"

  - if-option: fresh
    then:
      - action: compose-exec
        service: web
        command: "php artisan migrate:fresh"
        interactive: false

  - echo: |
      โœ… Project is up!
      โ†’ Web: http://localhost:8000

Interactive Shell

.project/console.yaml
# .project/console.yaml
help:
  short: Open shell in web container
  order: 50

context: outside-container

steps:
  - action: compose-exec
    service: web
    command: /bin/bash
    interactive: true

Stopping Services

.project/down.yaml
# .project/down.yaml
help:
  short: Stop the project
  order: 99

context: outside-container

steps:
  - action: compose-down
    volumes: false

  - echo: "โœ“ Project stopped"

Pass-Through Script Runner

Combine <args> interpolation with context: inside-container:<service> to create a general-purpose script runner that automatically routes through docker-compose exec when called from outside the container.

.project/commands/run.yaml
help:
  short: Run a script or binary inside the web container
  order: 10

context: inside-container:web

steps:
  - run: <args>

With this command in place, ./project run artisan migrate runs docker-compose exec web sh -c "artisan migrate" from the host, or runs artisan migrate directly when already inside the container. Add it with ./project init docker.


Best Practices

Always Provide Help

Clear descriptions help team members understand what commands do.

command.yaml
help:
  short: Clear one-liner
  long: Detailed explanation with options

Check Prerequisites

Fail fast with helpful messages.

command.yaml
steps:
  - check-for: docker
    if-missing: "Install Docker first"

Provide Feedback

Let users know what's happening.

command.yaml
steps:
  - echo: "๐Ÿš€ Starting deployment..."
  - run: "./deploy.sh"
  - echo: "โœ… Deployment complete!"

Handle Missing Dependencies

Auto-install when possible.

command.yaml
steps:
  - if-missing: node_modules
    then:
      - echo: "Installing..."
      - run: "npm install"

Don't Hardcode Paths

Use relative paths and environment variables.

Don't Skip Error Handling

Always check for required tools and files.


Complete Examples

Setup Command

.project/setup.yaml
# .project/setup.yaml
help:
  short: Setup the project
  long: |
    Initialize the project for local development.
    Checks dependencies, creates config files, and starts services.
  order: 1

context: outside-container

steps:
  - echo: "๐Ÿš€ Setting up project..."

  - check-for: docker
    if-missing: "Install Docker from https://docker.com"

  - check-for: node
    if-missing: "Install Node.js from https://nodejs.org"

  - if-missing: .env
    then:
      - run: "cp .env.example .env"
      - echo: "โš ๏ธ  Please configure .env"

  - if-missing: node_modules
    then:
      - echo: "Installing dependencies..."
      - run: "npm install"

  - command: up

  - echo: |
      โœ… Setup complete!

      Next steps:
        1. Configure .env with your settings
        2. Run: ./project migrate
        3. Visit: http://localhost:8000

Deployment Command

.project/deploy.yaml
# .project/deploy.yaml
help:
  short: Deploy the application
  long: |
    Deploy to specified environment.

    Options:
      --production  Deploy to production (requires confirmation)
      --staging     Deploy to staging
      --dry-run     Show what would be deployed
  order: 90

steps:
  - echo: "๐Ÿš€ Starting deployment..."

  - check-for: git
  - check-for: docker

  - if-no-option: staging|production
    then:
      - echo: "โŒ Error: Specify --staging or --production"

  - if-option: staging
    then:
      - echo: "Deploying to STAGING"
      - run: "git pull origin staging"
      - run: "./deploy-staging.sh"

  - if-option: production
    then:
      - echo: "โš ๏ธ  PRODUCTION DEPLOYMENT"
      - run: "git pull origin main"
      - run: "./deploy-production.sh"

  - if-no-option: dry-run
    then:
      - echo: "โœ… Deployment complete!"

Learn More

Examples

Reference