Skip to content

feat(ci): track merged core PRs for the opencode v2 rewrite - #15134

Merged
kirillk merged 3 commits into
mainfrom
shiny-grove
Oct 16, 2026
Merged

kirillk merged 3 commits into
mainfrom
shiny-grove

Conversation

@kirillk

@kirillk kirillk commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Issue

No issue. This is internal CI tooling for the opencode v2 rewrite; the tracking issues it creates are the artifacts, not the motivation for this PR.

What Problem This Solves

opencode v2 is a rewrite, so Kilo v1 fixes and features do not carry over automatically. The pr-track-v1 skill records what the behavior was and why it mattered in enough detail that a v2 agent can confirm v2 already covers it or implement it from scratch. The problem is that it only ran when a human remembered to invoke it after a merge, so the v2 port backlog depended on memory.

Why This Change Was Made

A merged PR that carries a Kilo-specific change to packages/opencode/ now files its own [v2-port] tracking issue in Kilo-Org/kilocode, assigned to the original PR author.

The gate is deterministic, so most merges never reach the model: a PR qualifies only when its diff touches a kilocode-named path under packages/opencode/, or adds a kilocode_change marker line in a packages/opencode/ file. That is the same signal the annotations check already enforces, so upstream merges, formatting, and dependency bumps are excluded for free.

The agent that writes the issue is steered by untrusted PR text — titles, bodies, diffs, and review comments from any contributor — while the job holds org secrets. So it runs with no GitHub token and no shell: the workflow pre-fetches the PR metadata and diff, and a deterministic script performs every GitHub mutation after validating the draft. Prompt injection can at worst produce a misleading issue body, which a human reviews.

Changes:

  • v2-port-tracker.yml runs on pull_request_target: closed (path-filtered to packages/opencode/**) plus workflow_dispatch for replays, and always checks out the base branch tip, never the PR head ref.
  • Permissions are explicit denies rather than --auto. An inherited ask default is auto-rejected headlessly and aborts the whole run (run.ts:1032-1039), whereas an explicit deny returns a tool error the agent can recover from. bash, network, task, external_directory, and the memory/recall tools are denied, and edit is scoped to v2-port-out/**.
  • The skill is vendored to .kilo/skills/pr-track-v1/SKILL.md so the interactive /pr-track-v1 command and CI share one source of truth; CI-only differences (author assignment, no gh, no interaction) live in prompt.md.
  • Issue creation is idempotent by marker (<!-- v2-port:pr-<N> -->), so a re-run updates rather than duplicates.
  • An assignee without repo access (external contributor, bot) leaves the issue unassigned with a ::warning::, rather than failing the run.
  • docs-sync/lib.mjs gains an optional outDir on runKilo so the two bots do not share an artifact tree.

User Impact

No end-user impact; this is CI-only. Reviewers get one core-v1-changes-port issue per qualifying merge instead of relying on someone remembering to run the skill, and every issue carries a paste-ready Prompt For V2 Agent block. Merged PRs can opt out with a no-v2-port label.

Screenshots / Video

N/A - no visual changes. The change is a GitHub Actions workflow and Node scripts.

How to Test

Manual/local verification

Agent-verified:

  • node .github/v2-port/gate.test.mjs — 25 tests passed. Includes end-to-end runs of the real gate.mjs against a stubbed gh and a stubbed GitHub API: a qualifying PR writes pr.json/pr.diff and reports qualifies=true; an unmarked shared-file change reports qualifies=false with a reason; a bot-authored PR is skipped before any diff fetch.
  • node .github/v2-port/issue.test.mjs — 22 tests passed. Drives the real issue.mjs against a local stub of the GitHub API via the DOCS_SYNC_API_BASE hook, so dedup, label ensure, assignee resolution, and comment idempotency are exercised as real code. Covers: one issue created with label/assignee plus back-link, dedup on re-run, unassignable author left unassigned with a warning, existing comment patched in place, skip.txt short-circuits without any API call, an invalid draft fails without creating anything, and dry run mutates nothing.
  • node .github/docs-sync/model-config.test.mjs and node .github/docs-sync/selftest.mjs — all cases passed, confirming the runKilo outDir change does not regress docs-sync.
  • bun run script/check-workflows.ts — ok (39 workflows).
  • bun run script/check-opencode-annotations.ts --worktree — all shared upstream changes annotated.
  • bun run script/check-md-table-padding.ts — 387 files checked, no padded tables.
  • bunx oxlint .github/v2-port — 0 warnings, 0 errors.

Reviewer test steps

  1. Dry-run the workflow against any already-merged PR that touched packages/opencode/:
    gh workflow run v2-port-tracker.yml -f pr_number=<N> -f dry_run=true
  2. Confirm the run summary reports qualifies or a skip reason, and that the draft is printed without creating anything.
  3. Re-run with dry_run=false, then run it a third time and confirm the second and third runs report the PR as already tracked rather than filing duplicates.

Blocked checks and substitute verification

  • A live end-to-end run (steps 1-3 above) was not executed, because no GitHub token with workflow-dispatch access is available in this environment. Substitute verification is the stub-API integration coverage in issue.test.mjs, which exercises the real create/dedup/assign/comment code paths, plus the stub-gh end-to-end coverage in gate.test.mjs.

Evidence

  • node .github/v2-port/gate.test.mjs: passed (25 tests) — agent.
  • node .github/v2-port/issue.test.mjs: passed (22 tests) — agent.
  • node .github/docs-sync/model-config.test.mjs: passed — agent.
  • node .github/docs-sync/selftest.mjs: passed, all cases — agent.
  • bun run script/check-workflows.ts: passed — agent.
  • bun run script/check-opencode-annotations.ts --worktree: passed — agent.
  • bun run script/check-md-table-padding.ts: passed — agent.
  • bunx oxlint .github/v2-port: passed, 0 warnings — agent.
  • Live workflow dispatch: not run (no token); see the blocked-check note above.

Dependency

Requires the repo secrets KILO_API_KEY and KILO_ORG_ID, both already present for docs-sync. KILO_ORG_ID is required, or the gateway bills the key owner's personal balance. Optional repo variables V2_PORT_MODEL (default kilo/anthropic/claude-sonnet-4.6) and V2_PORT_VARIANT (default high) override the model.

Checklist

  • Issue linked above, or exception explained
  • Tests/verification described
  • Screenshots/video included for visual changes, or marked N/A
  • Changeset considered for user-facing changes
  • I personally reviewed the diff and can explain the changes, including any AI-assisted work.

Get in Touch

No changeset: CI-only change, nothing user-facing.

Changes

  • Adds the v2-port-tracker workflow and its .github/v2-port/ scripts (gate, prompt, issue writer, tests, README).
  • Vendors the pr-track-v1 skill into .kilo/skills/pr-track-v1/.
  • Adds runKilo's optional outDir in .github/docs-sync/lib.mjs.
  • Adds v2-port-tracker.yml to the script/check-workflows.ts allowlist.

Kilo v1 fixes and features do not carry over to the opencode v2 rewrite
automatically, and the `pr-track-v1` skill that records them only ran when a
human remembered to invoke it. This automates that: a merged PR carrying a
Kilo-specific change to packages/opencode/ now files its own tracking issue.

The gate is deterministic, so upstream merges, formatting, and dependency
bumps never reach the model. Only PRs that touch a `kilocode`-named opencode
path or add a `kilocode_change` marker line qualify.

The agent that writes the issue is steered by untrusted PR text, so it runs
with no GitHub token and no shell: the workflow pre-fetches the PR metadata
and diff, and a deterministic script performs every GitHub mutation after
validating the draft. Permissions are explicit denies rather than `--auto`,
because an inherited `ask` default is auto-rejected headlessly and aborts the
run, while an explicit `deny` is a recoverable tool error.

The skill is vendored into the repo so the interactive command and CI share
one source of truth; CI-only differences live in the prompt file.
Comment thread .github/workflows/v2-port-tracker.yml
Comment thread .github/v2-port/prompt.md Outdated
Comment thread .github/docs-sync/lib.mjs Outdated
@kilo-code-bot

kilo-code-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

The only change since the previous review at 34daa5c is the deletion of the internal implementation plan .kilo/plans/1792092987367-v2-port-tracker-workflow.md; no executable code changed. The three earlier findings remain resolved at the current HEAD: the track job checkout sets persist-credentials: false (.github/workflows/v2-port-tracker.yml:85), gate.mjs writes the documented gh pr view --json payload via readPr (.github/v2-port/gate.mjs:115-133), and the unused runKilo(outDir) parameter was removed so .github/docs-sync/lib.mjs is no longer part of the diff.

Files Reviewed (9 files)
  • .github/v2-port/README.md
  • .github/v2-port/gate.mjs
  • .github/v2-port/gate.test.mjs
  • .github/v2-port/issue.mjs
  • .github/v2-port/issue.test.mjs
  • .github/v2-port/prompt.md
  • .github/workflows/v2-port-tracker.yml
  • .kilo/skills/pr-track-v1/SKILL.md
  • script/check-workflows.ts
Previous Review Summaries (2 snapshots, latest commit 34daa5c)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 34daa5c)

Status: No Issues Found | Recommendation: Merge

The three findings from the previous review are resolved at the current HEAD: the track job checkout now sets persist-credentials: false (with a workflow regression test), gate.mjs now writes the real gh pr view --json payload the prompt documents (readPr with the author/mergedAt/url shape plus commits, reviews, comments, closingIssuesReferences), and the unused runKilo(outDir) parameter was removed so .github/docs-sync/lib.mjs is back to its original behavior.

Files Reviewed (9 files)
  • .github/docs-sync/lib.mjs
  • .github/v2-port/README.md
  • .github/v2-port/gate.mjs
  • .github/v2-port/gate.test.mjs
  • .github/v2-port/issue.mjs
  • .github/v2-port/issue.test.mjs
  • .github/v2-port/prompt.md
  • .github/workflows/v2-port-tracker.yml
  • .kilo/plans/1792092987367-v2-port-tracker-workflow.md

Previous review (commit 71f96c3)

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
.github/workflows/v2-port-tracker.yml 81 actions/checkout persists the workflow token into .git/config, so the agent workspace is not credential-free despite the README's "no GH_TOKEN" containment claim
.github/v2-port/prompt.md 9 Describes pr.json as gh pr view --json shape, but gate.mjs:125 writes the raw REST GET /repos/{repo}/pulls/{n} payload (no commits/reviews/comments/closingIssuesReferences, uses user/merged_at/html_url)

SUGGESTION

File Line Issue
.github/docs-sync/lib.mjs 240 New outDir parameter has no caller; the doc comment claims the v2-port tracker passes it, but the workflow shells out to kilo directly
Files Reviewed (11 files)
  • .github/docs-sync/lib.mjs - 1 issue
  • .github/v2-port/README.md
  • .github/v2-port/gate.mjs
  • .github/v2-port/gate.test.mjs
  • .github/v2-port/issue.mjs
  • .github/v2-port/issue.test.mjs
  • .github/v2-port/prompt.md - 1 issue
  • .github/workflows/v2-port-tracker.yml - 1 issue
  • .kilo/plans/1792092987367-v2-port-tracker-workflow.md
  • .kilo/skills/pr-track-v1/SKILL.md
  • script/check-workflows.ts

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 45K · Output: 5.5K · Cached: 233.2K

Review guidance: REVIEW.md from base branch main

Keep the PR-steered agent away from the workflow token by disabling checkout credential persistence, and provide the complete gh pr view metadata shape the tracking skill expects. Remove the unused docs-sync outDir change and stale artifact claims called out in review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants