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
--timeoutto prevent runaway jobs:shuck --timeout 120 slow-tool - Use
--quietto suppress noisy tools:shuck --quiet verbose-tool - Use
--no-ptyfor 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