CI/CD Usage

shuck works in CI environments out of the box. It detects $CI=true and automatically falls back to pipe mode when a PTY isn’t available.

Automatic CI Detection

Most CI systems set CI=true in the environment. shuck checks this and switches to --no-pty mode automatically:

# In CI: shuck detects CI=true and uses pipes
# Locally: shuck uses PTY (full interactive behavior)
shuck my-interactive-tool

No configuration required. Your scripts work identically in both environments.

GitHub Actions

Basic Usage

name: Test with shuck
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install shuck
        run: cargo install shuck
        # Or: curl -fsSL https://shuck.build/install.sh | sh
      
      - name: Run interactive tool
        run: |
          result=$(shuck --json python3 -- "print('hello from CI')")
          echo "$result" | jq .

With JSON Output Parsing

- name: Run and parse output
  run: |
    result=$(shuck --json --timeout 60 my-tool -- "process data")
    exit_code=$(echo "$result" | jq -r '.exit_code')
    
    if [ "$exit_code" -ne 0 ]; then
      echo "Tool failed: $(echo "$result" | jq -r '.stderr')"
      exit 1
    fi
    
    echo "Output: $(echo "$result" | jq -r '.stdout')"

Testing Interactive Tools

- name: Test Python REPL interaction
  run: |
    # Verify a library works correctly in REPL mode
    output=$(shuck python3 -- "
    import numpy as np
    arr = np.array([1, 2, 3])
    print(arr.mean())
    ")
    echo "Mean: $output"
    [ "$output" = "2.0" ] || exit 1

Agent-Driven CI

Agents that manage CI pipelines can use shuck to run interactive tools within CI jobs:

# Agent-generated CI workflow
- name: Agent database migration check
  run: |
    # Agent uses shuck to inspect the database schema in CI
    result=$(shuck --json psql -U postgres testdb -- "\dt")
    echo "$result" | jq -r '.stdout' > schema.txt
    
    # Agent checks for expected tables
    if ! grep -q "users" schema.txt; then
      echo "Migration incomplete: users table missing"
      exit 1
    fi

- name: Agent package health check
  run: |
    # Agent runs diagnostics to verify CI environment
    shuck --json pip check > pip-health.json
    shuck --json npm doctor > npm-health.json

GitLab CI

test-with-shuck:
  image: rust:latest
  script:
    - cargo install shuck
    - shuck --json echo "hello CI"
    - result=$(shuck --json python3 -- "print('gitlab')")
    - echo $result | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['stdout'])"

CircleCI

version: 2.1
jobs:
  test:
    docker:
      - image: cimg/rust:1.75
    steps:
      - checkout
      - run:
          name: Install shuck
          command: cargo install shuck
      - run:
          name: Run interactive tests
          command: |
            shuck --json --timeout 30 my-interactive-tool

Docker

# Install shuck in your Docker image
FROM rust:1.75-slim AS builder
RUN cargo install shuck

FROM debian:bookworm-slim
COPY --from=builder /usr/local/cargo/bin/shuck /usr/local/bin/shuck

# shuck will auto-detect if it's in a container without TTY
CMD ["shuck", "--json", "my-tool"]

Force No-PTY

If you need to explicitly disable PTY (e.g., in a serverless function or container without PTY support):

shuck --no-pty my-tool

Or set CI=true in your environment.

Exit Code in CI

shuck’s exit codes integrate naturally with CI pass/fail:

# CI will mark this step as failed if my-tool exits non-zero
shuck my-tool

# Or check explicitly
shuck --json my-tool > result.json
exit_code=$(jq .exit_code result.json)
exit $exit_code

Performance Tips

  • Use --timeout to prevent runaway jobs: shuck --timeout 120 slow-tool
  • Use --quiet to suppress noisy tools: shuck --quiet verbose-tool
  • Use --no-pty for commands that don’t need PTY to shave a few ms

Caching shuck in CI

# GitHub Actions - cache cargo bin
- uses: actions/cache@v4
  with:
    path: ~/.cargo/bin/shuck
    key: shuck-${{ runner.os }}-v0.1.0
    
- name: Install shuck if not cached
  run: which shuck || cargo install shuck