Files
open-multi-agent/.github/CONTRIBUTING.md
T
Jack Chen 98516cedfc chore: pin the internal dependency tree and audit the production one (#570)
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.
2026-09-04 01:01:09 +08:00

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

  1. Fork the repo and create a branch from main
  2. Make your changes
  3. Add or update tests and user-facing documentation when behavior changes
  4. Run the checks relevant to your change and note any skipped checks with a reason
  5. Open a PR against main, titled as a conventional commit such as fix(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 (.js extensions 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 devDependencies entry is pinned to an exact version and the root .npmrc sets save-exact=true, but core's dependencies, every peerDependencies, and otel's @open-multi-agent/core stay semver ranges. save-exact will 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/otel independently 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/ and packages/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.