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
9 changes: 9 additions & 0 deletions .github/actions/e2b-provider/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: E2B helper cache
description: Restore the input-addressed E2B helper builds that scripts/build-e2b-provider.sh reuses.
runs:
using: composite
steps:
- uses: actions/cache@v6
with:
path: ~/.oac/cache/e2b-provider
key: e2b-provider-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('services/core/tools/e2b-provider/**', 'LICENSE', 'scripts/build-e2b-provider.sh') }}
25 changes: 25 additions & 0 deletions .github/actions/mcode-companion/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: MiniMax companion
description: Restore the pinned MiniMax companion into $RUNNER_TEMP/minimax-runtime, building it only when its inputs change.
runs:
using: composite
steps:
- id: cache
uses: actions/cache@v6
with:
path: ${{ runner.temp }}/minimax-runtime
key: mcode-harness-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('packages/mcode-harness/**', 'scripts/build-mcode-harness.sh') }}
- if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
source_repository="$(node -p 'require("./packages/mcode-harness/source.json").repository')"
source_revision="$(node -p 'require("./packages/mcode-harness/source.json").revision')"
source_version="$(node -p 'require("./packages/mcode-harness/source.json").version')"
git init --quiet "$RUNNER_TEMP/mcode-source"
git -C "$RUNNER_TEMP/mcode-source" remote add origin "$source_repository"
git -C "$RUNNER_TEMP/mcode-source" fetch --depth 1 origin "$source_revision"
git -C "$RUNNER_TEMP/mcode-source" checkout --detach FETCH_HEAD
npm install --prefix "$RUNNER_TEMP/mcode-native" --no-audit --no-fund --include=optional --install-strategy=nested "@minimax-ai/code@$source_version"
MCODE_NATIVE_SOURCE="$RUNNER_TEMP/mcode-source" \
MCODE_CLI_DIR="$RUNNER_TEMP/mcode-native/node_modules/@minimax-ai/code" \
MCODE_HARNESS_BUILD_DIR="$RUNNER_TEMP/minimax-runtime" \
bash scripts/build-mcode-harness.sh
2 changes: 2 additions & 0 deletions .github/actions/node/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ runs:
with:
path: ${{ steps.store.outputs.path }}
key: pnpm-v1-${{ runner.os }}-${{ runner.arch }}-node${{ inputs.node-version }}-10.30.3-${{ hashFiles(inputs.lockfiles) }}
# The store is content-addressed; another lockfile's store still supplies shared packages.
restore-keys: pnpm-v1-${{ runner.os }}-${{ runner.arch }}-node${{ inputs.node-version }}-10.30.3-
2 changes: 2 additions & 0 deletions .github/workflows/api-acceptance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ jobs:
run: |
python services/core/tests/official_client.py
go test ./services/core/internal/store -run '^(TestFunctionStateOfficialClientReadsAndLiveEvents|TestSavedReferenceRetryOfficialClient|TestAgentUpdateOfficialClient|TestAgentDeletionOfficialClient|TestSessionAgentFilterOfficialClient|TestSessionDeletionOfficialClient|TestEnvironmentInitialFailureOfficialClient|TestSelfHostedInitialCreationOfficialClient|TestSelfHostedCancellationOfficialClient|TestSelfHostedFunctionsOfficialClient|TestSelfHostedSteeringOfficialClient)$' -count=1
- uses: ./.github/actions/e2b-provider
if: inputs.container
- name: Verify the distribution's Core image
if: inputs.container
env:
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/cache-warm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: cache-warm

# Caches saved on main are the only ones every pull request and release tag can
# restore. This builds the input-addressed caches; it runs no tests.
on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: cache-warm
cancel-in-progress: false

jobs:
companion:
strategy:
fail-fast: false
matrix:
include:
- runner: blacksmith-2vcpu-ubuntu-2204
github-runner: ubuntu-22.04
- runner: macos-15
github-runner: macos-15
runs-on: ${{ vars.OAC_USE_GITHUB_RUNNERS == 'true' && matrix.github-runner || matrix.runner }}
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/node
with:
node-version: '22.22.0'
lockfiles: |
packages/claude-sdk-adapter/pnpm-lock.yaml
packages/mcode-harness/package-lock.json
- run: pnpm --dir packages/claude-sdk-adapter fetch
- uses: ./.github/actions/mcode-companion

linux:
runs-on: ${{ vars.OAC_USE_GITHUB_RUNNERS == 'true' && 'ubuntu-22.04' || 'blacksmith-2vcpu-ubuntu-2204' }}
timeout-minutes: 15
steps:
- uses: actions/checkout@v7
- uses: ./.github/actions/node
with:
lockfiles: '**/pnpm-lock.yaml'
- name: Fetch every pnpm lockfile into the store
run: git ls-files '*pnpm-lock.yaml' | while read -r lockfile; do pnpm --dir "$(dirname "$lockfile")" fetch; done
- uses: ./.github/actions/e2b-provider
- name: Build the E2B helper
run: E2B_PROVIDER_BUILD_DIR="$RUNNER_TEMP/e2b-provider" bash scripts/build-e2b-provider.sh
16 changes: 2 additions & 14 deletions .github/workflows/native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,9 @@ jobs:
rm -rf "$RUNNER_TEMP/claude-runtime/node_modules"
pnpm --dir "$RUNNER_TEMP/claude-runtime" install --prod --frozen-lockfile --config.node-linker=hoisted --ignore-scripts
npm install --prefix "$RUNNER_TEMP/native-tools" --no-save @openai/codex@0.153.4
- name: Build the pinned MiniMax companion on Unix
- name: Restore or build the pinned MiniMax companion on Unix
if: runner.os != 'Windows'
run: |
source_repository="$(node -p 'require("./packages/mcode-harness/source.json").repository')"
source_revision="$(node -p 'require("./packages/mcode-harness/source.json").revision')"
source_version="$(node -p 'require("./packages/mcode-harness/source.json").version')"
git init --quiet "$RUNNER_TEMP/mcode-source"
git -C "$RUNNER_TEMP/mcode-source" remote add origin "$source_repository"
git -C "$RUNNER_TEMP/mcode-source" fetch --depth 1 origin "$source_revision"
git -C "$RUNNER_TEMP/mcode-source" checkout --detach FETCH_HEAD
npm install --prefix "$RUNNER_TEMP/mcode-native" --no-audit --no-fund --include=optional --install-strategy=nested "@minimax-ai/code@$source_version"
MCODE_NATIVE_SOURCE="$RUNNER_TEMP/mcode-source" \
MCODE_CLI_DIR="$RUNNER_TEMP/mcode-native/node_modules/@minimax-ai/code" \
MCODE_HARNESS_BUILD_DIR="$RUNNER_TEMP/minimax-runtime" \
bash scripts/build-mcode-harness.sh
uses: ./.github/actions/mcode-companion
- name: Package and exercise CLI-only installation, additions and reuse
id: package
run: |
Expand Down
17 changes: 10 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ jobs:
path: ${{ runner.temp }}/native-artifacts
- name: Assemble the native installation catalog
run: node scripts/build-native-catalog.mjs "$RUNNER_TEMP/native-artifacts" "$RUNNER_TEMP/native-installers"
- uses: ./.github/actions/e2b-provider
- name: Build matched artifacts
env:
OAC_NATIVE_INSTALLER_BUILD_DIR: ${{ runner.temp }}/native-installers
Expand All @@ -134,13 +135,6 @@ jobs:
done
cp deploy/install.sh "$HOME/.oac/build/release-upload/install.sh"
(cd "$HOME/.oac/build/release-upload" && sha256sum install.sh > install.sh.sha256)
- uses: actions/upload-artifact@v6
with:
name: core-release-${{ steps.source.outputs.revision }}
path: ~/.oac/build/release-upload/*
compression-level: 0
if-no-files-found: error

- name: Sign in to GHCR
if: github.event_name == 'push' || inputs.draft_release
env:
Expand All @@ -150,6 +144,7 @@ jobs:
echo "DOCKER_CONFIG=$DOCKER_CONFIG" >> "$GITHUB_ENV"
printf '%s' "$GHCR_TOKEN" | docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
- name: Publish the version tag or create a manual draft
id: publish
if: github.event_name == 'push' || inputs.draft_release
env:
GH_TOKEN: ${{ github.token }}
Expand All @@ -161,3 +156,11 @@ jobs:
- name: Remove registry credentials
if: always() && (github.event_name == 'push' || inputs.draft_release)
run: rm -f "$RUNNER_TEMP/oac-release-docker/config.json"
# Recovering a failed publication reuses these exact assets.
- uses: actions/upload-artifact@v6
if: (failure() && steps.publish.outcome == 'failure') || (success() && steps.publish.outcome == 'skipped')
with:
name: core-release-${{ steps.source.outputs.revision }}
path: ~/.oac/build/release-upload/*
compression-level: 0
if-no-files-found: error
6 changes: 3 additions & 3 deletions docs/maintainers.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ The distribution combines the three Harness images into one Runtime image (`depl
make build-e2b-provider
```

Docker builds the Linux amd64 helper with the pinned CPython and Debian 12 image. The Python dependency closure, including PyInstaller, is hash-locked in `services/core/tools/e2b-provider/requirements.lock`; no E2B account key is needed. Set `E2B_PROVIDER_BUILD_DIR` for another output directory and `E2B_SOURCE_REVISION` when building from an exported source tree. The output is `oac-e2b-provider-linux-amd64.tar.gz` with its `.sha256`; it extracts to `oac-e2b-provider/` with the executable, `_internal/`, `licenses/`, `requirements.lock` and `manifest.json`. The Core image uses that tree; the host needs a compatible glibc and CA certificates, not Python.
Docker builds the Linux amd64 helper with the pinned CPython and Debian 12 image. The Python dependency closure, including PyInstaller, is hash-locked in `services/core/tools/e2b-provider/requirements.lock`; no E2B account key is needed. Set `E2B_PROVIDER_BUILD_DIR` for another output directory. The build is a pure function of the helper sources, `LICENSE` and the build script, so it is cached under `~/.oac/cache/e2b-provider/` by their hash and rebuilt only when they change. The output is `oac-e2b-provider-linux-amd64.tar.gz` with its `.sha256`; it extracts to `oac-e2b-provider/` with the executable, `_internal/`, `licenses/`, `requirements.lock` and `manifest.json`. The Core image uses that tree; the host needs a compatible glibc and CA certificates, not Python.

**microsandbox helper.** Linux only, with a C compiler:

Expand Down Expand Up @@ -124,7 +124,7 @@ git push origin v1.2.3

Tags use `vMAJOR.MINOR.PATCH`, optionally with a prerelease suffix such as `-rc.1` and build metadata such as `+build.1`. A prerelease suffix creates a GitHub prerelease. Pushing the tag is the release decision. Automated checks establish build and test results, not real-model qualification: assess live execution evidence before you push the tag. Model credentials and private certificate authorities never enter CI or release inputs, including acceptance images that contain them.

The workflow runs `check` on the tagged commit, including the full local gate, official-client and image acceptance, and the native matrix with its packaging artifacts enabled. After checks succeed, one `build` job on GitHub-hosted `ubuntu-22.04` prepares the pinned Runtime inputs, reuses the native installers, builds the distribution and publishes directly from its local files. This combined job has `contents: write` and `packages: write`; checkout does not persist credentials. It retains an uncompressed Actions artifact before publication for recovery, without downloading that artifact again during normal publication.
The workflow runs `check` on the tagged commit, including the full local gate, official-client and image acceptance, and the native matrix with its packaging artifacts enabled. After checks succeed, one `build` job on `blacksmith-4vcpu-ubuntu-2204` prepares the pinned Runtime inputs, reuses the native installers, builds the distribution and publishes directly from its local files. This combined job has `contents: write` and `packages: write`; checkout does not persist credentials. It retains the assets as an uncompressed Actions artifact only when publication fails, for recovery, or when a manual build does not publish.

Distribution and Runtime archives use `pigz` level 6 with at most four compression workers and no filename or timestamp in the gzip header. The publisher verifies archive and native installer checksums, resolves the repository identity, refuses an existing Release or draft for the tag and creates one draft with a fixed ID. Up to four assets upload concurrently, largest first, without retries. After confirming the complete remote inventory, the publisher validates all image archives and existing registry tags before pushing up to four images concurrently. Each image config and registry manifest is verified; any error leaves the Release unpublished. In-flight transfers finish before a failed operation returns. The publisher rechecks the version tag before publishing the draft by its ID.

Expand Down Expand Up @@ -156,7 +156,7 @@ With `draft_release=true` the result is an unpublished `build-<full SHA>` draft

## Continuous integration

Every PR runs `core-check` and reports the required status `check`. Main uses GitHub branch protection requiring this check and an up-to-date branch before merging, so merging does not start another copy of the test suite. Changes must enter through checked PRs; an administrator bypass does not establish CI success. Main pushes publish the website when its inputs change. Version tags and manual release builds run the full release gate at their exact source commit. `scripts/ci_plan.py` owns the only input-to-check map. Component rules require both a matching directory or script prefix and a matching file suffix; exact dependency, workflow and shared build inputs have explicit rules. Rules accumulate across shared consumers and mixed changes. Paths with no matching build/test rule run hygiene only. Add the corresponding rule when introducing a new component, language, build input or resource location.
Every PR runs `core-check` and reports the required status `check`. Main uses GitHub branch protection requiring this check and an up-to-date branch before merging, so merging does not start another copy of the test suite. Changes must enter through checked PRs; an administrator bypass does not establish CI success. Main pushes publish the website when its inputs change and run `cache-warm`, which builds the MiniMax companion, the E2B helper and the pnpm store without running tests, because only caches saved on main can be restored by every PR and release tag. Version tags and manual release builds run the full release gate at their exact source commit. `scripts/ci_plan.py` owns the only input-to-check map. Component rules require both a matching directory or script prefix and a matching file suffix; exact dependency, workflow and shared build inputs have explicit rules. Rules accumulate across shared consumers and mixed changes. Paths with no matching build/test rule run hygiene only. Add the corresponding rule when introducing a new component, language, build input or resource location.

The planner compares the PR event's tested merge commit with its verified first parent. NUL-delimited Git output and disabled rename detection retain both old and new paths. The plan and reasons appear in the run summary. Missing or inconsistent history, mismatched checkouts, invalid paths, planner/orchestration changes and shared build inputs select the full gate. A verified empty diff selects hygiene only. Release, manual and explicit-ref calls always select every group.

Expand Down
Loading
Loading