yarli 0.4.0

CLI, stream mode renderer, interactive TUI, scheduler, store, and API
Documentation
# CI/CD Integration Examples (YARLI API)

This document provides copy-ready examples for running YARLI from CI systems using the HTTP API.
It includes GitHub Actions, GitLab CI, and Jenkins examples plus wait-for-completion scripts.

## Prerequisites

- `YARLI_API_BASE_URL` points to a live YARLI API (for example `http://127.0.0.1:3000`).
- `jq` and `curl` available in the runner image.
- Optional API token can be sent in `Authorization: Bearer <token>` header.

```bash
export YARLI_API_BASE_URL="http://127.0.0.1:3000"
export YARLI_API_TOKEN="${YARLI_API_TOKEN:-}"
```

Create a helper header for authenticated calls:

```bash
if [ -n "${YARLI_API_TOKEN}" ]; then
  export YARLI_AUTH_HEADER="Authorization: Bearer ${YARLI_API_TOKEN}"
else
  export YARLI_AUTH_HEADER=""
fi
```

## Shared API call examples

### Start a YARLI run

```bash
run_payload="$(mktemp)"
curl -sS -X POST \
  -H "content-type: application/json" \
  ${YARLI_AUTH_HEADER:+-H "$YARLI_AUTH_HEADER"} \
  -d '{"objective":"ci-run","reason":"CI pipeline trigger"}' \
  "${YARLI_API_BASE_URL}/v1/runs" | tee "$run_payload"

run_id="$(jq -r '.run_id' "$run_payload")"
printf 'run_id=%s\n' "$run_id"
```

### Pause / resume / cancel

```bash
curl -sS -X POST \
  -H "content-type: application/json" \
  ${YARLI_AUTH_HEADER:+-H "$YARLI_AUTH_HEADER"} \
  -d '{"reason":"CI maintenance window"}' \
  "${YARLI_API_BASE_URL}/v1/runs/${run_id}/pause"

curl -sS -X POST \
  -H "content-type: application/json" \
  ${YARLI_AUTH_HEADER:+-H "$YARLI_AUTH_HEADER"} \
  -d '{"reason":"CI resume"}' \
  "${YARLI_API_BASE_URL}/v1/runs/${run_id}/resume"

curl -sS -X POST \
  -H "content-type: application/json" \
  ${YARLI_AUTH_HEADER:+-H "$YARLI_AUTH_HEADER"} \
  -d '{"reason":"CI timeout"}' \
  "${YARLI_API_BASE_URL}/v1/runs/${run_id}/cancel"
```

### Poll run status

```bash
curl -sS \
  ${YARLI_AUTH_HEADER:+-H "$YARLI_AUTH_HEADER"} \
  "${YARLI_API_BASE_URL}/v1/runs/${run_id}/status"
```

The status response contains `state` values such as `RunOpen`, `RunActive`, `RunVerifying`,
`RunBlocked`, `RunCompleted`, `RunFailed`, and `RunCancelled`.

## Example script: wait-for-completion

Use this script to block a pipeline until terminal state:

- `RunCompleted`
- `RunFailed`
- `RunCancelled`

Save as `docs/ci/wait-for-completion.sh`.

```bash
#!/usr/bin/env bash
set -euo pipefail

run_id="${1:?run_id required}"
base_url="${YARLI_API_BASE_URL:-http://127.0.0.1:3000}"
auth_header="${YARLI_AUTH_HEADER:-}"
poll_delay="${YARLI_POLL_SECONDS:-5}"
poll_attempts="${YARLI_POLL_ATTEMPTS:-120}"
attempt=0

while ((attempt < poll_attempts)); do
  payload="$(curl -sS \
    ${auth_header:+-H "$auth_header"} \
    "${base_url}/v1/runs/${run_id}/status")"

  state="$(jq -r '.state' <<<"${payload}")"
  updated_at="$(jq -r '.updated_at // "unknown"' <<<"${payload}")"
  echo "run ${run_id} state=${state} at=${updated_at}"

  case "${state}" in
    RunCompleted | RunFailed | RunCancelled)
      echo "run reached terminal state: ${state}"
      exit 0
      ;;
    "")
      echo "empty or invalid status response"
      exit 1
      ;;
  esac

  attempt=$((attempt + 1))
  sleep "${poll_delay}"
done

echo "timed out waiting for terminal state after ${poll_attempts} attempts"
exit 2
```

## GitHub Actions workflow sample

```yaml
name: YARLI run in CI
on:
  workflow_dispatch:

jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable

      - name: Start YARLI API
        run: |
          cargo build -p yarli-api --quiet
          nohup cargo run -p yarli-api -- --listen-addr 127.0.0.1:3000 > yarli-api.log 2>&1 &
          for i in $(seq 1 30); do
            if curl -fsS http://127.0.0.1:3000/health >/dev/null; then
              break
            fi
            sleep 1
          done
        env:
          RUST_LOG: warn

      - name: Trigger run and wait
        env:
          YARLI_API_BASE_URL: http://127.0.0.1:3000
        run: |
          run_payload="$(mktemp)"
          run_id="$(curl -sS -X POST \
            -H 'content-type: application/json' \
            -d '{"objective":"ci-github-actions"}' \
            "${YARLI_API_BASE_URL}/v1/runs" \
            | tee "$run_payload" | jq -r '.run_id')"
          bash docs/ci/wait-for-completion.sh "$run_id"
```

## GitLab CI sample

```yaml
stages:
  - trigger

trigger_yarli:
  image: rust:1.75
  stage: trigger
  script:
    - cargo build -p yarli-api --quiet
    - nohup cargo run -p yarli-api -- --listen-addr 127.0.0.1:3000 > yarli-api.log 2>&1 &
    - |
      for i in $(seq 1 30); do
        curl -fsS http://127.0.0.1:3000/health >/dev/null && break
        sleep 1
      done
    - export YARLI_API_BASE_URL=http://127.0.0.1:3000
    - |
      run_id="$(curl -sS -X POST \
        -H 'content-type: application/json' \
        -d '{"objective":"ci-gitlab"}' \
        "${YARLI_API_BASE_URL}/v1/runs" \
        | jq -r '.run_id')"
    - bash docs/ci/wait-for-completion.sh "$run_id"
```

## Jenkins pipeline sample

```groovy
pipeline {
  agent any
  stages {
    stage('Trigger YARLI') {
      steps {
        sh """
          cargo build -p yarli-api --quiet
          nohup cargo run -p yarli-api -- --listen-addr 127.0.0.1:3000 > yarli-api.log 2>&1 &
          for i in \$(seq 1 30); do
            curl -fsS http://127.0.0.1:3000/health >/dev/null && break || sleep 1
          done
          run_id=\$(curl -sS -X POST -H 'content-type: application/json' \
            -d '{\\\"objective\\\":\\\"ci-jenkins\\\"}' \
            http://127.0.0.1:3000/v1/runs | jq -r '.run_id')
          YARLI_API_BASE_URL=http://127.0.0.1:3000 \
          bash docs/ci/wait-for-completion.sh \"\\${run_id}\"
        """
      }
    }
  }
}
```

## Monitoring and troubleshooting

- Poll `/v1/runs?state=active&limit=50` to observe active work.
- Poll `/v1/audit?run_id=<uuid>` for event-level evidence.
- Poll via websocket endpoint `/v1/events/ws` or consume webhooks via `/v1/webhooks` for async visibility.