Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.github/workflows/*.lock.yml linguist-generated=true merge=ours
11 changes: 11 additions & 0 deletions .github/mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"mcpServers": {
"github-agentic-workflows": {
"command": "gh",
"args": [
"aw",
"mcp-server"
]
}
}
}
51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: CI
on:
push:
pull_request:
permissions:
contents: read
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Typecheck
run: npm run typecheck

- name: Test
run: npm test

integration-test:
runs-on: ubuntu-latest
needs: build-test
steps:
- uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Integration test
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
run: |
if [ -z "${COPILOT_GITHUB_TOKEN:-}" ]; then
echo "Skipping integration tests: COPILOT_GITHUB_TOKEN is not available."
else
npm run test:integration
fi
26 changes: 26 additions & 0 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: "Copilot Setup Steps"

# This workflow configures the environment for GitHub Copilot Agent with gh-aw MCP server
on:
workflow_dispatch:
push:
paths:
- .github/workflows/copilot-setup-steps.yml

jobs:
# The job MUST be called 'copilot-setup-steps' to be recognized by GitHub Copilot Agent
copilot-setup-steps:
runs-on: ubuntu-latest

# Set minimal permissions for setup steps
# Copilot Agent receives its own token with appropriate permissions
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install gh-aw extension
uses: github/gh-aw-actions/setup-cli@v0.77.5
with:
version: v0.77.5
1,532 changes: 1,532 additions & 0 deletions .github/workflows/daily-rig-sampler.lock.yml

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions .github/workflows/daily-rig-sampler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
name: Daily Rig Sampler
description: >
Each day, pick one rig sample (cached round-robin) from src/samples/,
run it with the rig skill, analyze harness performance, and apply one
focused quick-win improvement to skills/rig/rig.ts in a new draft PR.
on:
schedule: daily
workflow_dispatch:
permissions:
contents: read
actions: read
issues: read
pull-requests: read
engine: copilot
strict: true
timeout-minutes: 30
tools:
github:
mode: gh-proxy
toolsets: [default]
bash: ["*"]
edit:
cache-memory: true
network:
allowed: [defaults, github, node]
safe-outputs:
create-pull-request:
title-prefix: "[rig-sampler] "
labels: [automation, ai-agent]
draft: true
reviewers: [copilot]
allowed-files:
- "skills/rig/rig.ts"
---

## Task

You are improving the rig TypeScript harness one focused change at a time.

### Step 1 — Pick the next sample (cached round-robin)

1. Run `ls src/samples/` to list all sample files sorted alphabetically.
2. Open the cache-memory file `/tmp/gh-aw/cache-memory/last-sample.json`.
- If it does not exist, start from the first file.
- Otherwise read the `lastFile` field and advance to the next file in the sorted list (wrapping around).
3. Write `{"lastFile": "<chosen-file>"}` back to `/tmp/gh-aw/cache-memory/last-sample.json`.
4. Note the chosen sample file path, e.g. `src/samples/05-write-readme-intent.ts`.

### Step 2 — Install dependencies and run the sample

1. Run `npm install` in the repository root to ensure all dependencies are present.
2. Run the chosen sample through the rig skill launcher:
```
node skills/rig/rig.ts <chosen-sample-path> 2>&1
```
Capture both stdout (the agent's structured JSON output) and stderr (JSONL event lines prefixed with `rig.copilot-ask`).
3. Record the full output for analysis.

### Step 3 — Analyze harness performance

With the captured run output, evaluate:

- **Did it succeed?** Did the agent return valid JSON matching the declared output schema, or did it fail?
- **Repair turns**: Count how many times the harness had to retry due to invalid JSON or schema violations (`rig.copilot-ask` events with `turns > 1`).
- **Turn count and latency**: Note total turns from the JSONL events.
- **Schema fit**: Did the sample's output schema feel too loose (e.g. plain `s.string` where a structured type would help) or too strict (repair loops due to enum mismatches)?
- **Error messages**: Were any error messages unclear or unhelpful?
- **API ergonomics**: Was there anything awkward in how the sample had to express its intent — boilerplate that a helper could eliminate, or a missing convenience on `p.*` or `s.*`?

### Step 4 — Read rig.ts

Read `skills/rig/rig.ts` in full to understand the current implementation.

### Step 5 — Identify one quick-win improvement

Based on your analysis of the actual run, identify **exactly one** small, self-contained improvement to `skills/rig/rig.ts`.

Good categories (pick the one most directly supported by the run evidence):
- A missing `s.*` schema helper that would simplify sample code or prevent a repair loop.
- A clearer error message surfaced during repair or schema validation.
- A JSDoc comment on a public export that is currently undocumented.
- A small type-safety improvement (stricter overload, narrower generic).
- A minor performance or usability tweak with no behaviour change.

Do **not** change the public API in a breaking way. Keep the change small and reviewable.

### Step 6 — Apply the improvement

Edit `skills/rig/rig.ts` to implement the improvement. Use the `edit` tool.

### Step 7 — Create a pull request

Emit a `create-pull-request` output with:
- `title`: one-line description of the improvement (no prefix needed — it is added automatically).
- `body`: explain which sample was run, what the run revealed (repair turns, output quality, etc.), and why this change improves the harness.
- `branch`: `rig-sampler/<chosen-sample-basename>` (e.g. `rig-sampler/05-write-readme-intent`).
107 changes: 107 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Release

on:
workflow_dispatch:
inputs:
release_type:
description: "Release type"
required: true
type: choice
options:
- patch
- minor
- major

jobs:
release:
runs-on: ubuntu-latest
# Only run on the origin repo (not forks)
if: github.repository == 'pelikhan/rig'
permissions:
contents: write

steps:
- name: Check actor permission
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.actor,
});
const level = perm.permission;
if (level !== 'admin' && level !== 'maintain') {
core.setFailed(`Actor ${context.actor} has permission '${level}', which is insufficient. Admin or maintain required.`);
}

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- name: Use Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Typecheck
run: npm run typecheck

- name: Compute next version
id: semver
run: |
# Get the latest semver tag (vX.Y.Z), default to v0.0.0 if none exists
LAST_TAG=$(git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-version:refname | head -n 1)
if [ -z "$LAST_TAG" ]; then
LAST_TAG="v0.0.0"
fi
echo "Last tag: $LAST_TAG"

# Strip leading 'v'
VERSION="${LAST_TAG#v}"
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)

RELEASE_TYPE="${{ github.event.inputs.release_type }}"
case "$RELEASE_TYPE" in
major)
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
;;
minor)
MINOR=$((MINOR + 1))
PATCH=0
;;
patch)
PATCH=$((PATCH + 1))
;;
esac

NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
echo "New tag: $NEW_TAG"
echo "tag=$NEW_TAG" >> "$GITHUB_OUTPUT"

- name: Create and push tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "${{ steps.semver.outputs.tag }}"
git push origin "${{ steps.semver.outputs.tag }}"

- name: Create GitHub Release
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: '${{ steps.semver.outputs.tag }}',
name: '${{ steps.semver.outputs.tag }}',
generate_release_notes: true,
});
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"github.copilot.enable": {
"markdown": true
}
}
61 changes: 61 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# AGENTS.md

## Project Overview

Rig is a minimal TypeScript agent harness. The core runtime (`skills/rig/rig.ts`) provides declarative agent construction with typed input/output shapes, prompt intents, and a Copilot SDK runtime.

## Architecture

```
skills/rig/rig.ts — Core runtime (agent, p, copilotEngine, schemas)
skills/rig/samples/ — 51 sample agents demonstrating patterns
src/engines/copilot.test.ts — Copilot engine unit tests (vitest)
src/rig.test.ts — Unit tests (vitest)
scripts/run-sample.test.ts — Sample runner with a stub Copilot SDK client (dry-run)
skills/rig/SKILL.md — Framework reference docs
```

All imports use the `"rig"` path alias (resolved via tsconfig paths + vitest alias). `copilotEngine` is exported directly from `rig` for client construction.

## Commands

| Task | Command |
|------|---------|
| Typecheck | `npm run typecheck` |
| Unit tests | `npm test` |
| Run samples (stub) | `npm run sample` |
| Run single sample (stub) | `RIG_SAMPLE=02 npm run sample` |
| Run a sample for real | `echo "<input>" \| node skills/rig/rig.ts <program-file>` (`npm run sample:run`) |

## Code Style

- Keep the core (`skills/rig/rig.ts`) self-contained; `@github/copilot-sdk` is imported directly in `skills/rig/rig.ts`
- Minimal comments; code should be self-explanatory
- Use `node:` prefix for Node.js built-in imports
- Types are colocated with the module that defines them, not in separate `.d.ts` files
- Trailing underscore on object keys (`key_`) means optional field
- Do not add legacy compatibility bridges; update callers, samples, and docs to the current API

## Testing

- Framework: vitest
- Tests live in `src/rig.test.ts` (agent definition, invocation, validation, and prompt intent coverage)
- Stub the Copilot SDK client with `vi.mock("@github/copilot-sdk", ...)`
- All unit tests must pass before committing
- Samples run via a stub Copilot SDK client that synthesizes shape-conforming output from the prompt's `<output_schema>` block

## Key Concepts

- **Shape descriptors**: JS values used as type exemplars (e.g., `""` = string, `0` = number, `[""]` = string array). Promoted to schemas via `SchemaLike`.
- **Schema helpers (`s.*`)**: `s.string`, `s.number`, `s.boolean`, `s.unknown`, `s.array`, `s.object`, `s.record`, `s.enum`, `s.optional`
- **Prompt intents (`p.*`)**: `p.bash(cmd)`, `p.read(path)`, `p.write(path, content)` — declarative placeholders resolved into prompt instructions, not executed in-process
- **Prompts**: `p\`...\`` template tag composes instructions with inline `p.*` helpers
- **Runtime transport**: Copilot SDK sessions are created by the harness; use launcher `--server` to switch to stdio transport.
- **Repair**: built-in addon re-prompts on parse/validation failure up to `maxTurns`, and other addons can still steer retry prompts.

## Sample guide

- `20-issue-reproducer.ts` — chained diagnosis, fix planning, and review
- `36-subagent-delegation.ts` — focused-agent delegation
- `47-prompt-intents.ts` — prompt intent primitives
- `50-end-to-end-release-agent.ts` — end-to-end release workflow orchestration
Loading
Loading