shep

CI/CD Pipeline

Automated build, test, and release pipeline using GitHub Actions.

Pipeline Overview

Push/PR to main or develop:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Lint   β”‚ Typecheck β”‚ Unit Tests β”‚  E2E CLI  β”‚  E2E TUI  β”‚  E2E Web  β”‚ Storybook β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Gitleaks β”‚ Semgrep β”‚ Security Enforce β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            (all run in parallel)

On PR only:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Claude Review  β”‚  Documentation & Architecture compliance check    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

On push to main only (after ALL jobs pass, including security):
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Release  β”‚  β†’ npm publish + GitHub release + `v<version>` tag
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

On published GitHub Release (created by Release) or manual dispatch:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Docker Publish β”‚  β†’ build image + push to ghcr.io
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Jobs

Parallel Jobs (All Branches)

Job Description Duration
Lint & Format ESLint + Prettier + TypeSpec compile (pnpm tsp:compile) ~30s
Type Check TypeScript strict mode validation (requires TypeSpec types) ~20s
Unit Tests Vitest unit + integration tests (Linux + Windows) ~20s
E2E (CLI) CLI command execution tests (Linux + Windows) ~30s
E2E (TUI) Terminal UI interaction tests ~20s
E2E (Web) Playwright browser tests ~25s
Storybook Build Builds all stories (catches missing mocks/broken imports) ~40s
Electron Desktop installers for macOS/Windows/Linux ~5m

Note: Docker images are not built in the CI matrix. They are published by the separate docker-publish.yml workflow, triggered by the v* release tag (see Docker Images).

Security Jobs (All Branches)

Security scanners run in parallel and block releases on main:

Scanner Tool Severity Filter
Gitleaks Secret detection (API keys, passwords, tokens) All findings
Semgrep SAST rules (p/typescript, p/javascript, p/security-audit) All findings
Security Enforce shep security enforce β€” supply-chain/governance posture Gates release

Note: Gitleaks uses the CLI directly (not gitleaks-action) because the GitHub Action requires a paid license for organizations.

Claude Review Job (PRs Only)

Automated code review using Claude Code, focusing on:

Check Area What It Validates
Documentation Consistency Changes reflected in docs/, CLAUDE.md, AGENTS.md
Architecture Compliance Clean Architecture layers, dependency rule, patterns
TDD & Testing Test coverage for new functionality
Spec-Driven Workflow Feature PRs have specs/ directory with required files

Review Output:

Required Secret: CLAUDE_CODE_OAUTH_TOKEN (org-level)

Release Job (Main Only)

Runs after all parallel jobs pass, including security scanners. Uses semantic-release to:

  1. Analyze commits - Determine version bump from conventional commits
  2. Generate changelog - Create release notes from commits
  3. Update CHANGELOG.md - Append new release section
  4. Publish to npm - @shepai/cli package
  5. Create GitHub release - With changelog as release notes (triggers Docker Publish)
  6. Commit changes - chore(release): <version> [skip ci]
  7. Push v<version> tag - versioned tag pointing at the release commit

Docker images are built and pushed by the separate docker-publish.yml workflow, which fires on the published GitHub Release (and can be run manually via workflow dispatch). It is deliberately NOT triggered by the v* tag push: semantic-release tags the chore(release): … [skip ci] commit, and GitHub Actions skips workflows for tags pointing at a [skip ci] commit. The release event is immune to [skip ci], so it fires reliably.

Docker Images

Registry

Images are published to GitHub Container Registry (ghcr.io):

ghcr.io/shep-ai/shep

Tagging Strategy

Trigger Tags
Published Release (v* tag) latest, 1.2.3, 1.2, 1, sha-<full-commit-sha>
Manual dispatch (main) latest, sha-<full-commit-sha>

Pull & Run

# Latest stable
docker pull ghcr.io/shep-ai/shep:latest
docker run ghcr.io/shep-ai/shep --version

# Specific version
docker pull ghcr.io/shep-ai/shep:v1.0.0

# Specific commit (for testing)
docker pull ghcr.io/shep-ai/shep:sha-abc123...

Image Details

Release Process

Automatic Releases

Releases are fully automated based on Conventional Commits:

Commit Type Version Bump Example
feat: Minor (0.X.0) feat(cli): add analyze command
fix: Patch (0.0.X) fix(agents): resolve memory leak
perf: Patch perf(db): optimize query performance
refactor: Patch refactor(core): simplify state management
BREAKING CHANGE Major (X.0.0) Footer in commit message

Commits that don’t trigger releases:

If needed, you can trigger a release manually:

# Ensure you're on main with latest changes
git checkout main && git pull

# Run semantic-release in dry-run mode first
npx semantic-release --dry-run

# If satisfied, run actual release (requires NPM_TOKEN)
NPM_TOKEN=xxx GITHUB_TOKEN=xxx npx semantic-release

Configuration Files

File Purpose
.github/workflows/ci.yml Main CI/CD workflow (build, test, security, release)
.github/workflows/docker-publish.yml Build & push the image to ghcr.io on v* tags
.github/workflows/pr-check.yml PR-specific checks (commitlint, PR title)
.github/workflows/claude-review.yml Claude Code automated review
release.config.mjs semantic-release plugins and settings
Dockerfile Multi-stage build for production image
.dockerignore Files excluded from Docker build context
commitlint.config.mjs Commit message validation rules

Limitations & Considerations

Docker Cache

Concurrency

Required Secrets

Secret Purpose Where to Set
GITHUB_TOKEN Automatic, provided by GitHub Actions Built-in
NPM_TOKEN Publishing to npm registry Repository secrets
CLAUDE_CODE_OAUTH_TOKEN Claude Code automated PR review Organization secrets

Branch Protection

Recommended settings for main:

Troubleshooting

Release Not Triggered

  1. Check commit messages follow conventional format
  2. Ensure push is to main branch
  3. Verify commit doesn’t contain [skip ci]
  4. Check if commit type triggers a release (see table above)

Docker Build Fails

  1. Check .dockerignore isn’t excluding required files
  2. Verify pnpm-lock.yaml is committed
  3. Check Node.js version matches package.json engines

npm Publish Fails

  1. Verify NPM_TOKEN secret is set and valid
  2. Check package name isn’t taken on npm
  3. Ensure version in package.json wasn’t manually bumped

Local Testing

Test Docker Build

docker build -t shep-cli .
docker run shep-cli --version

Test Release (Dry Run)

npx semantic-release --dry-run

Validate Commit Messages

echo "feat(cli): add new command" | npx commitlint

Maintaining This Document

Update when:

Related files: