name: pnpm-monorepo type: skill description: pnpm workspace monorepo setup for AI agent gateway packages with catalogs, workspace protocol, shared configs, scripts, CI, and versioning. version: 1.0.0 author: skillregistry license: MIT agents: [cursor, claude-code, copilot, gemini-cli] categories: [tooling, monorepo, node] tags: [pnpm, workspaces, monorepo, catalogs, changesets, ci, typescript, packages]
pnpm Monorepo Expert
Implement a maintainable pnpm workspace for the agent gateway: shared packages, strict dependency boundaries, reproducible installs, shared TypeScript/test config, and predictable release workflows.
pnpm is well-suited for local-first gateway development because its content-addressable store and workspace protocol make multi-package TypeScript projects fast and explicit.
Architecture
repo/
pnpm-workspace.yaml
package.json
packages/
core/ -> AgentGateway
http/ -> HTTP routes
providers/ -> LLM provider adapters
storage/ -> memory/vector stores
ui/ -> control panel
Core Components
| Component | Purpose | Technology/Implementation |
|---|---|---|
| Workspace Manifest | Declare package globs and catalogs | pnpm-workspace.yaml |
| Root Package | Shared scripts and package manager pin | package.json |
| Internal Packages | Isolated gateway modules | workspace:* dependencies |
| Shared Config | TS/Vitest/ESLint defaults | @skillregistry/config |
| Versioning | Release and changelog automation | Changesets |
| CI | Reproducible install and filtered checks | pnpm install --frozen-lockfile |
Setup & Installation
corepack enable
corepack prepare pnpm@latest --activate
pnpm init
pnpm add -D typescript vitest tsx @types/node
Configuration (Zod Schema)
import { z } from "zod";
export const MonorepoConfigSchema = z.object({
packageManager: z.string().regex(/^pnpm@\d+\.\d+\.\d+/).default("pnpm@10.0.0"),
packages: z.array(z.string()).default(["packages/*", "apps/*"]),
nodeVersion: z.string().default(">=20.11"),
strictPeerDependencies: z.boolean().default(true),
onlyBuiltDependencies: z.array(z.string()).default([]),
catalogs: z.record(z.string()).default({
typescript: "^5.9.0",
vitest: "^4.0.0",
zod: "^4.0.0",
}),
});
export type MonorepoConfig = z.infer<typeof MonorepoConfigSchema>;
Implementation
Workspace Files
# pnpm-workspace.yaml
packages:
- "packages/*"
- "apps/*"
catalog:
typescript: ^5.9.0
vitest: ^4.0.0
zod: ^4.0.0
tsx: ^4.20.0
{
"name": "agent-gateway-workspace",
"private": true,
"packageManager": "pnpm@10.0.0",
"engines": { "node": ">=20.11" },
"scripts": {
"build": "pnpm -r --filter './packages/*' build",
"test": "pnpm -r test",
"typecheck": "pnpm -r typecheck",
"dev": "pnpm --filter @skillregistry/gateway dev"
},
"devDependencies": {
"typescript": "catalog:",
"vitest": "catalog:",
"tsx": "catalog:"
}
}
Internal Package
{
"name": "@skillregistry/providers",
"version": "0.1.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "vitest run"
},
"dependencies": {
"zod": "catalog:"
}
}
Shared TypeScript Config
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"declaration": true,
"sourceMap": true,
"outDir": "dist",
"skipLibCheck": true
}
}
Integration with Gateway
Use separate packages for core boundaries:
import { AgentGateway } from "@skillregistry/core";
import { createExpressServer } from "@skillregistry/http";
import { ProviderRegistry } from "@skillregistry/providers";
Best Practices
- Use
workspace:*for internal packages. - Put shared dependency versions in
catalog. - Keep package
exportsexplicit. - Run filtered commands during development.
- Keep apps private; version libraries that may be published.
- Commit
pnpm-lock.yaml. - Use
--frozen-lockfilein CI.
Testing
Unit Tests
it("loads monorepo config defaults", () => {
expect(MonorepoConfigSchema.parse({}).packages).toContain("packages/*");
});
Integration Tests
pnpm install --frozen-lockfile
pnpm -r typecheck
pnpm -r test
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Internal package not found | Missing workspace:* dependency |
Add dependency to consuming package |
| Duplicate dependency versions | Versions declared per package | Move versions to catalog |
| CI install fails | Lockfile not updated | Run pnpm install and commit lockfile |
| Build order wrong | Missing package dependency | Add internal dependency and use recursive build |
| Type imports fail | Missing exports.types |
Add types and export map |
Debug Commands
pnpm list -r --depth 0
pnpm why zod
pnpm --filter @skillregistry/providers test
pnpm -r exec pwd
Resources
- pnpm Workspaces - Official workspace documentation.
- pnpm Workspace Manifest -
pnpm-workspace.yamlreference. - pnpm Catalogs - Centralized dependency versions.
- Changesets - Monorepo versioning.
- Node Package Exports - Export map behavior.
Principles
- Dependency boundaries should be explicit.
- Shared config should reduce drift, not hide behavior.
- CI must use the lockfile.
- Internal package APIs are still APIs.
- Prefer filtered work over whole-repo work during development.