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.
5.3 KiB
Contributing
Thanks for your interest in contributing to Open Multi-Agent! This guide covers the basics to get you started.
Setup
git clone https://github.com/open-multi-agent/open-multi-agent.git
cd open-multi-agent
npm install
Requires Node.js >= 20.0.0.
Development Commands
npm run build # Compile every workspace
npm run dev # Watch-mode compilation for @open-multi-agent/core
npm run lint # Type-check every workspace (tsc --noEmit)
npm test # Run unit tests in every workspace
npm run test:watch # Core Vitest watch mode
npm run test:coverage # Core unit tests with coverage
npm run test:scaffold # End-to-end create-oma-app scaffold smoke test
Running Tests
Unit tests live in each workspace's tests/ directory: currently packages/core/tests/, packages/create-oma-app/tests/, and packages/otel/tests/. They run without API keys or network access — provider SDKs and external processes are mocked where needed.
npm test
Core E2E tests are separate because they require RUN_E2E=1 and real provider credentials. Each provider suite runs only when its matching credential is present, so a single-key canary does not fail on unrelated providers:
# Runs only the suites whose credentials are set.
# Supported keys: OPENAI_API_KEY, ANTHROPIC_API_KEY,
# GEMINI_API_KEY / GOOGLE_API_KEY, and DEEPSEEK_API_KEY.
npm run test:e2e
Set DEEPSEEK_E2E_MODEL to override the DeepSeek canary model; it defaults to deepseek-v4-flash.
The Provider Canary workflow runs the DeepSeek suite daily and can also be started manually. Maintainers must configure DEEPSEEK_API_KEY as a GitHub Actions repository secret; never add a provider credential to source files or workflow YAML.
Run checks that match the surface you changed and record the commands and results in the PR description. For code changes, start with npm run lint && npm test; also run npm run build when package output or public entry points may be affected, and npm run test:scaffold when changing create-oma-app scaffolding or templates.
CI is the source of truth for the full pre-merge matrix. It runs lint, unit tests on Node 20/22/24, coverage, workspace builds, package/import smoke tests, template type-checking, tarball assertions, and the scaffold E2E test.
Making a Pull Request
- Fork the repo and create a branch from
main - Make your changes
- Add or update tests and user-facing documentation when behavior changes
- Run the checks relevant to your change and note any skipped checks with a reason
- Open a PR against
main, titled as a conventional commit such asfix(core): reject empty tool names
Opening a PR prefills the pull request template, which carries the review checklist. Fill in the sections it asks for instead of deleting them, and write "None" or "Not applicable" where a category does not apply.
Code Style
- TypeScript strict mode, ES modules (
.jsextensions in imports) - No additional linter/formatter configured — follow existing patterns
- Keep dependency ownership explicit. Core must remain importable and runnable without optional integrations
- Pin what stays in the repository; keep ranges on what a consumer installs. Every
devDependenciesentry is pinned to an exact version and the root.npmrcsetssave-exact=true, but core'sdependencies, everypeerDependencies, and otel's@open-multi-agent/corestay semver ranges.save-exactwill pin a new dependency added to one of those blocks, so widen it by hand — CI fails when one is left exact - Add new optional provider SDKs as peer dependencies and load them lazily with dynamic
import() - Keep OpenTelemetry APIs, SDKs, semantic-convention packages, and exporters in
@open-multi-agent/otel, never in the core root import - Version
@open-multi-agent/otelindependently from core and express core compatibility in its dependency range - Justify dependency changes to other workspaces in the PR description
Architecture Overview
See the README for an architecture diagram. Key entry points:
- Orchestrator:
packages/core/src/orchestrator/orchestrator.ts— top-level API - Task system:
packages/core/src/task/queue.ts,packages/core/src/task/task.ts— dependency DAG - Agent:
packages/core/src/agent/runner.ts— conversation loop - Tools:
packages/core/src/tool/framework.ts,packages/core/src/tool/executor.ts— tool registry and execution - LLM adapters:
packages/core/src/llm/— built-in providers + OpenAI-compatible + AI SDK bridge (see docs/providers.md) - Observability:
packages/core/src/observability/— trace records, sinks, exporters, and stores - OpenTelemetry adapter:
packages/otel/src/— optional OTel mapping and export integration kept outside core - App scaffolder:
packages/create-oma-app/src/andpackages/create-oma-app/templates/— CLI and starter templates
Where to Contribute
Check the issues page. Issues labeled good first issue are scoped and approachable. Issues labeled help wanted are larger but well-defined.
License
By contributing, you agree that your contributions will be licensed under the MIT License.