# Set Up Ci

> >-

- **Type:** Skill
- **Install:** `agentstack add skill-cboone-agent-harness-plugins-set-up-ci`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [cboone](https://agentstack.voostack.com/s/cboone)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [cboone](https://github.com/cboone)
- **Source:** https://github.com/cboone/agent-harness-plugins/tree/main/dist/codex/plugins/set-up-ci/skills/set-up-ci
- **Website:** https://github.com/cboone/agent-harness-plugins

## Install

```sh
agentstack add skill-cboone-agent-harness-plugins-set-up-ci
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Set-Up CI

Detect the project's language(s), create a GitHub Actions CI workflow with appropriate parallel jobs (test, lint, format, vulnerability check), and create matching Makefile targets for local development.

## Workflow

### 1. Detect Project Type

If the user specified a language in their request (e.g., `go-cli`, `go-library`, `javascript`, `python`, `rust`, `ruby`, `shell`, `zig`, `zsh`), use it directly instead of scanning for markers. Still perform sub-detection steps as needed (e.g., JS package manager detection for `javascript`, or verifying `main.go`/`cmd/` for `go-cli` vs `go-library`).

Scan for language and file-type markers using Glob. **Exclude `node_modules/`, `.yarn/`, `vendor/`, and other dependency directories from all searches** to avoid false positives from vendored code.

| Marker(s)                                                                                                     | Language              |
| ------------------------------------------------------------------------------------------------------------- | --------------------- |
| `go.mod`                                                                                                      | Go                    |
| `package.json` + source files (`*.js`, `*.ts`, `*.jsx`, `*.tsx`, `*.mjs`, `*.mts`, excluding `node_modules/`) | JavaScript/TypeScript |
| `pyproject.toml`, `setup.py`, `requirements.txt`                                                              | Python                |
| `Cargo.toml`                                                                                                  | Rust                  |
| `build.zig`, `build.zig.zon`                                                                                  | Zig                   |
| `Gemfile`, `*.gemspec`                                                                                        | Ruby                  |
| `*.sh`, `bin/*`, `scripts/*`                                                                                  | Shell                 |
| `*.zsh`, `#!/usr/bin/env zsh` shebangs, `.zshrc`, `.zshenv`                                                   | Zsh                   |

**Go sub-detection**: If `main.go` exists at the root or a `cmd/` directory exists, classify as **Go CLI**. Otherwise classify as **Go Library**.

**JS/TS sub-detection**: Determine the package manager from lockfiles:

- `package-lock.json` = npm
- `yarn.lock` or `.yarnrc.yml` = yarn
- `pnpm-lock.yaml` = pnpm
- `bun.lock` = bun
- Default to npm if no lockfile found.

**Source file verification**: When `package.json` is detected, verify that actual JavaScript or TypeScript source files exist (`*.js`, `*.ts`, `*.jsx`, `*.tsx`, `*.mjs`, `*.mts`, excluding `node_modules/` and config files like `eslint.config.js`). A `package.json` used only for devDependencies (e.g., markdownlint tooling) does not make the project a JavaScript project. If no source files are found, skip JavaScript/TypeScript CI.

If multiple languages are detected, create a multi-language workflow with one job group per language. Present the detected languages to the user and confirm before proceeding.

If no language is detected, offer a generic workflow with `make test` and `make lint` targets.

### 2. Check for Existing CI

Look for existing CI files:

```bash
ls .github/workflows/ci.yml
ls .github/workflows/ci.yaml
ls .github/workflows/*.yml
```

If a CI workflow exists, present its contents and ask the user:

1. **Overwrite**: Replace the existing CI workflow entirely
1. **Merge**: Add missing jobs to the existing workflow (keep existing jobs intact)
1. **Abort**: Stop without changes

### 3. Check for Existing Makefile

If a `Makefile` exists, scan for existing CI-relevant targets:

```bash
grep -E '^(test|lint|fmt|vet|vuln|build|cover|coverage|tidy|tools|all|deny|audit|typos|changelog):' Makefile
```

Report which targets already exist and which will be added. Only add targets that do not already exist. Ask before modifying any existing target.

If no `Makefile` exists, offer to create one with the appropriate language-specific Makefile reference (see `./references/makefile-.md`). The Makefile provides standard targets for local development (`test`, `lint`, `fmt`, `vuln`, etc.) and is required by the Go CI reusable workflow (`run-go-ci.yml@v3.0.0`), which calls Makefile targets (`make test`, `make vet`, `make fmt`, etc.) directly. If the user declines, note that CI will fail for Go templates because the reusable workflow requires Makefile targets.

### 4. Create CI Workflow

Read the appropriate language CI reference under `./references/ci-.md` and generate `.github/workflows/ci.yml` from it. Write the file using the Write tool. The `.github/workflows/` directory will be created automatically if it does not exist.

Go, Rust, Zig, Shell, and secret scanning templates use `cboone/gh-actions` reusable workflows that handle tool installation, caching, and execution internally. Other language templates use inline jobs.

#### Ensure a Language Version File

The CI templates read language runtime versions from a project-owned version file rather than pinning inline:

| Language | Version source the workflow reads                | Action if missing                                                                 |
| -------- | ------------------------------------------------ | --------------------------------------------------------------------------------- |
| Node.js  | `.tool-versions` (line `nodejs `)       | Create `.tool-versions` with `nodejs ` and warn the user to commit it |
| Ruby     | `.tool-versions` (line `ruby `)         | Create `.tool-versions` (or append) with `ruby `                   |
| Go       | `go.mod` (`go X.Y` directive)                    | Always present in a Go project; no action needed                                  |
| Rust     | `rust-toolchain.toml` (when present)             | Create one with `[toolchain] channel = "stable"` if missing                       |
| Python   | `pyproject.toml` `requires-python` (uv reads it) | Ensure the constraint is present in `pyproject.toml`                              |
| Zig      | `build.zig.zon` `minimum_zig_version`            | Always present in a Zig project; no action needed                                 |

Before writing the CI workflow, check for the relevant version file and create or update it as needed. Latest LTS / stable lookups:

- Node.js LTS: `curl -s https://nodejs.org/dist/index.json | jq -r 'first(.[] | select(.lts != false)) | .version' | sed 's/^v//'`
- Latest stable Ruby: `gh api repos/ruby/ruby/releases --jq 'first(.[] | select(.prerelease == false)) | .tag_name' | sed 's/^v//; s/_/./g'` (Ruby tags use both `v3.4.0` and `v3_4_0` forms; the trailing `sed` normalizes them to the dotted format `.tool-versions` expects)

All templates share:

- Triggers: push to `main`, pull requests targeting `main`
- `paths-ignore` for documentation and agent configuration changes
- Concurrency groups to cancel in-progress runs on the same branch/PR
- `permissions: contents: read`
- `actions/checkout@v6` (in inline jobs) or handled by reusable workflows

#### Runner Usage Notes

The `paths-ignore` patterns skip CI for changes that do not affect build or test outcomes:

- `*.md` matches root-level Markdown only (README, CONTRIBUTING, etc.). Nested `.md` files such as Scrut CLI tests in `tests/scrut/` are NOT ignored, so CI still runs when test files change.
- `docs/**` skips documentation directory changes.
- `.claude/**`, `**/CLAUDE.md`, `**/AGENTS.md` skip AI agent configuration files.
- `LICENSE` and `.editorconfig` skip non-code metadata.

**When to adjust**: Remove `*.md` from `paths-ignore` if your project treats Markdown files as source code (e.g., documentation-focused projects where Markdown linting is a CI step). Remove `docs/**` if your docs directory contains generated API references that should trigger CI.

The concurrency group cancels in-progress CI runs when new commits are pushed to the same branch or PR. This prevents wasted minutes on superseded commits.

For multi-language projects, combine language-specific jobs into a single workflow file using the multi-language pattern in `./references/ci-multi-language.md`.

### 5. Create or Update Makefile Targets

Read the appropriate language Makefile reference under `./references/makefile-.md` and add missing targets from it. Include both targets that the CI workflow references directly (e.g., `make test`, `make vet`) and standard local-development targets (`test`, `lint`, `fmt`, `vuln`, etc.) even when the CI workflow runs equivalent commands directly rather than via `make`.

Rules:

- Only add targets that do not already exist in the Makefile
- Ask before modifying existing targets
- If creating a new Makefile, include a `help` target
- Preserve any existing Makefile content (append new targets at the end)

### 6. Summary

Print a summary of what was created or modified:

- List every file created or modified
- Suggest complementary plugins:
  - The set-up-secret-scanning skill for secret scanning
  - The set-up-linters skill for linter configuration (if no linter configs detected)
  - The add-scrut-cli-tests skill for CLI snapshot testing (if CLI project detected)
  - The add-goreleaser-homebrew skill for release automation (if Go project detected)

## Error Handling

- **Not a git repo**: Warn the user, suggest `git init`, then continue (CI workflow files do not require a git repo to create, but will not trigger without one)
- **No language detected**: Offer a generic workflow with checkout + `make test` / `make lint` targets
- **Existing CI**: Ask before overwriting (covered in step 2)
- **Missing Makefile**: Offer to create one; if the user declines, note that CI may fail for language templates whose workflows reference `make` targets

## CI Workflow Templates

- `./references/ci-go-cli.md` -- Go CLI CI workflow
- `./references/ci-go-library.md` -- Go library CI workflow
- `./references/ci-javascript.md` -- JavaScript/TypeScript CI workflow
- `./references/ci-python.md` -- Python CI workflow
- `./references/ci-rust.md` -- Rust CI workflow
- `./references/ci-ruby.md` -- Ruby CI workflow
- `./references/ci-shell.md` -- Shell CI workflow
- `./references/ci-zig.md` -- Zig CI workflow
- `./references/ci-zsh.md` -- Zsh CI workflow
- `./references/ci-multi-language.md` -- Multi-language CI pattern

## Makefile Templates

- `./references/makefile-go-cli.md` -- Go CLI Makefile
- `./references/makefile-go-library.md` -- Go library Makefile
- `./references/makefile-javascript.md` -- JavaScript/TypeScript Makefile
- `./references/makefile-python.md` -- Python Makefile
- `./references/makefile-rust.md` -- Rust Makefile
- `./references/makefile-ruby.md` -- Ruby Makefile
- `./references/makefile-shell.md` -- Shell Makefile
- `./references/makefile-zig.md` -- Zig Makefile
- `./references/makefile-zsh.md` -- Zsh Makefile

## Refresh `cboone/gh-actions` SHAs before scaffolding

The `cboone/gh-actions` reusable-workflow refs in this skill's templates are SHA-pinned with a `# vX.Y.Z` comment that was current when the template was authored. New releases of `cboone/gh-actions` rot those SHAs. Before emitting a workflow into a user's repo, refresh both the SHA and the comment to current latest:

```bash
TAG="$(gh release view --repo cboone/gh-actions --json tagName --jq '.tagName')"
SHA="$(gh api "repos/cboone/gh-actions/commits/${TAG}" --jq '.sha')"
echo "${SHA} # ${TAG}"
```

Replace each `cboone/gh-actions/.../.yml@ # ` in the emitted workflow with the new SHA and tag. Dependabot in the user's repo keeps them in sync afterwards.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [cboone](https://github.com/cboone)
- **Source:** [cboone/agent-harness-plugins](https://github.com/cboone/agent-harness-plugins)
- **License:** MIT
- **Homepage:** https://github.com/cboone/agent-harness-plugins

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-cboone-agent-harness-plugins-set-up-ci
- Seller: https://agentstack.voostack.com/s/cboone
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
