How BuilderIO/agent-native Handles Dependencies Defined in Root Files

BuilderIO/agent-native manages root-level dependencies through a pnpm monorepo architecture where the root package.json contains only development-time tooling, while runtime dependencies are centrally controlled via pnpm-workspace.yaml catalogs and enforced by custom guard scripts.

Managing dependencies in a JavaScript monorepo requires strict coordination to prevent version conflicts and duplicated packages. BuilderIO/agent-native solves this through a centralized dependency strategy that leverages pnpm's workspace protocol alongside automated validation. This approach ensures that root file definitions serve as the single source of truth for the entire repository.

Root package.json as a Development-Only Manifest

The root package.json in BuilderIO/agent-native serves exclusively as a manifest for development-time tooling rather than application runtime dependencies. It contains only devDependencies required to build, test, or lint any package within the workspace, including tools like concurrently, oxlint, prettier, and tsx.

This approach ensures that build tools and test runners are installed once at the repository root rather than duplicated across individual package node_modules directories. By keeping runtime dependencies out of the root manifest, the repository maintains a clear separation between development infrastructure and package-specific requirements.

Centralized Version Control via pnpm-workspace.yaml

The repository defines its workspace structure and dependency versions in pnpm-workspace.yaml. This configuration file declares the workspace layout (packages/* and templates/*), a catalog of approved dependency versions, and overrides that force every package to use identical versions of shared libraries like React and Tailwind.

The catalog acts as a central version lock-file. When a package lists a dependency that exists in the catalog without specifying an explicit version, it automatically inherits the catalog version. This eliminates the need to update version numbers across dozens of individual package.json files when upgrading shared libraries.

Version Overrides for Consistency

The overrides section in pnpm-workspace.yaml ensures that critical libraries use identical versions across the entire monorepo. For example, the configuration forces react and react-dom to version 19.2.7 and @types/react to ^19.2.14 regardless of what individual packages might specify. This prevents the "dependency hell" scenario where different packages pull in conflicting versions of shared libraries.

Enforcing the Workspace Protocol with Guard Scripts

Internal packages reference each other using the workspace:* protocol rather than specific version numbers. The scripts/guard-public-packages.ts script validates that all intra-repository dependencies use this protocol and that only packages on the npm-publish allow-list are exposed with proper semver ranges.

The localWorkspaceDependencyFailures function in this script checks that any dependency referencing another @agent-native package uses workspace:* in the source:

function localWorkspaceDependencyFailures(
  pkgName: string,
  field: string,
  dependencies: Record<string, string> | undefined,
): string[] {
  if (!dependencies) return [];
  return Object.entries(dependencies)
    .filter(([dep, version]) =>
      // Must stay "workspace:*" when referring to another @agent-native package
      workspacePackageNames.has(dep) && version !== "workspace:*",
    )
    .map(
      ([dep, version]) =>
        `${pkgName} ${field}.${dep} must stay workspace:* in source, not ${version}; pnpm pack rewrites it for npm publishing`,
    );
}

This validation ensures that internal packages remain properly linked during development, while pnpm pack automatically rewrites these references to proper semver ranges during the publishing process.

Pre-Publish Validation Checks

The same guard script enforces that workspace-only packages stay private and are excluded from changesets. It verifies that published packages have publishConfig.access set to "public" and publishConfig.provenance set to true. Additionally, it checks that no raw TypeScript files are referenced in main, exports, or bin fields—all entries must point to compiled JavaScript or .d.ts files in the dist/ directory.

Automated Build Synchronization

After pnpm install completes, the postinstall script triggers scripts/prebuild-workspace-packages.ts. This script detects missing build artifacts for each workspace package and clears stale TypeScript build-info files (.tsbuildinfo) to ensure fresh compilation.

The firstMissingOutput function checks whether expected output files exist in each package's directory:

function firstMissingOutput(target: PackageTarget): string | null {
  for (const output of target.expectedOutputs) {
    if (!existsSync(path.join(target.dir, output))) return output;
  }
  return null;
}

If artifacts are missing, the script clears stale build information and runs pnpm run build selectively for only those packages requiring recompilation. This ensures that the compiled dist/ output matches the exported entries declared in each package's package.json without forcing unnecessary rebuilds of unchanged code.

Summary

  • The root package.json contains only devDependencies for development tooling, avoiding duplication across the monorepo while keeping runtime dependencies package-specific.
  • pnpm-workspace.yaml centralizes version management through catalogs and overrides, ensuring consistent library versions across all workspace packages.
  • The workspace:* protocol enforces proper internal linking, validated by scripts/guard-public-packages.ts to prevent improper version references.
  • Automated build synchronization via scripts/prebuild-workspace-packages.ts ensures compiled outputs match exported entries without unnecessary rebuilds.

Frequently Asked Questions

Why does BuilderIO/agent-native keep only devDependencies in the root package.json?

Keeping only devDependencies in the root package.json ensures that build tools, linters, and test runners are installed once at the repository level rather than duplicated in each package's node_modules. This reduces disk space usage and installation time while maintaining a clear separation between development infrastructure and runtime dependencies required by individual applications.

What happens if a package references internal dependencies without the workspace:* protocol?

The scripts/guard-public-packages.ts script will fail validation during pre-publish checks. The localWorkspaceDependencyFailures function specifically filters for internal dependencies that don't use the workspace:* protocol and generates error messages indicating that the version must remain workspace:* in source. This allows pnpm pack to properly rewrite these references to semver ranges during the npm publishing process.

How does the pnpm-workspace.yaml catalog prevent version conflicts?

The catalog in pnpm-workspace.yaml acts as a centralized version registry that provides a single source of truth for dependency versions. When a package lists a dependency that exists in the catalog without specifying a version, it automatically inherits the catalog version. The overrides section further ensures that critical libraries like React use identical versions across every package, preventing runtime conflicts from incompatible library versions.

When does the prebuild script trigger and what does it optimize?

The prebuild script triggers automatically after pnpm install via the postinstall hook. It optimizes the build process by using firstMissingOutput to check for missing compiled files and only rebuilding packages that actually require recompilation. The script also clears stale TypeScript build-info files to prevent compilation errors from outdated incremental build data, ensuring that pnpm run build runs fresh only for packages with missing or outdated artifacts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →