# Run a Met from GitHub Actions

The CLI covers the same API as the SDK, so anything your backend does a CI step can do too.
This recipe runs a Met when something happens in the repository, and makes the pipeline
fail if the task failed.

## Before you start

Store two secrets in the repository (**Settings → Secrets and variables → Actions**):

| secret | what it is |
|---|---|
| `MET_API_KEY` | a `met_live_` key with whatever scopes your step uses |
| `MET_WORKSPACE` | the numeric workspace id |

The CLI reads both environment variables directly, so there's no `met config set` in CI.

## 1. A Met that summarizes what just shipped

```yaml
name: Deploy summary

on:
  push:
    branches: [main]

jobs:
  summarize:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 20

      - run: npm i -g @meteor.ia/cli

      - name: Summarize the pushed commits
        env:
          MET_API_KEY: ${{ secrets.MET_API_KEY }}
          MET_WORKSPACE: ${{ secrets.MET_WORKSPACE }}
        run: |
          COMMITS=$(git log --format='%s' -20)
          met run "Summarize these commits for the support team, in three bullets: $COMMITS" \
            --json --no-stream > output.json
          jq -r '.output' output.json >> "$GITHUB_STEP_SUMMARY"
```

`--json` prints the whole run on one line, ready for `jq`. `--no-stream` is what makes it
usable in CI: without it the CLI paints the answer as it arrives, and what ends up in the
log is fragments rather than parseable JSON.

## 2. A task that can fail the pipeline

`met run` executes a standalone Met. For a procedure with steps — the normal case when the
result matters — use a task, and `--wait` to hold for the final state:

```yaml
      - name: Pre-release review
        env:
          MET_API_KEY: ${{ secrets.MET_API_KEY }}
          MET_WORKSPACE: ${{ secrets.MET_WORKSPACE }}
        run: met tasks run tsk_123 --wait
```

With `--wait`, **the exit code reflects the execution's final state**: if the task fails,
the step fails and the pipeline stops. Without `--wait`, the command fires the execution
and returns immediately with a `0` that only means it started.

One thing to watch: if the task has a step that waits for someone's approval, `--wait`
sits there until a person decides, and in CI that's a job hanging until the timeout. Tasks
that run unattended shouldn't carry human pauses — see
[the approval recipe](recipe-human-approval.html) for when they're worth having.

## 3. A look at what went wrong

Useful as a final step when something failed, or as a scheduled job:

```bash
met runs list --status failed --limit 20
```

## Energy is consumed all the same

A run from CI costs the same as one from your backend, and a workflow that fires on every
push adds up fast. Two things help: use a separate key for CI, and give it a budget —
subscribe to `billing.threshold` and you get a heads-up at 50, 80 and 100% instead of a
surprise. Per-key consumption is in your dashboard under **Developers**.

## Next

- Every command, the configuration and the output formats: [CLI (met)](cli.html).
- To react when the run ends rather than waiting inside the job:
  [receive signed events](recipe-signed-webhooks.html).
