DeepSeek retired the V4-Flash model and named the current generation
`deepseek-flash`, with no version in the name. `deepseek-v4-flash` is still
accepted, but DeepSeek documents it as a temporary compatibility name and
already serves those requests from V4.1-Flash.
The repository handed that name to users in the places most likely to be
copied: the `oma` CLI default for `provider: 'deepseek'`, the adapter JSDoc
that ships in the type declarations, the provider table in docs, the
scaffolder env template, and every DeepSeek example. A copied name that the
vendor calls temporary has an expiry date the reader cannot see.
The provider table and the adapter JSDoc also stated that `deepseek-v4-flash`
resolves to DeepSeek-V4-Flash-0731. That model is retired, so the sentence
described a routing that no longer happens.
Two corrections of the same kind travel with it. The thinking-mode note
claimed the V4 models run at `high` effort, but the adapter forwards whatever
effort the caller passes and sets none itself, so the claim is dropped rather
than restated. Three `examples/basics` headers offered `deepseek-chat`, which
DeepSeek retired outright on 2026-07-24 and which no longer resolves at all.
The release bot moves to the same name. Callers that pass an explicit model
are unaffected, and the old name keeps working for as long as DeepSeek
accepts it.
Left unchanged on purpose: `bench/config.json`, whose values are frozen
controls for an already-run benchmark; the AtlasCloud pages, whose IDs come
from that vendor's own model library; and the changelog history.
`publish.yml` decided whether a commit on main was a release by asking
whether packages/core/package.json and packages/create-oma-app/package.json
had changed at all. Those two files carry more than a version: dependency
specs, `exports`, `files`, `engines`, keywords. Any edit to either one read as
a release.
98516ce was the first commit to hit it. It only pinned dependency specs, and
neither version moved, but both manifests changed, so `detect_release_commit`
reported `is_release=true` and the publish job started. It entered the
`npm-release` environment, minted a contents:write GitHub App token, checked
out, installed, built, and then stopped at the publisher's own guard:
98516ce... is not a release commit: @open-multi-agent/core did not
increment from its first parent.
Nothing was published, tagged, or released, and the registry versions are
untouched, so the safety net did its job. But the outer gate should not have
opened. A dependency bump is the most ordinary maintenance there is, and it
should not cost a write-scoped token and a red Publish run every time.
The detection now reads the `version` field of both manifests at the release
commit and at its first parent and stops unless both moved, which is the same
fact the publisher re-derives later. A manifest that does not exist at the
release commit is a no-op rather than an error, matching what the old file
comparison concluded for the pre-monorepo tags. A manifest that exists but
declares no version fails the job, because that is a broken tree rather than
an ordinary commit.
It also closes a fail-open path found while building the check harness.
`git diff --quiet` exits 1 for "changed" and 128 for "could not run", and the
old step read both as "changed", so any git failure resolved to
`is_release=true`. Reading the version field fails closed instead. Unreachable
in practice, since checkout and the ancestry verification both run first, but
a publish gate should not lean on that.
Checked against every `v*` tag in the repository. All three tags from after
publish.yml existed — v1.16.0, v1.16.1, v1.17.0 — still detect as releases,
as do v1.8.0 through v1.10.0 and v1.13.0 through v1.15.0. v1.11.0 and v1.12.1
now report false because their tagged commits genuinely did not move both
versions; both predate this workflow, and the publisher would have refused
them for exactly that reason, so the gate now agrees with the publisher
instead of deferring the disagreement to a failed job.
A library that gets installed into someone else's backend is judged partly on
what its own install pulls down. Three changes tighten that, and two questions
turned out to need no change at all.
The line this draws is what ships. Every dependency that stays inside the
repository is now pinned to the exact version the lockfile already resolved:
all 27 devDependencies across the four workspaces, plus the private release
bot's own zod. The lockfile change is 28 spec lines with no
resolution moved, no entry added or removed, and all 61 platform-specific
entries intact. A new root .npmrc sets save-exact=true so the next one arrives
pinned rather than as a range nobody notices.
What a consumer installs keeps its range: `dependencies` in packages/core, the
only published runtime block here, every `peerDependencies`, and otel's core
compatibility range. An exact version in those blocks overrides the consumer's
own resolution and stops their `npm audit fix` from reaching a patched build
until we cut a release, which is a worse trade than the install-time drift it
prevents. save-exact will still pin a new dependency added to one of them, so
the package job now asserts all three published manifests and fails when one
is left exact, next to the assertion that already covers otel's range.
min-release-age is deliberately not set. It first shipped in npm 11.10.0, and
the CI matrix runs Node 20 and 22, which bundle npm 10.8.2 and 10.9.8. Those
two accept the key, echo it back from `npm config get`, and never act on it,
so a quarantine window would hold on one leg of the matrix while silently
doing nothing on the other two. It also has no effect on `npm ci`, which
installs the lockfile verbatim.
Every `npm ci` that installs this repository's own tree now passes
--ignore-scripts, so a compromised dependency cannot run an install hook on a
runner that holds release credentials. Only three dependencies declare a
postinstall at all, and the full lint, test, build, scaffold, and example
suites pass on a tree installed that way. The `npm install` calls that stand
in for a real consumer are deliberately left alone: their job is to reproduce
what a user's install actually does, and hardening them would make the smoke
tests prove less than they claim.
A new scheduled Supply chain audit workflow asks two questions about the
dependencies that reach a consumer, an hour before the weekly release bot so a
finding lands before the release PR is drafted. --omit=dev is the point of
running it separately: auditing the full tree reports eighteen advisories,
every one of them in test and fixture tooling that never ships, and a
permanently red job is one nobody reads. The two steps fail differently.
`npm audit` reports into the run summary, because a new upstream advisory is
not this repository misbehaving and may have no fixed version yet.
`npm audit signatures` fails, because it compares served bytes against the
registry's own signature, so a mismatch is tampering rather than churn; all
27 production packages verify today.
Two things needed no change. npm provenance is already live: publish.yml
publishes through npm trusted publishing with id-token: write, which attaches
SLSA attestations on its own, and every version since core 1.16.0, otel 0.1.2,
and create-oma-app 0.8.1 carries one. And .npmrc left .gitignore in #198
because it only restated the default registry; it comes back tracked, with the
ignore rule narrowed so a contributor's own nested .npmrc stays out.
GitHub never delivered the Friday 2026-08-28 trigger; no run record exists
for it. The daily provider canary shows why: its 03:17 UTC schedule ran
~40 minutes late through 08-26, then 10h50m late on 08-27 and 12h01m late
on 08-28. GitHub delays or drops schedules under load, and the top of the
hour is the most contended slot.
Move the trigger to :23 and update the release order documentation so the
documented time matches the workflow.
Two consecutive Friday runs failed without anyone noticing, and the one
that was noticed reported only "OMA release analysis failed." with no
cause at all. Both gaps are closed here, with the smaller defects the
same investigation surfaced.
- Name the cause when a run fails without any agent failing. A token
budget stop leaves later tasks skipped and every agent result
successful, so the message degenerated to a bare sentence and sent the
reader to the raw [OMA] progress log. It now carries the run status
with token totals, the run's error kind and flags, and every unfinished
task with its status.
- Report a failed run as a GitHub issue, opening one or commenting on the
open one. A weekly job whose only failure signal is the Actions tab is
a job nobody reads. It uses the built-in token, so it needs no App
permission and no new secret.
- Define what earns a changelog entry in the release contract. The bot
reads .github/RELEASING.md as evidence, so the rule applied by hand in
#523 and again in #543 is now applied by the bot itself.
- Retry the two synthesis tasks once, so a provider timeout or 5xx no
longer ends the run. They carry no tools and read a few thousand
tokens. The evidence tasks stay at zero because a second attempt
re-calls their tools and would trip the exactly-one-call coverage
assertion. Schema failures stay terminal either way.
- Separate comment-only diffs from behavior changes in the compatibility
auditor's instructions. It reported a JSDoc-only edit as a latency and
cost risk in #543.
- Echo the three validation commands. They dominate the step's wall clock
and produced no output at all, so a hang there was indistinguishable
from a slow model call.
The whole-run token ceiling becomes a named, validated option so the
budget-stop path is testable.
* fix(release-bot): disable thinking for synthesis agents
The release-reviewer runs with thinking effort high and maxTokens 3500. Its reasoning consumed the whole output budget (two attempts at ~3500 reasoning tokens each, empty text both times), so it never emitted the JSON releaseReviewSchema requires and structured-output validation failed after retry, failing the release closed. Disable extended thinking for the two synthesis agents (planner and reviewer) so they emit structured output directly. The two evidence agents keep high-effort thinking.
* chore: remove maintainer issue-to-PR automation
Removes the maintainer-bot, maintainer-host, maintainer-runtime, and
maintainer-harness-canary workspaces, their GitHub Actions workflows, and
their documentation. This issue-to-Draft-PR automation is removed in favor
of a local maintainer workflow.
Load a narrowly scoped AppArmor profile for /usr/bin/bwrap on Ubuntu 24.04 while preserving the global user namespace restriction and fail-closed diagnostics.
Add a read-only Claude Code and DeepSeek harness canary with deterministic validation, credential isolation, bounded artifacts, and documented promotion gates.
The live maintainer canary showed that IssueComment GraphQL actors expose the App slug without the REST [bot] suffix, causing the strict provenance check to fail after STARTED. Verify the exact Bot database ID and type across workflow and host paths while retaining REST identity and editor checks.
* ci(release-smoke): verify the published OTel adapter against the released core
@open-multi-agent/otel rides its own version track and carries no git tag, so
the post-publish smoke test covered core and create-oma-app but never otel.
Add an otel-consumer job that reads the otel version from the release commit,
installs it alongside the released core in a clean consumer, asserts npm
resolved the core we just published rather than quietly falling back to an
older one the dependency range still allows, and exports a span through
createOtelTraceSink.
When otel did not change in a release, its version is already live from an
earlier one and the job still proves the pairing holds against the new core.
* docs(release): document the three-package release process
The repository publishes three packages with independent version tracks, a
fixed publish order, and template pins that must move with the core version.
None of that was written down, so it had to be reconstructed from package
manifests, git tags, and the workflows each time.
Record what ships, the ordered steps and why each depends on the previous one,
what a release commit must contain, and what CI proves before merge versus what
release-smoke proves after publish.
* docs(agents): sharpen the architecture map and link the release guide
Replace the per-area entry point table with the directory layout plus the
published export surface, which stays accurate as subsystems move. Mark the
subsystem documentation table as a curated selection rather than a complete
index of docs/, and add the routing, scheduling, consensus, recovery, and
replay docs to it.
Link the new release guide, and add the Claude Code shim next to the existing
packages/create-oma-app/AGENTS.md so package-level rules load there the same way
they do at the repository root.
* chore(deps)!: upgrade OpenAI SDK to v7
Require Node.js 22 across packages, starters, and CI. Add real SDK boundary coverage and reject unsupported custom tool calls explicitly.
Refs #391
* fix(core): classify OpenAI user aborts as cancellation
Use the SDK error constructor name because OpenAI v7 APIUserAbortError retains the default Error name. Cover retry and observability classification with the real SDK class.
* chore(deps)!: target OpenAI v6 and retain Node 20
* docs: simplify Node runtime guidance
Assert the otel tarball ships only dist/, README.md, LICENSE, and package.json with its entry points present, smoke-test the built entry import, and scan core src for @opentelemetry references since workspace hoisting makes the import-based check toothless.
run a post-release smoke test against create-oma-app and core from the public npm registry
scaffold the recommended PR-review cloud starter and verify both its declared and installed core version match the GitHub Release tag
retry registry propagation with online-preferred resolution, then prove the generated demo reaches the expected missing-key gate
use a fresh project directory per retry so failed attempts cannot contaminate later attempts
Unit tests call scaffold() directly and never exercise the packed tarball.
Add `npm run test:scaffold`: pack the scaffolder, generate a project in an
isolated temp dir, install, and run the demo to the missing-key gate, proving
the published bytes scaffold, install, and load end-to-end. Wire it into CI as
a scaffold-e2e job. Core installs from a local tarball so the test validates
the current commit and stays green during the release window.
Add a build-output import smoke test plus oma help check to the package job; concurrency with cancel-in-progress; contents read-only permissions; per-job 15-minute timeouts; split lint into its own job so the type check no longer repeats across the Node matrix.
npm's package-name similarity protection permanently rejects the
unscoped `create-oma`, so the intended `npm create oma` could never
resolve for users. Rename the package and command to `create-oma-app`
/ `npm create oma-app` so the one-command first run actually works;
the `-app` suffix keeps the OMA name and reads naturally.
Pure rename — package name, bin, directory, the command text in the
scaffolder and READMEs, and the CI workspace/path references. The
generated demo and template are unchanged. Published to npm as
create-oma-app@0.1.0.
* refactor(repo): monorepo groundwork for an easier first run
Trying OMA for the first time costs more than it should: a lot to read before anything runs, and no one-command way to watch a team actually work. The plan is to fix that with a `npm create oma` scaffold (a multi-agent demo that runs on the first try) and an npm README that leads with getting started. Neither lands cleanly until core lives in its own package, so this PR does that part first.
This is groundwork, not the payoff: nothing changes for anyone installing `@open-multi-agent/core` today. It turns the repo into an npm-workspaces monorepo with core in `packages/core/`, and splits the README into a GitHub landing page (root) and the npm package page (`packages/core/`). Doing it now, while the repo is small, avoids migrating twice.
The published package is byte-identical: same name, same three runtime dependencies, same entry points, guarded by an isolated-install smoke test. `npm ci` + lint + test (1060) + build pass; the tarball still ships only `dist/`, `README.md`, `LICENSE`, and `package.json`.
* build: restore cross-platform optional deps in package-lock.json
Regenerating the lockfile on macOS pruned the non-host rollup/esbuild optional binaries (npm/cli#4828), so Linux CI could not load @rollup/rollup-linux-x64-gnu and vitest failed to start. Rebuild the lock from the pre-migration base so every platform variant is present again. Verified with npm ci + lint + build + test (1060).
* fix(examples,docs): correct monorepo paths and anchors after the packages/core move
with-vercel-ai-sdk example (pre-existing, surfaced by the move):
- package.json: the @open-multi-agent/core file: link was file:../../, which
resolves to packages/core/examples (no manifest). Corrected to file:../../..
(packages/core); predev cd updated to match.
- package-lock.json regenerated: was linking ../.. and pinning a stale core
1.4.0; now links ../../.. at 1.7.0.
- README: setup paths and the file: note updated.
docs missed by the move:
- docs/cli.md: repo-clone build output is now packages/core/dist/cli/oma.js;
the quick-start anchor now lives in the package README.
- CONTRIBUTING.md: the architecture anchor and src/ entry-point paths now live
under packages/core/.
- Replace the static fake coverage badge with codecov.
- Add npm version and bundlephobia bundle-size badges.
- Add test:coverage script and lcov reporter so CI can upload.
- Add a coverage job in CI that uploads to codecov on Node 20.
Requires CODECOV_TOKEN secret to be set in the repo for the badge to
populate; until then the badge will display "unknown".
- Add @google/genai to devDependencies so types are available for
lint/test in CI (stays as optional peerDependency for consumers)
- Delete package-lock.json in CI before npm install to avoid
Mac-generated lockfile missing Linux platform-specific rollup binaries
npm ci fails on Linux CI when package-lock.json was generated on macOS,
because platform-specific optional deps (@rollup/rollup-linux-x64-gnu)
are missing from the lockfile. This is a known npm bug (#4828).
- 5 test files, 61 test cases covering TaskQueue, SharedMemory,
ToolExecutor, ToolRegistry, and Semaphore
- GitHub Actions CI running lint + test on Node 18/20/22
- CONTRIBUTING.md with setup, commands, and PR workflow
- Pull request template with checklist