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
36 changes: 36 additions & 0 deletions .github/workflows/pickled.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Pickled

on:
pull_request:
workflow_dispatch:
inputs:
max_cells:
description: "Abort real-agent runs above this execution count"
required: false
default: "12"

jobs:
deterministic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bunx @pickled-dev/cli test .
- run: bunx @pickled-dev/cli check . --plan
- run: bunx @pickled-dev/cli build . --plan

real-agent:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bunx @pickled-dev/cli check . --max-cells "${PICKLED_MAX_CELLS:-12}"
env:
PICKLED_MAX_CELLS: ${{ inputs.max_cells }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY_PICKLED }}
- run: bunx @pickled-dev/cli build . --max-cells 2
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY_PICKLED }}
32 changes: 32 additions & 0 deletions fixtures/pickled/prq-config.solution.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
diff --git a/.prqrc.json b/.prqrc.json
new file mode 100644
index 0000000..8afcd43
--- /dev/null
+++ b/.prqrc.json
@@ -0,0 +1,9 @@
+{
+ "repos": ["caiopizzol/prq", "caiopizzol/moor"],
+ "staleDays": 5,
+ "filters": ["!draft:true", "!label:wontfix"],
+ "actions": {
+ "review": "./scripts/prq-review.sh {url}",
+ "checkout": "gh pr checkout {number} --repo {owner}/{repo}"
+ }
+}
diff --git a/scripts/prq-review.sh b/scripts/prq-review.sh
new file mode 100755
index 0000000..f7b8931
--- /dev/null
+++ b/scripts/prq-review.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+if [ $# -lt 1 ]; then
+ echo "PR URL is required" >&2
+ exit 1
+fi
+
+url="$1"
+
+claude "/review ${url}"
17 changes: 17 additions & 0 deletions fixtures/pickled/prq-config/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Create a project-level prq configuration.

The workspace should end with:

- `.prqrc.json`
- `scripts/prq-review.sh`

The config should:

- watch `caiopizzol/prq` and `caiopizzol/moor`
- set `staleDays` to `5`
- set filters to `!draft:true` and `!label:wontfix`
- define `review` as `./scripts/prq-review.sh {url}`
- define `checkout` as `gh pr checkout {number} --repo {owner}/{repo}`

The script should accept a PR URL as its first argument and run Claude Code
with `/review <url>`.
38 changes: 38 additions & 0 deletions fixtures/pickled/prq-config/tests/verify-prq-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail

test -f README.md
test -f .prqrc.json
test -f scripts/prq-review.sh
test -x scripts/prq-review.sh

if grep -R "npm install -g prq\\|bun add -g prq" .prqrc.json scripts >/dev/null; then
echo "uses the wrong prq package name" >&2
exit 1
fi

bun -e '
const fs = require("fs");
const cfg = JSON.parse(fs.readFileSync(".prqrc.json", "utf8"));

if (!Array.isArray(cfg.repos)) throw new Error("repos must be an array");
for (const repo of ["caiopizzol/prq", "caiopizzol/moor"]) {
if (!cfg.repos.includes(repo)) throw new Error(`missing repo ${repo}`);
}
if (cfg.staleDays !== 5) throw new Error("staleDays must be 5");
if (!Array.isArray(cfg.filters)) throw new Error("filters must be an array");
for (const filter of ["!draft:true", "!label:wontfix"]) {
if (!cfg.filters.includes(filter)) throw new Error(`missing filter ${filter}`);
}
if (!cfg.actions || typeof cfg.actions !== "object") throw new Error("actions missing");
if (cfg.actions.review !== "./scripts/prq-review.sh {url}") {
throw new Error("review action must call the helper with {url}");
}
if (cfg.actions.checkout !== "gh pr checkout {number} --repo {owner}/{repo}") {
throw new Error("checkout action must use gh pr checkout with template variables");
}
'

grep -Fq "claude" scripts/prq-review.sh
grep -Fq "/review" scripts/prq-review.sh
grep -Fq '"$1"' scripts/prq-review.sh
180 changes: 180 additions & 0 deletions pickled.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# yaml-language-server: $schema=https://pickled.dev/schema/pickled.schema.json

schemaVersion: 2

product:
name: prq
description: Developer attention CLI for GitHub PRs, GitHub issues, and Linear tickets.

sources:
cli_readme: { path: ./apps/cli/README.md }

agents:
quick:
provider: claude-code
model: claude-haiku-4-5
maxTurns: 5
builder:
provider: claude-code
model: claude-haiku-4-5
maxTurns: 30

contexts:
given_cli_readme: { mode: inject, source: cli_readme }

facts:
install_and_auth:
statement: Installs prq from npm and requires an authenticated GitHub CLI.
match:
allOf: ["npm install -g prq-cli", "GitHub CLI", "gh"]
anyOf: ["authenticated", "gh to be authenticated"]
linear_optional:
statement: Says Linear support is optional through LINEAR_API_KEY.
match:
allOf: ["LINEAR_API_KEY", "Optional"]
status_modes:
statement: Shows the queue in interactive, plain text, and JSON modes.
match:
allOf: ["prq", "prq --no-interactive", "prq status --json"]
action_commands:
statement: Names the built-in PR action commands.
match:
allOf: ["prq review", "prq open", "prq nudge"]
categories:
statement: Names the main work categories prq reports.
match:
allOf: ["Needs Re-review", "Requested", "Stale", "Your PRs Waiting"]
in_progress:
statement: Explains that started PRs appear in an In Progress group.
match:
allOf: ["In Progress"]
anyOf: ["mark as started", "Start/Stop"]
filters:
statement: Shows filter syntax and the supported filter keys.
match:
allOf: ["--filter", "label:priority", "type:pr", "source:linear"]
config_order:
statement: Explains global config, project config, and CLI flag precedence.
match:
allOf: ["~/.config/prq/config.json", ".prqrc.json", "CLI flags"]
custom_actions:
statement: Explains custom action templates in .prqrc.json.
match:
allOf: [".prqrc.json", "actions", "{url}", "{number}"]
actions_takeover:
statement: Says actions can run interactive tools because they take over the terminal.
match:
allOf: ["full terminal control"]
anyOf: ["suspends its TUI", "interactive tools"]
skill_install:
statement: Shows how to install the Claude Code skill.
match:
allOf: ["prq skill", "prq skill --global"]
skill_action_reuse:
statement: Says the Claude skill reads .prqrc.json actions and otherwise opens the browser.
match:
allOf: [".prqrc.json actions", "falls back to opening the browser"]

misstatements:
wrong_package:
statement: Installs the wrong npm package name.
match:
anyOf: ["npm install -g prq@latest", "bun add -g prq"]
linear_required:
statement: Claims Linear is required for prq to work.
match:
anyOf: ["Linear is required", "requires Linear"]
config_replaces_cli:
statement: Claims config overrides CLI flags.
match:
anyOf: ["config overrides CLI flags", "CLI flags have the lowest priority"]
only_browser_actions:
statement: Claims custom actions can only open browser URLs.
match:
anyOf: ["only open browser", "browser-only actions"]

questions:
- id: first_run
question: How do I install prq and run my first queue check?
agents: [quick]
contexts: [given_cli_readme]
expects: [install_and_auth, linear_optional, status_modes, action_commands]
rejects: [wrong_package, linear_required]
examples:
pass:
- "Install with `npm install -g prq-cli`. prq needs the GitHub CLI (`gh`) to be authenticated. LINEAR_API_KEY is optional for Linear. Run `prq`, `prq --no-interactive`, or `prq status --json`, then act with `prq review`, `prq open`, or `prq nudge`."
fail:
- "Install with `npm install -g prq@latest`. Linear is required before the command can show anything."

- id: queue_categories
question: What do the main prq queue categories mean?
agents: [quick]
contexts: [given_cli_readme]
expects: [categories, in_progress]
examples:
pass:
- "prq groups work as Needs Re-review, Requested, Stale, and Your PRs Waiting. PRs you mark as started show in an In Progress group."
fail:
- "prq only sorts work by repository name and has no in-progress state."

- id: filters_and_config
question: How do I configure default repos, filters, and stale-day behavior?
agents: [quick]
contexts: [given_cli_readme]
expects: [filters, config_order]
rejects: [config_replaces_cli]
examples:
pass:
- "Use filters like `--filter label:priority`, `--filter type:pr`, and `--filter source:linear`. Config loads from `~/.config/prq/config.json`, then `.prqrc.json`, then CLI flags."
fail:
- "Put filters in config because config overrides CLI flags and CLI flags have the lowest priority."

- id: custom_actions
question: How do I make prq dispatch a review to Claude Code or another command?
agents: [quick]
contexts: [given_cli_readme]
expects: [custom_actions, actions_takeover]
rejects: [only_browser_actions]
examples:
pass:
- "Add actions in `.prqrc.json`, such as `review: claude '/review {url}'`. Templates can use `{url}` and `{number}`. Actions run with full terminal control, so interactive tools can take over."
fail:
- "Custom actions only open browser URLs and cannot run shell commands."

- id: claude_skill
question: How do I install and use the prq Claude Code skill?
agents: [quick]
contexts: [given_cli_readme]
expects: [skill_install, skill_action_reuse]
examples:
pass:
- "Run `prq skill` in a project or `prq skill --global`. The skill reads `.prqrc.json actions`; if no review action is configured it falls back to opening the browser."
fail:
- "There is no prq skill command. Claude Code cannot reuse `.prqrc.json` actions."

builds:
- id: create_project_prq_config
goal: >-
Create a project-level `.prqrc.json` and a `scripts/prq-review.sh`
helper. The config should watch `caiopizzol/prq` and
`caiopizzol/moor`, set staleDays to 5, filter out drafts and
wontfix-labeled work, define a review action that runs the helper with
`{url}`, and define a checkout action using `gh pr checkout {number}
--repo {owner}/{repo}`. The helper should accept the PR URL as its first
argument and run Claude Code with `/review <url>`.
agents: [builder]
contexts: [given_cli_readme]
trials: 2
workspace:
path: ./fixtures/pickled/prq-config
verifier:
failToPass:
- { name: prq config, run: ./tests/verify-prq-config.sh }
passToPass:
- { name: keeps fixture instructions, run: test -f README.md }
referenceSolution:
patch: ./fixtures/pickled/prq-config.solution.patch

thresholds:
questions: 80
builds: 80
Loading