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
16 changes: 8 additions & 8 deletions .github/workflows/shipyard-reviewer.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Shipyard Cloud Reviewer reviewing itself. It uses the last released major rather
# than executing code from the pull request under review.
# Shipyard Cloud Reviewer reviewing itself. Use an audited immutable revision,
# never code from the pull request under review.
name: Shipyard Cloud Reviewer

on:
Expand All @@ -24,19 +24,19 @@ concurrency:
jobs:
review:
if: >-
vars.LLM_BASE_URL != '' &&
vars.LLM_MODEL != '' &&
vars.OPENROUTER_REVIEWER_ENABLED == 'true' &&
((github.event_name == 'pull_request_target' &&
!startsWith(github.event.pull_request.head.ref, 'shipyard/issue-')) ||
(github.event_name == 'repository_dispatch' && github.event.action == 'shipyard-review') ||
(github.event.issue.pull_request && contains(github.event.comment.body, '@shipyard')))
runs-on: shipyard-runners
steps:
- uses: dymoo/shipyard@v3
- uses: dymoo/shipyard@efec252b39c55bc3d902d14d59286660046f9776
with:
api-key: ${{ secrets.LLM_API_KEY }}
base-url: ${{ vars.LLM_BASE_URL }}
model: ${{ vars.LLM_MODEL }}
api-key: ${{ secrets.OPENROUTER_REVIEWER_API_KEY }}
base-url: https://openrouter.ai/api/v1
model: deepseek/deepseek-v4.1-flash
reasoning-effort: max
handoff-token: ${{ secrets.SHIPYARD_HANDOFF_TOKEN }}
instructions: |
This action has no runtime dependencies. Any import that is not
Expand Down
8 changes: 6 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,12 @@ The review action's public inputs are exactly `api-key`, `base-url`, `model`,
When omitted, reasoning effort uses the provider default; an explicit validated
value is sent unchanged. The released `dymoo/shipyard@v3` reference does not
accept this new input; consumers must pin a supporting immutable revision until
it is released. The self-review workflow remains on `@v3` and omits it. When
its base URL is exactly OpenRouter, the shared client adds the fixed public app
it is released. The self-review workflow pins a supporting immutable revision
and selects `deepseek/deepseek-v4.1-flash` with explicit `max` effort. Its dedicated
`OPENROUTER_REVIEWER_API_KEY` is separate from the Coder's `LLM_API_KEY`;
`OPENROUTER_REVIEWER_ENABLED` must be `true` only after that key and the existing
hand-off secret are configured. The generic `@v3` examples remain unchanged.
When its base URL is exactly OpenRouter, the shared client adds the fixed public app
attribution headers `HTTP-Referer: https://github.com/dymoo/shipyard` and
`X-OpenRouter-Title: Shipyard`, plus one `session_id` derived from the opaque
GitHub workflow-run identifier to keep provider prompt caches sticky. It never
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,20 @@ image and `npm test`, because that command uses only Node's built-in test
runner. A consumer whose Agent Brief declares another test command must publish
an image containing that toolchain and use its immutable digest.

This repository's own reviewer pilot uses `deepseek/deepseek-v4.1-flash`
through OpenRouter with explicit `max` reasoning and a supporting immutable
action revision. It
uses a dedicated `OPENROUTER_REVIEWER_API_KEY`, not the Coder's `LLM_API_KEY`.
Keep its `OPENROUTER_REVIEWER_ENABLED` Variable absent or `false` until the new
key and existing `SHIPYARD_HANDOFF_TOKEN` are configured; set it to `true` to
activate, and clear it before removing or rotating either secret. The reviewer
key must allow only this model and retain strict ZDR/no-training routing with
both OpenRouter input/output logging options off and an owner-selected spending
cap. Account/member guardrails can further restrict it; key creation does not
prove model eligibility. Verify an actual review after activation. Coder model
variables and credentials remain unchanged. These pilot settings do not change
the configurable, released-version workflow examples above.

Use `dymoo/shipyard/cloud-coder@v4` in the copied workflow. Both actions must
receive the same `SHIPYARD_HANDOFF_TOKEN`; Shipyard uses it only to sign and
verify context-bound HMAC hand-offs, never stores it in the dispatch payload,
Expand Down
17 changes: 0 additions & 17 deletions test/cloud-coder-action.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,6 @@ test('the Shipyard pilot workflow routes only ready Issues through a pinned Node
assert.match(example, /github\.event\.issue\.state == 'open'/);
});

test('the Shipyard reviewer pilot targets the dedicated ARC scale set', () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 low · convention

Reviewer-pilot test deleted instead of repinning its gate and runner guards

This deletion removes the file's only reviewer-pilot guard while the sibling Coder-pilot test kept directly above (lines 44-55) still pins exactly the same properties: the readiness Variable vars.SHIPYARD_CODER_READY == 'true' and runs-on: shipyard-runners. Of the deleted assertions only the two vars.LLM_BASE_URL/vars.LLM_MODEL matches went stale — the workflow name, the dedicated runner label and the example-workflow gates are all still true. Repin rather than delete: swap the stale matches for vars.OPENROUTER_REVIEWER_ENABLED == 'true' and keep the rest, so a later change of the reviewer's runner label or activation gate fails a test.

Verifier: The diff deletes lines 65-80, the only reviewer-pilot test, which pinned .github/workflows/shipyard-reviewer.yml's activation gate and its dedicated runs-on: shipyard-runners, plus the example/README guards; the retained sibling Coder test (lines 44-55) still pins the analogous Coder gate and runner (lines 50, 53) and AGENTS.md states Cloud Reviewer runs on the dedicated shipyard-runners label, so the runner/name guards remain live properties and should have been repinned (swapping only the

Shipyard Cloud Reviewer

const workflow = fs.readFileSync(new URL('../.github/workflows/shipyard-reviewer.yml', import.meta.url), 'utf8');
assert.match(workflow, /^name: Shipyard Cloud Reviewer$/m);
assert.match(workflow, /runs-on: shipyard-runners/);
assert.match(workflow, /vars\.LLM_BASE_URL != ''/);
assert.match(workflow, /vars\.LLM_MODEL != ''/);

const example = fs.readFileSync(new URL('../examples/workflows/shipyard-reviewer.yml', import.meta.url), 'utf8');
assert.match(example, /vars\.LLM_BASE_URL != ''/);
assert.match(example, /vars\.LLM_MODEL != ''/);

const readme = fs.readFileSync(new URL('../README.md', import.meta.url), 'utf8');
assert.match(readme, /Do \*\*not\*\* create a reviewer-only workflow from this README/);
assert.match(readme, /`setup-shipyard`/);
assert.doesNotMatch(readme, /^## Add Shipyard Cloud Reviewer$/m);
});

test('dispatches only when ready-for-agent labels an Issue', (t) => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'shipyard-coder-event-'));
const eventPath = path.join(dir, 'event.json');
Expand Down
Loading