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
2 changes: 1 addition & 1 deletion .agents/skills/versioned-tool/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ This project manages external CLI tools through a **single-source-of-truth versi
| Systematic | `DEFAULT_SYSTEMATIC_VERSION` | `systematic-version` | `npm` (`@fro.bot/systematic`) |
| OpenCode (harness base) | `base_version` in `packages/harness/harness.config.json` | _(internal only — config-JSON, not a TS constant)_ | `github-releases` (`anomalyco/opencode`) |

**Release-job coupled sites (not Renovate-tracked):** `DEFAULT_OPENCODE_VERSION` and the workspace `ARG OPENCODE_VERSION` hold the harness build version (`<base>+harness.<sha>`); the Dockerfile ARG default stays this V1 harness build, and V2 is selected by build-arg instead. Renovate cannot order SemVer build-metadata tags, so both are bumped together by `harness-release.yaml`'s `sync-default-version` job at publish time (one auto-PR, dual-source idempotency guard). Do not add Renovate `customManager` entries for these — they would be dropped. **V2 pin:** the JSON file's `version` is Renovate-tracked, but its per-asset digests are not; after a bump, run `node scripts/sync-opencode-v2-pin.ts` and commit the result (see `deploy/README.md` § OpenCode V2). See `docs/solutions/best-practices/cross-libc-build-and-release-safety-2026-06-14.md` §4 and `docs/solutions/workflow-issues/harness-base-version-source-of-truth-2026-06-12.md`.
**Release-job coupled sites (not Renovate-tracked):** `DEFAULT_OPENCODE_VERSION` and the workspace `ARG OPENCODE_VERSION` hold the harness build version (`<base>+harness.<sha>`); the Dockerfile ARG default stays this V1 harness build, and V2 is selected by build-arg instead. Renovate cannot order SemVer build-metadata tags, so both are bumped together by `harness-release.yaml`'s `sync-default-version` job at publish time (one auto-PR, dual-source idempotency guard). Do not add Renovate `customManager` entries for these — they would be dropped. **V2 pin:** Renovate bumps the JSON file's `version`; its per-asset digests are not Renovate-tracked, so the rule's `postUpgradeTasks` run `bun run postupgrade` (`scripts/sync-opencode-v2-pin.ts`) to regenerate them on the update branch. Any command added there must match the runner's `allowedCommands` (see `scripts/renovate-v2-pin-postupgrade.test.ts`; `node scripts/...` is not allowed). See `deploy/README.md` § OpenCode V2. See `docs/solutions/best-practices/cross-libc-build-and-release-safety-2026-06-14.md` §4 and `docs/solutions/workflow-issues/harness-base-version-source-of-truth-2026-06-12.md`.

## Quick Start

Expand Down
21 changes: 14 additions & 7 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@
{
// Tracks the stock OpenCode V2 pin. The Dockerfile's `opencode-v2` stage and the Action's
// installOpenCode both read this file. Bumping `version` alone leaves the per-asset sha256
// digests stale, and both consumers fail closed on that: the digests are regenerated by
// `scripts/sync-opencode-v2-pin.ts` (see the packageRules entry below).
// digests stale, and both consumers fail closed on that: the packageRules entry below regenerates
// the digests on the update branch with `bun run postupgrade` (scripts/sync-opencode-v2-pin.ts).
customType: 'regex',
managerFilePatterns: ['/packages\\/runtime\\/src\\/shared\\/opencode-v2-pin\\.json/'],
matchStrings: ['"version":\\s*"(?<currentValue>\\d+\\.\\d+\\.\\d+)"'],
Expand Down Expand Up @@ -164,16 +164,23 @@
// The V2 pin lives in its own file and follows its own major, so the V1 cap above does not
// apply to it. This entry must stay AFTER that cap (a later rule wins) and must not become the
// first `anomalyco/opencode` rule with `allowedVersions`: pin-invariants.test.ts reads the cap
// from the first one. The pin PR cannot pass CI as Renovate opens it, because the per-asset
// digests still describe the old version; prBodyNotes tells the reviewer how to fix that.
// from the first one.
//
// Renovate only changes `version`; the per-asset sha256 digests still describe the old release, and the
// Dockerfile and the Action both fail closed on that. `bun run postupgrade` (scripts/sync-opencode-v2-pin.ts)
// rewrites the digests from the release's SHA256SUMS on the update branch. A rule-level `postUpgradeTasks`
// REPLACES the top-level one rather than merging with it, so the full list is repeated here on purpose, with
// the sync between install and build. Every command must match the self-hosted runner's `allowedCommands`
// (pinned by scripts/renovate-v2-pin-postupgrade.test.ts); `node scripts/...` is not allowed there.
matchFileNames: ['packages/runtime/src/shared/opencode-v2-pin.json'],
matchPackageNames: ['anomalyco/opencode'],
allowedVersions: '/^2\\./',
commitMessageTopic: 'OpenCode V2 pin',
automerge: false,
prBodyNotes: [
'This only bumps `version`. Regenerate the sha256 digests before merging: `node scripts/sync-opencode-v2-pin.ts`, then commit `packages/runtime/src/shared/opencode-v2-pin.json`. CI builds the V2 workspace image against the new pin.',
],
postUpgradeTasks: {
commands: ['bun install --ignore-scripts', 'bun run postupgrade', 'bun run build'],
executionMode: 'branch',
},
},
{
// Cap Bun at 1.4.4. The build gate requires an exact match with upstream
Expand Down
2 changes: 1 addition & 1 deletion STRUCTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ fro-bot/agent/
- **`deploy/plugins/`**, **`deploy/managed-config/`** — the baked OpenCode reuse-guard plugin (`no-task-reuse.mjs`) and the root-owned managed config (`/etc/opencode/opencode.json`) that loads it; plain Node ESM / JSON, tested from `deploy/scripts/*.test.mjs`. The same `no-task-reuse.mjs` is the single source for the Action's guard: `tsdown.config.ts` builds it into `dist/no-task-reuse.js`, and `src/services/setup/no-task-reuse-config.ts` copies it into the CI OpenCode config dir at every Action server start (`no-task-reuse.d.mts` types it for the Vitest suite).
- **`deploy/scripts/`** — Plain Node ESM (`.mjs`) helpers for deploy-time operations (auth validation, config merge, protected-dir creation, legacy checkout ownership migration, agent-side config provisioning, V2 plugin install and image smoke); uses `node --test`, not Vitest.
- **`deploy/tests/`** — `isolation-harness.sh`, the CI acceptance harness that proves the service/agent uid boundary in a real container started with production's security posture.
- **`scripts/`** — Repo-level build tooling: action dist builder, hidden-Unicode scrubber, third-party notices, release dispatch, and `sync-opencode-v2-pin.ts` (regenerates the OpenCode V2 pin's digests on a Renovate bump).
- **`scripts/`** — Repo-level build tooling: action dist builder, hidden-Unicode scrubber, third-party notices, release dispatch, and `sync-opencode-v2-pin.ts` (regenerates the OpenCode V2 pin's digests; Renovate runs it as `bun run postupgrade`).
- **`evals/`** — Gated agent-outcome eval corpus that runs the real execution path against disposable fixture repos; the pure gate and baseline tests run in normal CI, while live scenarios require `FRO_BOT_EVAL=1`.
- **`.github/workflows/`** — All CI/CD automation; 12 workflow files covering tests, releases, security scanning, and bot triggers.
- **`RFCs/`** — 19 architecture specification documents; read before making cross-cutting changes.
Expand Down
8 changes: 4 additions & 4 deletions deploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -570,14 +570,14 @@ A major of 2 or higher selects the V2 path; the value must equal the pin's `vers

**Paired deploy.** Deploy a gateway that includes the V2 run loop (#1985) before the V2 workspace, or together with it, from the same ref. A gateway without that loop runs the V1 loop against a V2 server, which is unsafe. A V2-capable gateway in front of a V1 workspace is safe. The shared control-API token requirement above applies to both.

**Bumping the pin.** Renovate opens a PR that changes only `version` (major 2 only; no automerge). Regenerate the digests before merging:
**Bumping the pin.** Renovate opens the PR (major 2 only; no automerge). It changes `version`, then its post-upgrade tasks run `bun run postupgrade` (`scripts/sync-opencode-v2-pin.ts`), which rewrites every asset digest from the release's `SHA256SUMS`, before the build. The PR already carries matching digests. To run the same step by hand:

```bash
node scripts/sync-opencode-v2-pin.ts # rewrite the digests from the release's SHA256SUMS
node scripts/sync-opencode-v2-pin.ts --check # exit 1 if the file disagrees with upstream
bun scripts/sync-opencode-v2-pin.ts # rewrite the digests from the release's SHA256SUMS
bun scripts/sync-opencode-v2-pin.ts --check # exit 1 if the file disagrees with upstream
```

Commit the updated `opencode-v2-pin.json`. The **Workspace Image Smoke Test** CI job builds the image against the pin, starts it with no network, and fails on a stale digest.
The **Workspace Image Smoke Test** CI job builds the image against the pin, starts it with no network, and fails on a stale digest.

**Revert.** Before switching, record the digests of the running workspace and gateway images. To revert, redeploy those previous workspace and gateway images by digest. Rebuilding an older ref does not reproduce the same digests.

Expand Down
2 changes: 1 addition & 1 deletion deploy/workspace.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ WORKDIR /app
# in the form <base>+harness.<sha>. Bumped in lockstep with the action default
# by the harness-release workflow; merge the auto-PR to advance both surfaces.
ARG OPENCODE_VERSION=1.19.4+harness.5bde2635
ARG SYSTEMATIC_VERSION=3.27.2
ARG SYSTEMATIC_VERSION=3.28.0

# System packages come from the base image's Alpine 3.24 branch and are not
# pinned: the branch index drops older versions, so exact pins would break the
Expand Down
2 changes: 1 addition & 1 deletion dist/artifact-BIg7elxR.js → dist/artifact-C0wQlV2Q.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/main.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/post.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"dist:escape-hidden-unicode": "node --experimental-strip-types scripts/escape-dist-hidden-unicode.ts",
"fix": "bun run --filter @fro-bot/runtime fix && bun run --filter @fro-bot/action fix && bun run --filter @fro.bot/harness fix && bun run --filter @fro.bot/opencode-plugin fix && bun run --filter @fro-bot/gateway fix && bun run --filter @fro-bot/workspace-agent fix",
"postinstall": "simple-git-hooks",
"postupgrade": "bun scripts/sync-opencode-v2-pin.ts",
"lint": "bun run --filter @fro-bot/runtime lint && bun run --filter @fro-bot/action lint && bun run --filter @fro.bot/harness lint && bun run --filter @fro.bot/opencode-plugin lint && bun run --filter @fro-bot/gateway lint && bun run --filter @fro-bot/workspace-agent lint && bun run dist:check-hidden-unicode && bun run check:md-links",
"test": "bun run --filter @fro-bot/runtime test && bun run --filter @fro-bot/action test && bun run --filter @fro-bot/workspace-agent test && bun run --filter @fro.bot/harness test && bun run --filter @fro.bot/opencode-plugin test && bun run --filter @fro-bot/gateway test && bun run test:evals",
"evals:baseline:update": "bun run evals/update-baseline.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const DEFAULT_MODEL = {
// releases, checksum-verified, and fail-closed on mismatch — no silent stock fallback.
// FALLBACK_VERSION (in opencode.ts) is the plain stock base used when latest-fetch fails.
export const DEFAULT_OPENCODE_VERSION = '1.19.4+harness.5bde2635'
export const DEFAULT_SYSTEMATIC_VERSION = '3.27.2'
export const DEFAULT_SYSTEMATIC_VERSION = '3.28.0'

// Systematic for OpenCode V2. 3.27.x loads on both V1 and V2, so the V2 path installs DEFAULT_SYSTEMATIC_VERSION too
// and there is no separate V2 pin. The plugin id is the `id` of the object the package's default export carries
Expand Down
Loading
Loading