> ## Documentation Index
> Fetch the complete documentation index at: https://staplehire.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Use in CI

> Run Staplehire CLI commands in GitHub Actions, GitLab CI, or any pipeline with STAPLEHIRE_KEY and JSON output — no browser login required.

In CI, authenticate with `STAPLEHIRE_KEY` (never browser login), install the CLI, and rely on JSON output with stable [exit codes](/docs/cli-errors) for assertions.

```yaml theme={null}
env:
  STAPLEHIRE_KEY: ${{ secrets.STAPLEHIRE_KEY }}
steps:
  - run: npm install -g @staplehire/staplehire-cli
  - run: staplehire doctor -q
```

<Warning>
  Do not run `staplehire login` in CI — it opens a browser and waits for an interactive callback. Always provide `STAPLEHIRE_KEY` as a secret.
</Warning>

## Set up the key

Create an API key in [Settings → Developers](https://app.staplehire.com/settings/developers) and store it as a CI secret named `STAPLEHIRE_KEY`. Then verify it in the pipeline:

```bash theme={null}
npm install -g @staplehire/staplehire-cli
staplehire doctor -q | jq -e '.ok'
staplehire whoami | jq -r '.organization.id'
```

## CI examples

<Tabs>
  <Tab title="GitHub Actions">
    ```yaml theme={null}
    name: Staplehire CLI

    on:
      workflow_dispatch:

    jobs:
      staplehire:
        runs-on: ubuntu-latest
        env:
          STAPLEHIRE_KEY: ${{ secrets.STAPLEHIRE_KEY }}
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-node@v4
            with:
              node-version: "20"
          - run: npm install -g @staplehire/staplehire-cli
          - run: staplehire doctor -q | jq -e '.ok'
          - name: Create a role
            run: |
              staplehire roles create \
                --jd "On-call SRE for ${GITHUB_REPOSITORY}." \
                | jq -e '.role.id'
    ```
  </Tab>

  <Tab title="GitLab CI">
    ```yaml theme={null}
    staplehire:
      image: node:20
      variables:
        STAPLEHIRE_KEY: $STAPLEHIRE_KEY
      script:
        - npm install -g @staplehire/staplehire-cli
        - staplehire doctor -q | jq -e '.ok'
        - staplehire roles list | jq '.roles[].id'
    ```
  </Tab>

  <Tab title="Plain shell">
    ```bash theme={null}
    #!/usr/bin/env bash
    set -euo pipefail
    export STAPLEHIRE_KEY="${STAPLEHIRE_KEY:?set STAPLEHIRE_KEY}"

    npm install -g @staplehire/staplehire-cli
    staplehire doctor -q | jq -e '.ok'
    ROLE_ID=$(staplehire roles create --jd "Backend engineer…" | jq -er '.role.id')
    echo "Created role $ROLE_ID"
    ```
  </Tab>
</Tabs>

## Environment variables

| Variable             | Description                                              |
| -------------------- | -------------------------------------------------------- |
| `STAPLEHIRE_KEY`     | API key — `sh_live_…` (production) or `sh_test_…` (test) |
| `STAPLEHIRE_API_URL` | Optional API gateway override                            |
| `STAPLEHIRE_APP_URL` | Optional dashboard URL (only affects `login` / `open`)   |

## Clean JSON output

Use `-q` (or pipe stdout) so scripts get JSON without human status lines. `jq -e` makes assertions fail the job when a field is missing.

```bash theme={null}
staplehire doctor -q | jq -e '.ok'
staplehire roles list | jq -e '.roles | length > 0'
```

## Common errors

| Error                 | Exit code | Fix                                                                           |
| --------------------- | --------- | ----------------------------------------------------------------------------- |
| `AuthenticationError` | `2`       | The `STAPLEHIRE_KEY` secret is missing or empty                               |
| `PermissionError`     | `6`       | Key lacks access — create one for the correct organization                    |
| CLI usage             | `8`       | Bad arguments — run `staplehire commands` locally and pass all required flags |

## FAQ

<AccordionGroup>
  <Accordion title="Should CI run `staplehire login`?">
    No. `login` opens a browser. Set `STAPLEHIRE_KEY` as a secret instead.
  </Accordion>

  <Accordion title="`--json` or `-q`?">
    Use `-q` for JSON-only output that also suppresses human status lines. Output is already JSON when stdout is piped, but `-q` guarantees it in any context.
  </Accordion>

  <Accordion title="Can CI create roles and candidates?">
    Yes — if the key has permission and the command includes every required flag.
  </Accordion>
</AccordionGroup>

Related: [Authentication](/docs/authentication) · [Use with AI agents](/docs/ai-agents) · [Command reference](/docs/commands)
