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

# Deploy Plays with GitHub Actions

> Validate Deepline Plays in pull requests and publish approved revisions after merge.

[Human guide: work with your agent →](https://deepline.com/docs/human/sdk-v2/github-deployments.md)

> [!NOTE]
>
> Deploy a selected Play directory from a pinned CLI workflow and inspect the
> resulting versions.

Use GitHub as the source of truth for Deepline Play code. Pull requests validate
changes, and merges to `main` publish them to Deepline.

These instructions work for a human or coding agent.

> [!NOTE]
>
> For GitHub.com, use [Git deploys](https://deepline.com/docs/sdk-v2/git-deploys.md) unless your
> organization cannot install the Deepline GitHub App. This Actions workflow is
> the fallback for restricted organizations and GitHub Enterprise Server.

## Deploy a directory of Plays

`deepline plays deploy` takes a directory, works out which Plays it contains,
and deploys them as one unit: every changed Play is validated and registered,
then promoted together, so either all of them go live or none do. Unchanged
Plays are skipped.

It does not use git. Check the code out however you like first — in GitHub
Actions that is `actions/checkout`:

```yaml theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
name: Deploy Deepline Plays

on:
  push:
    branches: [main]

permissions:
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - run: npx --yes "deepline@${{ vars.DEEPLINE_CLI_VERSION }}" plays deploy
        env:
          DEEPLINE_API_KEY: ${{ secrets.DEEPLINE_API_KEY }}
```

The directory's `deepline.json` selects the Plays (default `**/*.play.ts`).
Pass a path to deploy one part of a monorepo (`deepline plays deploy ./growth`)
and `--manifest <file>` for a different manifest. Any CI works the same way:
the command only needs the files on disk and `DEEPLINE_API_KEY`.

Record where the code came from with `--repo`, `--ref`, and `--commit`. They
are provenance on the deployment receipt, nothing more:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
deepline plays deploy --repo "$GITHUB_REPOSITORY" --ref "$GITHUB_REF" --commit "$GITHUB_SHA"
```

Each deploy prints its result, and the command exits non-zero when the deploy
fails. A warning (for example, a Play another linked repository owns) still
exits zero. It is printed with the Play. Look a deployment up again from
anywhere in the workspace:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
deepline plays deployments               # recent deployments
deepline plays deployments "$DEPLOYMENT_ID"  # its Plays, versions, and warnings
```

Deleting a Play file does not retire the live Play. decommission its
schedules, webhooks, and callers separately.

Each Play is built with the Deepline SDK, so a new SDK release gives Plays you
didn't change a new version on their next deploy. Those are marked **SDK
updated**: the Play's code and everything it imports are unchanged.

### A Play a linked repository owns

Deploying a directory that contains a Play a linked repository deploys is
allowed: the version goes live and the Play is marked drifted from that
repository, because the next push from it will replace what you just
deployed.

* **Still using the repository?** Push the same change from it. That deploy
  wins and clears the drift.
* **Done with the repository?** Unlink it. An unlinked repository owns
  nothing, so its Plays are released: they keep their live version and stop
  showing the repository as their source or being marked drifted from it.

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
deepline git list             # find the link id
deepline git unlink "$LINK_ID"
```

Unlinking never stops a live Play. It only stops the repository deploying.

## 1. Add Play source to the repository

Commit each Deepline Play as a `*.play.ts` file: one Play per file, named by
the file. The files can live anywhere in the repository.

Keep code and non-secret configuration in GitHub. Store provider credentials in
Deepline. Do not commit customer data, credentials, or live provider responses.

## 2. Pin the Deepline CLI

Choose a tested version:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
npm view deepline version
```

Set `DEEPLINE_CLI_VERSION` as a GitHub Actions repository variable. Pinning the
CLI prevents an unreviewed release from changing deployment behavior.

## 3. Configure Deepline credentials

Add these GitHub Actions secrets:

| Secret | Scope | Purpose |
| - | - | - |
| `DEEPLINE_CHECK_API_KEY` | Repository | Validate against an isolated non-production workspace |
| `DEEPLINE_API_KEY` | Protected `deepline-production` environment | Publish approved Plays to the production workspace |

Restrict the production environment to `main`. Add required reviewers if
publication needs a separate approval.

Each key must identify one Deepline workspace. Do not use a production key for
pull-request validation or choose the target workspace from pull-request input.
Configure each workspace with the provider credentials its Plays use and active
Play secrets for every name those Plays declare. Use non-production credentials
in the validation workspace and production credentials in the production
workspace.

This workflow supports pull requests whose branches live in the same repository.
GitHub withholds repository secrets from forked pull requests. To validate a fork,
move the reviewed commit to a maintainer-controlled branch. do not expose secrets
with `pull_request_target`.

## 4. Add the workflow

Create `.github/workflows/deepline.yml`:

```yaml theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
name: Deploy Deepline Plays

on:
  pull_request:
  push:
    branches: [main]
  workflow_dispatch:

permissions:
  contents: read

env:
  DEEPLINE_HOST_URL: https://code.deepline.com
  DEEPLINE_CLI_VERSION: ${{ vars.DEEPLINE_CLI_VERSION }}

jobs:
  validate:
    name: Validate Plays
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - name: Install Deepline
        shell: bash
        run: |
          set -euo pipefail
          : "${DEEPLINE_CLI_VERSION:?Set the DEEPLINE_CLI_VERSION repository variable}"
          npm install --global "deepline@${DEEPLINE_CLI_VERSION}"
      - name: Check Plays
        shell: bash
        env:
          DEEPLINE_API_KEY: ${{ secrets.DEEPLINE_CHECK_API_KEY }}
        run: |
          set -euo pipefail
          found=0
          while IFS= read -r -d '' play; do
            found=1
            echo "Checking ${play}"
            deepline plays check "${play}"
          done < <(git ls-files -z -- '*.play.ts')
          test "${found}" -eq 1

  publish:
    name: Publish Plays
    if: github.event_name != 'pull_request'
    needs: validate
    runs-on: ubuntu-latest
    environment: deepline-production
    concurrency:
      group: deepline-production
      cancel-in-progress: false
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - name: Install Deepline
        shell: bash
        run: |
          set -euo pipefail
          : "${DEEPLINE_CLI_VERSION:?Set the DEEPLINE_CLI_VERSION repository variable}"
          npm install --global "deepline@${DEEPLINE_CLI_VERSION}"
      - name: Publish Plays
        shell: bash
        env:
          DEEPLINE_API_KEY: ${{ secrets.DEEPLINE_API_KEY }}
        run: |
          set -euo pipefail
          while IFS= read -r play; do
            [[ -n "${play}" ]] || continue
            check_json="$(deepline plays check "${play}" --json)"
            artifact_hash="$(jq -r '.artifactHash // empty' <<<"${check_json}")"
            [[ -n "${artifact_hash}" ]] || {
              echo "Missing artifactHash for ${play}" >&2
              exit 1
            }
            deepline plays publish "${play}" \
              --expected-artifact "${artifact_hash}"
          done < <(git ls-files -- '*.play.ts' | sort)
```

The workflow checks every tracked `*.play.ts` file. After a merge or manual run,
it republishes every tracked Play so changes to imported helpers and configuration
are included. `--expected-artifact` prevents publication if a file differs from
the artifact that was just checked.

## 5. Test and operate the workflow

Open a pull request that changes a Play and confirm **Validate Plays** passes.
Merge it, then confirm **Publish Plays** succeeds in GitHub Actions.

Set `PLAY_NAME` to the saved Play you just published, then verify the live
revision:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
PLAY_NAME="my-play"
deepline plays versions --name "$PLAY_NAME"
deepline describe "$PLAY_NAME"
```

For later changes, repeat the same pull request, validation, merge, and
verification flow. Test changed runtime behavior with approved synthetic input
in an internal or test workspace. Do not publish production Plays from a
workstation during normal development.

To roll back, copy the previous immutable revision ID from `plays versions`,
then promote it:

```bash theme={"languages":{"custom":["/languages/deepline-prompt.json"]}}
PLAY_NAME="my-play"
REVISION_ID="revision-id-from-plays-versions"
deepline plays set-live "$PLAY_NAME" --revision-id "$REVISION_ID"
```

Then revert or fix the GitHub source so the repository and live revision agree
again.

> [!WARNING]
>
> Keep production credentials out of pull-request jobs. Deleting a `*.play.ts`
> file does not disable the live Play. decommission its schedules, webhooks, and
> callers separately.

> **[Play SDK quickstart](https://deepline.com/docs/sdk-v2/quickstart.md)**
>
> Create, check, and run a custom Play.

> **[Production integration](https://deepline.com/docs/sdk-v2/production-integration.md)**
>
> Integrate published Plays into a production application.

## Verify this task

Confirm the checked source, pinned CLI version, intended credentials, and workflow result. Keep pull-request validation distinct from production publication.

Ask your agent to explain a failed check before repeating work or expanding the scope.


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