# The scenario tracks (harness/scenarios.mjs): agents doing a day's git # work through the MCP server. Each run costs model usage, so this never # runs on a push or a pull, only when the owner asks for it by name: # # knotless rerun knotless://chadtmiller.com/knotless --ref refs/heads/main \ # --workflow scenarios [-e TRACKS="team solo"] [-e SCENARIO_MODEL=...] # # TRACKS names the tracks, all of them but `ci` by default: its runner # needs Docker, which a run's container does not have. The report is the # end of the log; the check passes whatever the agents tripped on, and # fails only when the tracks could not run. # # The agents are Claude Code sessions, on whichever credentials the # runner's secrets file on the host grants main: ANTHROPIC_API_KEY (the # API), CLAUDE_CODE_OAUTH_TOKEN (a subscription, from `claude # setup-token`), or OPENROUTER_API_KEY, which goes through OpenRouter # instead and is used first when granted. SCENARIO_MODEL picks the model, # through OpenRouter any it has (-e SCENARIO_MODEL=openai/gpt-5), though # Claude Code is made for Anthropic's. image: rust:1.98 on: asked: {refs: [refs/heads/main]} secrets: [ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, OPENROUTER_API_KEY] cache: [target, /usr/local/cargo/registry, /usr/local/rustup, /opt/node, /opt/atproto, harness/node_modules] env: TRACKS: contribution mentions moderation owners private review revert solo team # As test.yml's, for the tracks that need the spaces alpha. ATPROTO_COMMIT: 11c5d98cd50261c5e1201fedc5c6c05a7b8d1ccf ALPHA_BUILD: "2" steps: - uses: chadtmiller.com/steps/node@1 with: {version: 24.22.1} - name: claude run: | export PATH=/opt/node/bin:$PATH [ -x /opt/node/bin/claude ] || npm install -g --no-audit --no-fund @anthropic-ai/claude-code claude --version - uses: chadtmiller.com/steps/npm-ci@1 name: harness with: {dir: harness, omit: dev} - name: spaces alpha run: | case " $TRACKS " in *" private "*) ;; *) exit 0 ;; esac [ "$(cat /opt/atproto/.built 2>/dev/null)" = "$ATPROTO_COMMIT $ALPHA_BUILD" ] && exit 0 export PATH=/opt/node/bin:$PATH COREPACK_ENABLE_DOWNLOAD_PROMPT=0 COREPACK_HOME=/opt/atproto/.corepack find /opt/atproto -mindepth 1 -delete cd /opt/atproto git init -q . && git fetch -q --depth 1 https://github.com/bluesky-social/atproto.git "$ATPROTO_COMMIT" && git checkout -q FETCH_HEAD mkdir .bin && corepack enable --install-directory /opt/atproto/.bin export PATH=/opt/atproto/.bin:$PATH pnpm install --frozen-lockfile --ignore-scripts pnpm run build:tooling --force pnpm --filter '@atproto/dev-env^...' --filter @atproto/dev-env run --if-present prebuild pnpm exec tsc --build packages/dev-env/tsconfig.build.json pnpm --filter @atproto/oauth-provider-ui run build:ui cd "$(dirname "$(node -p "require.resolve('better-sqlite3/package.json', { paths: ['/opt/atproto/packages/pds'] })")")" [ -f build/Release/better_sqlite3.node ] || npm run install echo "$ATPROTO_COMMIT $ALPHA_BUILD" > /opt/atproto/.built - name: build run: cargo build -q --workspace --bins - name: scenarios # Tracks go side by side, each step of one a session of up to 20 # minutes, in turn. timeout: 240 run: | export PATH=/opt/node/bin:$PATH KNOTLESS_SPACES_DEV_ENV=/opt/atproto/packages/dev-env # OpenRouter speaks Claude Code's own protocol; the Anthropic key # must be empty, not unset, or it is tried first. if [ -n "${OPENROUTER_API_KEY:-}" ]; then export ANTHROPIC_BASE_URL=https://openrouter.ai/api ANTHROPIC_AUTH_TOKEN=$OPENROUTER_API_KEY ANTHROPIC_API_KEY= fi rm -rf target/scenarios node harness/scenarios.mjs $TRACKS cat target/scenarios/*/report.md