{
  "slug": "pilot/executors",
  "title": "Executors",
  "description": "Pilot executor reference — Browser, Terraform, Git, Store, Shell, HTTP, and Composite.",
  "url": "https://cuitty.com/docs/pilot/executors",
  "markdown_url": "https://cuitty.com/docs/pilot/executors.md",
  "json_url": "https://cuitty.com/docs/pilot/executors.json",
  "frontmatter": {
    "title": "Executors",
    "description": "Pilot executor reference — Browser, Terraform, Git, Store, Shell, HTTP, and Composite.",
    "order": 3,
    "section": "Pilot",
    "updatedAt": "2026-06-01"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "executors",
      "text": "Executors"
    },
    {
      "depth": 2,
      "slug": "browser-default",
      "text": "Browser (default)"
    },
    {
      "depth": 3,
      "slug": "configuration",
      "text": "Configuration"
    },
    {
      "depth": 2,
      "slug": "terraform",
      "text": "Terraform"
    },
    {
      "depth": 3,
      "slug": "configuration-1",
      "text": "Configuration"
    },
    {
      "depth": 2,
      "slug": "git",
      "text": "Git"
    },
    {
      "depth": 3,
      "slug": "configuration-2",
      "text": "Configuration"
    },
    {
      "depth": 2,
      "slug": "store",
      "text": "Store"
    },
    {
      "depth": 3,
      "slug": "configuration-3",
      "text": "Configuration"
    },
    {
      "depth": 2,
      "slug": "shell",
      "text": "Shell"
    },
    {
      "depth": 3,
      "slug": "configuration-4",
      "text": "Configuration"
    },
    {
      "depth": 2,
      "slug": "http",
      "text": "HTTP"
    },
    {
      "depth": 3,
      "slug": "configuration-5",
      "text": "Configuration"
    },
    {
      "depth": 2,
      "slug": "composite",
      "text": "Composite"
    },
    {
      "depth": 3,
      "slug": "example-conditional--parallel",
      "text": "Example: Conditional + parallel"
    },
    {
      "depth": 2,
      "slug": "see-also",
      "text": "See also"
    }
  ],
  "body_markdown": "# Executors\n\nPilot routes each playbook step to an **executor** based on the step's `executor` field or its action prefix. The executor registry resolves the target executor in this order:\n\n1. Explicit `executor` field on the step\n2. Action prefix inference (`tf_` -> terraform, `git_` -> git, etc.)\n3. Default: `browser`\n\n## Browser (default)\n\nThe browser executor drives a Playwright browser instance. It handles all 14 built-in actions: `navigate`, `click`, `fill`, `select`, `set_toggle`, `wait_for`, `assert`, `capture`, `capture_secret`, `ai_decide`, `scroll`, `hover`, `press`, `upload`.\n\nWhen `ai_fallback: true`, a failing selector triggers the AI healing engine, which compares the stored DOM snapshot to the current page and proposes a replacement selector.\n\n### Configuration\n\nNo explicit configuration required. The browser executor starts automatically.\n\n| Env var | Purpose | Default |\n|---------|---------|---------|\n| `CUITTY_AI_KEY` | AI model key for selector healing | (local model) |\n\n## Terraform\n\nWraps the Architect API for infrastructure provisioning. Steps are prefixed with `tf_`.\n\n| Action | Description | Key fields |\n|--------|-------------|------------|\n| `tf_init` | Create or ensure a target | `target_id`, `provider`, `kind` |\n| `tf_validate` | Validate target config | `target_id`, `resource_types` |\n| `tf_plan` | Generate a runtime plan | `target_id`, `resource_types` |\n| `tf_apply` | Apply runtime state | `target_id`, `resource_types` |\n| `tf_destroy` | Destroy runtime resources | `target_id`, `resource_types` |\n| `tf_output` | Read a specific output value | `target_id`, `output_name` |\n| `tf_import` | Import an existing resource | `target_id`, `resource_type`, `resource_id` |\n| `tf_state` | Read full runtime state | `target_id` |\n\nAll Terraform steps accept an optional `capture_as` field and `allow_remote` boolean.\n\n### Configuration\n\n| Env var | Purpose | Default |\n|---------|---------|---------|\n| `PILOT_ARCHITECT_URL` | Architect API base URL | `http://localhost:4470` |\n| `PILOT_EXECUTOR_TERRAFORM` | Enable/disable | `true` |\n\n## Git\n\nWraps the Code API for repository and pull request operations. Steps are prefixed with `git_`.\n\n| Action | Description | Key fields |\n|--------|-------------|------------|\n| `git_clone` | Create a repository | `name`, `visibility`, `auto_init` |\n| `git_branch` | Create a branch | `owner`, `repo`, `name`, `sha` |\n| `git_commit` | Create a commit | `owner`, `repo`, `message` |\n| `git_push` | Push a branch | `owner`, `repo`, `branch` |\n| `git_pr_create` | Open a pull request | `owner`, `repo`, `title`, `head`, `base` |\n| `git_pr_merge` | Merge a pull request | `owner`, `repo`, `number`, `strategy` |\n| `git_tag` | Create a tag | `owner`, `repo`, `tag_name`, `name` |\n| `git_release` | Create a release | `owner`, `repo`, `tag_name`, `name`, `body` |\n\nMerge strategies: `merge`, `squash`, `rebase`, `fast_forward`.\n\n### Configuration\n\n| Env var | Purpose | Default |\n|---------|---------|---------|\n| `PILOT_CODE_URL` | Code API base URL | `http://localhost:4351` |\n| `PILOT_EXECUTOR_GIT` | Enable/disable | `true` |\n\n## Store\n\nWraps the Store API for storage provisioning and data management. During the migration window, Pilot still accepts the legacy `persist_` action prefix.\n\n| Action | Description | Key fields |\n|--------|-------------|------------|\n| `persist_provision` | Provision storage stores | `profile`, `stores` |\n| `persist_migrate` | Run database migrations | `dry_run` |\n| `persist_sync` | Sync data between stores | |\n| `persist_backup` | Create a backup | |\n| `persist_restore` | Restore from backup | `archive_path` |\n| `persist_proxy_start` | Start the proxy | |\n| `persist_proxy_stop` | Stop the proxy | |\n\n### Configuration\n\n| Env var | Purpose | Default |\n|---------|---------|---------|\n| `PILOT_PERSIST_URL` | Legacy Store API base URL variable | `http://localhost:4290` |\n| `PILOT_EXECUTOR_PERSIST` | Enable/disable legacy `persist_` actions | `true` |\n\n## Shell\n\nExecutes shell commands with an allowlist for security. Steps are prefixed with `shell_`.\n\n| Action | Description | Key fields |\n|--------|-------------|------------|\n| `shell_exec` | Run a single command | `command`, `args`, `env` |\n| `shell_script` | Run a multi-line script | `command` |\n| `shell_assert` | Run a command and assert output | `command`, `assert` |\n\nShell assertions support: `exit_code`, `stdout_contains`, `stderr_empty`.\n\n### Configuration\n\n| Env var | Purpose | Default |\n|---------|---------|---------|\n| `PILOT_EXECUTOR_SHELL` | Enable/disable | `false` (disabled by default) |\n\nThe shell executor uses an `allowedCommands` allowlist in `executor_config`:\n\n```yaml\nexecutor_config:\n  shell:\n    allowedCommands: [\"curl\", \"dig\", \"nslookup\", \"jq\"]\n    timeout: 30000\n```\n\n## HTTP\n\nMakes API requests, polls endpoints, and asserts response contents. Steps are prefixed with `http_`.\n\n| Action | Description | Key fields |\n|--------|-------------|------------|\n| `http_request` | Send an HTTP request | `url`, `method`, `headers`, `body` |\n| `http_assert` | Request + assert response | `url`, `assert` |\n| `http_poll` | Poll until condition met | `url`, `until`, `interval`, `max_attempts` |\n\nHTTP assertions support: `status`, `body_contains`, `header`.\n\n### Configuration\n\n| Env var | Purpose | Default |\n|---------|---------|---------|\n| `PILOT_EXECUTOR_HTTP` | Enable/disable | `true` |\n\nThe HTTP executor supports an `allowedHosts` restriction in `executor_config`:\n\n```yaml\nexecutor_config:\n  http:\n    allowedHosts: [\"api.cloudflare.com\", \"api.github.com\"]\n    timeout: 30000\n```\n\n## Composite\n\nThe composite executor orchestrates other steps. It supports four meta-actions:\n\n| Action | Description | Key fields |\n|--------|-------------|------------|\n| `run_playbook` | Execute another playbook inline | `playbook`, `inputs` |\n| `parallel` | Run step branches concurrently | `branches` |\n| `conditional` | Execute steps if condition is true | `condition`, `then` |\n| `loop` | Repeat steps until condition or max iterations | `until`, `max_iterations`, `steps` |\n\nConditions use the syntax `captures.key == value`, `captures.key != value`, or `captures.key` (truthy check).\n\n### Example: Conditional + parallel\n\n```yaml\nsteps:\n  - id: check-provider\n    action: conditional\n    executor: composite\n    condition: \"captures.provider == cloudflare\"\n    then:\n      - id: setup-dns\n        action: run_playbook\n        playbook: cloudflare.dns.add-a-record\n        inputs:\n          zone: \"{{zone}}\"\n          record_name: \"{{subdomain}}\"\n          ip_address: \"{{ip}}\"\n  - id: deploy-both\n    action: parallel\n    executor: composite\n    branches:\n      - steps:\n          - id: provision-storage\n            action: persist_provision\n            profile: production\n      - steps:\n          - id: apply-infra\n            action: tf_apply\n            target_id: \"{{target}}\"\n            resource_types: [\"aws_s3_bucket\"]\n```\n\n## See also\n\n- [Playbook reference](/docs/pilot/playbook-reference) — full YAML schema\n- [JavaScript SDK](/docs/pilot/sdk/javascript) — run playbooks programmatically\n- [Quickstart](/docs/pilot/quickstart) — record and replay your first workflow",
  "links_out": [
    "/docs/pilot/playbook-reference",
    "/docs/pilot/sdk/javascript",
    "/docs/pilot/quickstart"
  ]
}