Docs/CI Templates
Templates

CI Templates

Drop these files into your repository to run DocsCI on every push. All templates call the same public API — pick the one that fits your stack.

Quick setup (2 steps)

  1. Create a project — copy your Project ID from the project settings page
  2. Add DOCSCI_TOKEN as a secret and DOCSCI_PROJECT_ID as a variable in your CI settings

API tokens: coming soon — use your Supabase session cookie for now (see curl script below)

🐙 GitHub Actions

Add to .github/workflows/docsci.yml

# .github/workflows/docsci.yml
name: DocsCI
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]
jobs:
  docs-ci:
    name: Verify docs with DocsCI
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v4
      - name: Run DocsCI
        id: docsci
        run: |
          set -euo pipefail
          RESULT=$(curl -sf -X POST https://snippetci.com/api/runs/queue \
            -H "Authorization: Bearer ${{ secrets.DOCSCI_TOKEN }}" \
            -H "Content-Type: application/json" \
            --max-time 120 \
            -d '{"mode":"repo","repo_id":"${{ vars.DOCSCI_PROJECT_ID }}","branch":"${{ github.ref_name }}","commit_sha":"${{ github.sha }}"}')
          STATUS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','unknown'))")
          FINDINGS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('finding_count',0))")
          echo "status=$STATUS"     >> "$GITHUB_OUTPUT"
          echo "findings=$FINDINGS" >> "$GITHUB_OUTPUT"
      - name: Fail if docs have errors
        if: steps.docsci.outputs.status == 'failed'
        run: |
          echo "::error::DocsCI found ${{ steps.docsci.outputs.findings }} issue(s)."
          exit 1

🌀 curl fallback script

Works in any CI system (CircleCI, Bitbucket Pipelines, Jenkins, Buildkite) or locally. Save as scripts/run-docsci.sh.

#!/usr/bin/env bash
# run-docsci.sh — works in any CI or locally
# Export: DOCSCI_TOKEN, DOCSCI_PROJECT_ID
set -euo pipefail

BRANCH="${DOCSCI_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}"
COMMIT="${DOCSCI_COMMIT:-$(git rev-parse HEAD)}"

RESULT=$(curl -sf -X POST https://snippetci.com/api/runs/queue \
  -H "Authorization: Bearer $DOCSCI_TOKEN" \
  -H "Content-Type: application/json" \
  --max-time 120 \
  -d "{\
    \"mode\":\"repo\",\
    \"repo_id\":\"$DOCSCI_PROJECT_ID\",\
    \"branch\":\"$BRANCH\",\
    \"commit_sha\":\"$COMMIT\"\
  }")

STATUS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','unknown'))")
FINDINGS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('finding_count',0))")

echo "DocsCI $STATUS — $FINDINGS finding(s)"
[ "$STATUS" = "passed" ] && exit 0 || exit 1
Download run-docsci.shchmod +x scripts/run-docsci.sh

Environment variables

DOCSCI_TOKEN — required, your API token

DOCSCI_PROJECT_ID — required, project UUID

DOCSCI_BRANCH — optional, defaults to current git branch

DOCSCI_COMMIT — optional, defaults to HEAD SHA

DOCSCI_FAIL_FAST — set to "0" to exit 0 on findings

DOCSCI_TIMEOUT — curl timeout seconds (default: 120)

🦊 GitLab CI

Add to .gitlab-ci.yml

# .gitlab-ci.yml
stages: [docs-ci]
docsci:
  stage: docs-ci
  image: python:3.11-alpine
  before_script: [apk add --no-cache curl]
  script:
    - |
      RESULT=$(curl -sf -X POST https://snippetci.com/api/runs/queue \
        -H "Authorization: Bearer $DOCSCI_TOKEN" \
        -H "Content-Type: application/json" \
        --max-time 120 \
        -d "{\"mode\":\"repo\",\"repo_id\":\"$DOCSCI_PROJECT_ID\",\"branch\":\"$CI_COMMIT_BRANCH\",\"commit_sha\":\"$CI_COMMIT_SHA\"}")
      STATUS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status','unknown'))")
      FINDINGS=$(echo "$RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('finding_count',0))")
      echo "DocsCI $STATUS — $FINDINGS finding(s)"
      [ "$STATUS" = "failed" ] && exit 1 || exit 0
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

⚙️ docsci.yml config

Drop in your repo root to control timeouts, languages, file globs, and security. See the getting started guide for all options.

# docsci.yml — place in your repo root
version: 1
docs:
  path: docs
  include: ["docs/**/*.md"]
  exclude: ["docs/internal/**"]
openapi:
  path: openapi.yaml
snippets:
  timeout_seconds: 20
  languages: [python, javascript, typescript]
  skip_patterns: ["# docsci: skip"]
security:
  network_isolated: false
  allowlist: ["api.example.com"]
checks:
  accessibility: true
  copy_lint: true
  drift_detection: true
  snippets: true

Programmatic access

All templates are available via the API — useful for automation:

# List all templates
curl https://snippetci.com/api/templates

# Download a specific template
curl https://snippetci.com/api/templates?id=github-actions&download=1 > .github/workflows/docsci.yml
curl https://snippetci.com/api/templates?id=curl-fallback&download=1 > scripts/run-docsci.sh
curl https://snippetci.com/api/templates?id=docsci-yml&download=1 > docsci.yml
📖

Migrating from ad-hoc doctests?

If you're using pytest doctest, Jupyter notebooks, or custom test scripts to verify code examples, our migration guide shows you how to replace them with DocsCI in under an hour.

Read the migration guide →