## Problem
Agent CI still depended on the TypeScript runner as the main execution path. That made it harder to ship a small native binary and harder to prove the Rust path matched the TypeScript path. Review also found places where Rust and TypeScript could drift before the Rust path becomes the default.
## Solution
This PR adds the opt-in Rust native `agent-ci` binary and platform npm packages while keeping the TypeScript fallback. It splits the Rust code into `agent-ci-core`, `agent-ci-runtime`, and a thin CLI/orchestration crate. Pure planning, reusable workflow expansion, event contracts, and run-result contracts now live in core; runtime owns Docker, DTU, runner, macOS VM, workspace, execution-plan adapters, and the generic wave worker pool.
The fixture checks now use real TypeScript helpers instead of a shadow planner. Shared fixtures cover plans, events, run results, Docker socket resolution, and default job-limit CPU/memory vectors. The Rust runner honors `--jobs`, probes Docker memory for the default job limit, supports macOS VM concurrency limits, avoids nested runner container name collisions, has `--all` smoke coverage, and stages `bin/agent-ci` in every platform package.
## Validation
- `cargo check --workspace --all-targets`
- `cargo fmt --all -- --check`
- `cargo clippy --workspace --all-targets -- -D warnings`
- `cargo test --workspace --all-targets`
- `pnpm check`
- `pnpm fixtures:check`
- `pnpm golden:cli`
- `pnpm rust:smoke:parity`
- `pnpm agent-ci-dev run --all -q -p --json --github-token`
## Notes
Rust execution is still opt-in. The TypeScript implementation and fallback remain in place until the later default-switch and removal gates pass.
Replace mutable tag refs (@v4, @v5, @v1, @main) with 40-char commit
SHAs and a trailing `# vX.Y.Z` comment, per GitHub's hardening guidance.
Covers .github/workflows/, .docs/marketing/demo-recording/, and the
skill-evals fixture repos. Embedded YAML inside heredocs is also pinned.
No packages/ code changes, so no changeset.
* chore: require Node 24 and drop tsx
Node 24 ships native TypeScript stripping as a stable feature. We no
longer need tsx to execute .ts files in development scripts.
Changes:
- `engines.node` bumped from `>=22` to `>=24` in each package.
- `tsx` removed from every workspace's devDependencies.
- Each `tsx foo.ts` invocation in package scripts becomes `node foo.ts`.
Includes `scripts/agent-ci-dev.sh` (the dev wrapper) and the demo
package.
- tsconfigs gain `allowImportingTsExtensions`, `rewriteRelativeImportExtensions`,
and `verbatimModuleSyntax` so source uses `.ts` extensions while tsc
still emits `.js` paths in dist.
- All relative imports rewritten from `from "./foo.js"` to `from "./foo.ts"`
across 72 source files. Dynamic imports updated too.
- Type-only imports (`Job`, `Polka`, MessageResponse, …) converted to
`import type` to satisfy `verbatimModuleSyntax`.
- The json-loader hook registration in workflow-parser.ts picks `.ts`
when the source file exists (dev) and `.js` otherwise (compiled dist).
- Root `package.json` adds `"type": "module"` (no existing .js files
affected) and `yaml` as a devDep (already used by scripts/diff-parse.ts;
previously hoisted through cli's deps).
- `tests.yml` CI bumps from Node 22 to Node 24. Smoke fixtures that set
`node-version: 22` are left alone — they exercise `actions/setup-node`
with various versions deliberately.
Verified:
- pnpm check: clean
- Node 24 dev run: `node packages/cli/src/cli.ts --help` works
- Full smoke suite (`pnpm agent-ci-dev run --all`): 45/45 jobs pass
* fix(shutdown.test): use `node --input-type=module` instead of `npx tsx`
The shutdown integration test spawns a fresh process to sidestep
vitest's mock system. It was using `npx tsx`, but `tsx` is no longer
a dependency. Node 24 reads TypeScript files natively, so we ask Node
directly via `--input-type=module`.
Target tmux panes by captured pane ID instead of window:pane indices so
the script works regardless of the user's tmux base-index. Invoke
scripts/agent-ci-dev.sh directly instead of going through
pnpm --dir "$REPO_ROOT", so the CLI inherits DEMO_DIR as its cwd and
resolves the demo's own .github/workflows/ci.yml.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: support local reusable workflows (uses: ./.github/workflows/...)
Inline called workflow jobs into the caller's dependency graph so that
`jobs.<id>.uses` with local refs works end-to-end. Includes dependency
rewiring, smoke tests, runner seed resilience fix, boot-failure log
surfacing, and dev script improvements.
Closes#149
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update website compatibility matrix for reusable workflows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add section descriptions to website compatibility matrix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add descriptions to compatibility matrix legend items
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add 'not planned' status icon to compatibility matrix
Distinguish architectural limitations (concurrency groups, GitHub
secrets) from features that could be implemented in the future.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: support remote reusable workflows (uses: owner/repo/path@ref)
Pre-fetch remote workflow YAML from GitHub Contents API before expansion,
cache SHA refs forever and always re-fetch mutable tag/branch refs. Also
changes missing workflow files from warn+skip to hard failure.
Closes#165
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: split monolithic smoke-tests.yml into discrete workflow files
Each smoke test area now has its own workflow file for isolated failure
visibility: matrix, artifacts/services, cross-job outputs, job conditions,
reusable workflows (local + remote), and binary smoke.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style: fix formatting in .docs/ files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: clarify agent-ci-dev.sh is for local development only
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* kindling: start task
* Add marketing strategy research and synthesis
- investigation-plan.md: scope and search strategy for both tracks
- research-developer-channels.md: how CI tools gain adoption (act case study, HN, Reddit, npm, messaging)
- research-agent-discoverability.md: how AI agents discover tools (llms.txt, CLAUDE.md, MCP, training data)
- marketing-strategy.md: synthesized multi-step plan for human devs and AI agents
* Fix three evidence quality issues flagged by Critic review
- Source the 844k llms.txt adoption figure to BuiltWith tracking dashboard
(trends.builtwith.com/robots/LLMS-Text, as of Oct 25 2025); add caveat
that other methodologies (NerdyData, SE Ranking) show far lower counts
- Reword LLMs-do-not-use-llms.txt claim from tested negative to absence
of public documentation — more accurate epistemic framing
- Replace unsourced act tutorial claims with verified direct URLs: Red Hat,
BrowserStack, Microsoft Azure, LogRocket, freeCodeCamp, plus 10 dev.to
article links confirming the organic tutorial coverage
* Tighten sourcing and hedging language per Critic precision review
- HN traffic numbers: hedge 10k-100k as 'commonly estimated' with no single controlled measurement; add in-text Nebula Graph citation for 300+ stars figure
- Act HN appearances: reduce 'at least four times' to 'multiple times' (only two item IDs substantiated)
- Tutorial blog claim: 'all recommend act' softened to 'Leading tutorial blogs...recommend'
- Overnight agent commits: remove unsourced '1,000+' figure; soften to 'large batches of agent-generated commits'
- Reddit comment claim: reframe 'drives qualified signups for months' as 'can drive sustained qualified traffic'; note it reflects SEO best-practice inference, not a case study
- HN/Product Hunt 100 vs 30 comparison: add in-text citation bracket linking to Medium source
* Fix four citation issues flagged by Critic review
- Fix 1: Add inline WebProNews link to February 9, 2026 GitHub Actions outage claim (both files)
- Fix 2: Add HN item ID inline for Dagger stats (item?id=30857012)
- Fix 3: Replace 'typical' with 'commonly observed as' / 'reported in case studies'
- Fix 4: Generalize act fork/dependent stats with link to current repo instead of bare numbers
* Update strategy with Apr 7-9 tweet learnings and revised positioning
The Apr 7 "Running GitHub Actions locally" tweet hit 78K impressions —
revealing that the universal developer pain point is the primary hook,
not the AI agent angle. This updates the strategy doc with performance
data, a revised positioning funnel (hook → explain → differentiate →
convert), updated HN draft, and new action items. Adds tweet tracking
for the Apr 7-9 thread.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Add tweet queue with 8 drafts following screenshot-first formula
Each tweet follows the pattern that drove 78K impressions on Apr 7:
one-line hook, terminal screenshot, no AI-agent lead. Covers dirty
tree, speed comparison, retry, git hooks, service containers, matrix
strategy, quiet mode, and act comparison. Includes posting order and
cadence recommendations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: action tarball disk cache, step output capture, and demo recording
- Cache action tarballs on first download and serve from disk on re-runs,
eliminating ~30s GitHub CDN delays
- Capture step output via tee to signals dir for reliable pause-on-failure
tail display
- Fix CLI to treat empty results as failure and skip summary print
- Add marketing demo recording setup with VHS tape and test project
- Add `agent-ci` script alias in root package.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: add tests for action tarball cache, group filtering, and empty-results fix (#119)
Cover the untested changes from the tarball cache PR: action tarball proxy
cache hit/miss, download info URL rewriting with sub-path stripping, step
output group filtering, tee output capture, and CLI empty-results exit logic.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent concurrent tarball cache-miss race condition
Use an in-flight download map so concurrent requests for the same
tarball coalesce into a single GitHub fetch instead of racing on
the same tmp file, which could cause corruption or rename errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use relative path in demo.tape for portability
Replace hard-coded absolute path with a relative path so the demo
recording works on any contributor's machine.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: correct sanitized-refs test to assert 404 for slash-containing refs
The test was passing vacuously (status >= 200 matches 404). Now it
properly asserts that Polka does not bind :ref across slashes, so
slash-containing refs return 404 and do not serve cached content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(website): add blog section with first post
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(website): integrate blog section with routing and styles
* Add lock file.
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a VHS-based terminal recording that demonstrates the core agent-ci
workflow: pause on failure, fix the bug, retry the failed step.
The demo uses tmux split panes to show fixing code in one pane while
agent-ci is paused in the other. The tape auto-resets state on each
recording for easy re-recording.
No changeset needed — no packages/ code changed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>