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

# CI with GitHub Actions

> Make a GitHub Actions runner an envlink sandbox, build in a leased box, and clean up afterwards.

A CI runner can be a sandbox like your laptop. It registers for the length of the job, leases what it needs, and deregisters at the end.

## Set up

1. In the console, create a CLI token for CI (**Settings → CLI tokens**).
2. In your repository, add it as an Actions secret named `ENVLINK_TOKEN`.

## Workflow

```yaml .github/workflows/build.yml theme={null}
name: build
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      ENVLINK_API: https://envlink-api.projectinwork.com
      ENVLINK_TOKEN: ${{ secrets.ENVLINK_TOKEN }}
    steps:
      - uses: actions/checkout@v4

      - name: Install envctl
        run: |
          curl -fsSL https://envlink.projectinwork.com/install/install.sh | ENVLINK_INSTALL_DIR="$HOME/.local/bin" sh
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Make this runner a sandbox
        run: envctl sandbox up --name "ci-${{ github.run_id }}"

      - name: Lease a build box
        run: |
          envctl env create linux-build --share src=. --label ci-run=${{ github.run_id }} \
            --snapshot "ci/${{ github.ref_name }}" --restore "ci/${{ github.ref_name }},ci/main" --idle 30m --json > env.json
          echo "BOX=$(jq -r .name env.json)" >> "$GITHUB_ENV"

      - name: Build and test
        run: envctl exec "$BOX" -- sh -c 'cd /work && make test && make build && cp -r dist out/'

      - name: Keep the build
        run: envctl artifact put .remote/$BOX/out/dist/app.tar.gz --expires 14d --link 7d

      - name: Clean up
        if: always()
        run: |
          for id in $(envctl env list --label ci-run=${{ github.run_id }} --json | jq -r '.[].id'); do envctl env delete "$id"; done
          envctl sandbox down --forget
```

## Notes

* `ENVLINK_API` and `ENVLINK_TOKEN` stand in for `envctl login`, so nothing is written to the runner's disk.
* `--snapshot ci/<branch>` with `--restore ci/<branch>,ci/main` starts each run from the last one on the branch, or from `main`, so the first sync sends only what changed.
* Labels make cleanup exact, even when a step fails.
* `envctl sandbox down --forget` deregisters the runner and takes it off the tailnet.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.