From 49bca7ac29b48b71f719699c5ab5271196186d21 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Wed, 2 Sep 2026 10:24:51 -0600 Subject: [PATCH 1/4] feat: add reusable OpenCode runner --- .github/workflows/opencode.yml | 111 +++++++++++++++++++++++++++++++++ README.md | 29 +++++++++ 2 files changed, 140 insertions(+) create mode 100644 .github/workflows/opencode.yml diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml new file mode 100644 index 0000000..4232c61 --- /dev/null +++ b/.github/workflows/opencode.yml @@ -0,0 +1,111 @@ +name: opencode + +on: + workflow_call: + inputs: + config-source-path: + description: Path in the caller repository containing agents/ and skills/ + required: true + type: string + secrets: + KIMI_API_KEY: + description: Kimi provider credential for the OpenCode runner + required: true + +permissions: {} + +jobs: + opencode: + permissions: + contents: write + pull-requests: write + issues: write + runs-on: ubuntu-24.04 + steps: + - name: Checkout caller repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 1 + persist-credentials: false + + - name: Stage OpenCode runner configuration + env: + CONFIG_DIR: ${{ runner.temp }}/opencode-config + CONFIG_SOURCE_PATH: ${{ inputs.config-source-path }} + run: | + set -euo pipefail + source_dir="$GITHUB_WORKSPACE/$CONFIG_SOURCE_PATH" + test -d "$source_dir/agents" + test -d "$source_dir/skills" + rm -rf "$CONFIG_DIR" + mkdir -p "$CONFIG_DIR" + jq -n \ + --arg model "kimi-for-coding/k3" \ + --arg default_agent "makeitwork" \ + '{ + "$schema": "https://opencode.ai/config.json", + autoupdate: false, + model: $model, + default_agent: $default_agent, + enabled_providers: ["kimi-for-coding"], + provider: { + "kimi-for-coding": { + options: { + apiKey: "{env:KIMI_API_KEY}" + } + } + }, + mcp: {}, + permission: { + question: "deny", + external_directory: "deny" + } + }' > "$CONFIG_DIR/opencode.json" + cat > "$CONFIG_DIR/AGENTS.md" <<'EOF' + # GitHub Actions OpenCode runner instructions + + You are running in an ephemeral GitHub Actions runner with a checkout of + the repository that triggered this workflow. Apply that repository's + `AGENTS.md` and task-relevant documentation before editing files. + + ## Runner boundary + + - The production OpenCode server's Kubernetes MCP proxies are intentionally + not configured here. Do not assume cluster, AWS, Argo CD, Grafana, + Kubernetes, or SSH access. + - Treat secrets, tokens, decrypted values, private keys, kubeconfigs, state, + and sensitive plan output as unavailable. Never add them to repository + files, logs, issues, pull requests, or comments. + - Do not deploy, publish, merge, dispatch another workflow, or mutate a live + system. Propose such work for explicit confirmation. + - Make changes only in the checked-out repository. Do not create, push, or + open pull requests manually: `opencode github run` handles branch and pull + request delivery after the session completes. + - The workflow supplies GitHub event context and authentication. Do not claim + that an unavailable GitHub MCP or other MCP integration was used. + + ## Validation and reporting + + Use the repository's authoritative CI and guidance. Report only checks and + outcomes actually available from the workflow; distinguish authored changes + from validation, publication, deployment, and functional verification. + EOF + cp -R "$source_dir/agents" "$source_dir/skills" "$CONFIG_DIR"/ + printf 'OPENCODE_CONFIG_DIR=%s\n' "$CONFIG_DIR" >> "$GITHUB_ENV" + + - name: Install pinned OpenCode runtime + run: | + set -euo pipefail + curl -fsSL https://raw.githubusercontent.com/anomalyco/opencode/ef2880f379129aa048be9e9353e30aa168d42c17/install | + bash -s -- --version 1.18.23 --no-modify-path + printf '%s\n' "$HOME/.opencode/bin" >> "$GITHUB_PATH" + + - name: Run OpenCode + env: + GITHUB_TOKEN: ${{ github.token }} + KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} + MODEL: kimi-for-coding/k3 + MENTIONS: /opencode,/oc + SHARE: "false" + USE_GITHUB_TOKEN: "true" + run: opencode github run diff --git a/README.md b/README.md index 3913afe..d9a3fec 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,40 @@ pre-commit drift fails the `test` job and the pull request branch must be updated manually. Fork pull requests never receive secrets and always fail on drift. +### OpenCode + +The OpenCode workflow is called from a repository-local, comment-triggered +workflow. It checks out the caller repository, stages that repository's agent +and skill definitions, and runs a pinned OpenCode `1.18.23` binary. The caller +must provide the exact path that contains both `agents/` and `skills/`, grant +the listed write permissions, and pass only the Kimi credential required by the +runner. + +```yaml +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + opencode: + uses: makeitworkcloud/shared-workflows/.github/workflows/opencode.yml@ + with: + config-source-path: opencode-server/files + secrets: + KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} +``` + +Do not use `secrets: inherit`: the reusable workflow requires only +`KIMI_API_KEY`. The caller's event filter decides when the runner may execute; +the runner does not configure cluster-only MCP integrations or deploy systems. + ## Available Workflows | Workflow | Description | |----------|-------------| | `opentofu.yml` | OpenTofu/Terraform CI/CD with PR validation and an apply on every push to `main` | +| `opencode.yml` | Comment-triggered OpenCode runner for caller-supplied agent and skill definitions | Same-repository PRs run tests and a credentialed plan; fork PRs run tests only. A push to `main` runs tests followed by a fresh apply, which does not reuse the PR plan. From 73444d2177762549d8c476dc612f23811e0a2180 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Wed, 2 Sep 2026 10:35:10 -0600 Subject: [PATCH 2/4] fix: retain caller token for OpenCode delivery --- .github/workflows/opencode.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml index 4232c61..b629be5 100644 --- a/.github/workflows/opencode.yml +++ b/.github/workflows/opencode.yml @@ -26,7 +26,8 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 1 - persist-credentials: false + # opencode github run uses the caller token for its final git push. + persist-credentials: true - name: Stage OpenCode runner configuration env: From 99b9bd55dd65dbc1b8038ae2fdbdb1e1050425f3 Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Fri, 2 Oct 2026 17:42:00 -0600 Subject: [PATCH 3/4] docs: align runner branch with current workflow guidance --- README.md | 54 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index d9a3fec..570c10b 100644 --- a/README.md +++ b/README.md @@ -78,42 +78,51 @@ pre-commit drift fails the `test` job and the pull request branch must be updated manually. Fork pull requests never receive secrets and always fail on drift. -### OpenCode +### Stale pull request lifecycle -The OpenCode workflow is called from a repository-local, comment-triggered -workflow. It checks out the caller repository, stages that repository's agent -and skill definitions, and runs a pinned OpenCode `1.18.23` binary. The caller -must provide the exact path that contains both `agents/` and `skills/`, grant -the listed write permissions, and pass only the Kimi credential required by the -runner. +`tfroot-github` owns the scheduled caller at +`.github/workflows/stale-pull-requests.yml`; do not hand-maintain that path in +a consumer repository. The reusable callee is +`_stale-pull-requests.yml`. ```yaml +name: stale-pull-requests + +on: + schedule: + - cron: "17 3 * * *" + workflow_dispatch: + permissions: contents: write pull-requests: write - issues: write jobs: - opencode: - uses: makeitworkcloud/shared-workflows/.github/workflows/opencode.yml@ + stale: + uses: makeitworkcloud/shared-workflows/.github/workflows/_stale-pull-requests.yml@main with: - config-source-path: opencode-server/files - secrets: - KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} + dry-run: true ``` -Do not use `secrets: inherit`: the reusable workflow requires only -`KIMI_API_KEY`. The caller's event filter decides when the runner may execute; -the runner does not configure cluster-only MCP integrations or deploy systems. +The caller must be on the consumer's default branch for scheduled execution. +It accepts no secrets. The workflow reports only to its Actions log, and when +`dry-run` is `false`, closes non-draft, unassigned, unmilestoned pull requests +whose `pullRequest.updated_at` is at least 30 days old. Labels `do-not-close`, +`blocked`, and `security` are exempt. + +After a successful close, it deletes only an unprotected same-repository head +branch that is neither the default branch nor used as the head or base of any +open pull request. GitHub's closed-pull-request **Restore branch** path is the +recovery mechanism. Enable live mode only after a reviewed dry-run pilot. ## Available Workflows | Workflow | Description | -|----------|-------------| -| `opentofu.yml` | OpenTofu/Terraform CI/CD with PR validation and an apply on every push to `main` | -| `opencode.yml` | Comment-triggered OpenCode runner for caller-supplied agent and skill definitions | +|---|---| +| `opentofu.yml` | OpenTofu/Terraform CI/CD with PR validation and an environment-gated apply on every push to `main` | +| `_stale-pull-requests.yml` | Dry-run-first reusable lifecycle for closing pull requests inactive for at least 30 days and deleting only recoverable eligible head branches. | -Same-repository PRs run tests and a credentialed plan; fork PRs run tests only. A push to `main` runs tests followed by a fresh apply, which does not reuse the PR plan. +Same-repository PRs run tests and a credentialed plan; fork PRs run tests only. A push to `main` runs tests followed by a fresh apply, which does not reuse the PR plan. The apply job uses the caller's `environment` input (default `production`); repository owners must configure that GitHub Environment with the required protection rules. ## Runners @@ -129,5 +138,6 @@ See [images](https://github.com/makeitworkcloud/images) for container source and 1. Grant `id-token: write` in the caller workflow so GitHub OIDC can authenticate the cloud provider. 2. For AWS roots, ensure the default `aws-role-to-assume` exists (`arn:aws:iam::332355796717:role/github-actions-sops-kms`) or pass another role ARN. 3. For GCP roots, pass both `gcp-workload-identity-provider` and `gcp-service-account`; this selects Google Workload Identity Federation instead of AWS credentials. -4. Create caller workflow in `.github/workflows/`. -5. Ensure repository has required files (e.g., `Makefile` with expected targets). +4. Create the caller workflow in `.github/workflows/`. +5. Create the GitHub Environment selected by `environment` (default `production`) and configure its required reviewers and protection rules before allowing a `main` apply. +6. Ensure the repository has required files (e.g., `Makefile` with expected targets). From 87c84d0573afd0b1319b678aacc5caf9ea3f6fec Mon Sep 17 00:00:00 2001 From: Steven Welch Date: Fri, 2 Oct 2026 17:42:32 -0600 Subject: [PATCH 4/4] docs: restore OpenCode runner guide alongside current contracts --- README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/README.md b/README.md index 570c10b..8bf7181 100644 --- a/README.md +++ b/README.md @@ -115,12 +115,41 @@ branch that is neither the default branch nor used as the head or base of any open pull request. GitHub's closed-pull-request **Restore branch** path is the recovery mechanism. Enable live mode only after a reviewed dry-run pilot. +### OpenCode + +The OpenCode workflow is called from a repository-local, comment-triggered +workflow. It checks out the caller repository, stages that repository's agent +and skill definitions, and runs a pinned OpenCode `1.18.23` binary. The caller +must provide the exact path that contains both `agents/` and `skills/`, grant +the listed write permissions, and pass only the Kimi credential required by the +runner. + +```yaml +permissions: + contents: write + pull-requests: write + issues: write + +jobs: + opencode: + uses: makeitworkcloud/shared-workflows/.github/workflows/opencode.yml@ + with: + config-source-path: opencode-server/files + secrets: + KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} +``` + +Do not use `secrets: inherit`: the reusable workflow requires only +`KIMI_API_KEY`. The caller's event filter decides when the runner may execute; +the runner does not configure cluster-only MCP integrations or deploy systems. + ## Available Workflows | Workflow | Description | |---|---| | `opentofu.yml` | OpenTofu/Terraform CI/CD with PR validation and an environment-gated apply on every push to `main` | | `_stale-pull-requests.yml` | Dry-run-first reusable lifecycle for closing pull requests inactive for at least 30 days and deleting only recoverable eligible head branches. | +| `opencode.yml` | Comment-triggered OpenCode runner for caller-supplied agent and skill definitions | Same-repository PRs run tests and a credentialed plan; fork PRs run tests only. A push to `main` runs tests followed by a fresh apply, which does not reuse the PR plan. The apply job uses the caller's `environment` input (default `production`); repository owners must configure that GitHub Environment with the required protection rules.