# How to Add a New Package to the OpenWork Monorepo: A Step-by-Step Guide

> Learn how to add a new package to the OpenWork monorepo with this step-by-step guide. Discover the simple process of using pnpm workspaces for seamless integration.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: how-to-guide
- Published: 2026-08-14

---

**OpenWork uses a pnpm workspace that automatically links any directory matching the `packages/*` and `apps/*` globs declared in [`pnpm-workspace.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-workspace.yaml), so adding a new package only requires creating a properly scoped [`package.json`](https://github.com/different-ai/openwork/blob/main/package.json) and running `pnpm install`.**

The `different-ai/openwork` repository is a TypeScript monorepo orchestrated by pnpm and Turbo. To **add a new package to the OpenWork monorepo**, you follow a repeatable, convention-based workflow that keeps builds, tests, and CI pipelines intact. Every new package lives under the `packages/` or `apps/` directories and inherits shared tooling defined at the repository root.

## Step-by-Step Guide to Adding a New Package

### 1. Create the Package Directory

Create a folder under `packages/<my-package>` for a library or `apps/<my-app>` for an application. The folder must match one of the glob patterns defined in [`pnpm-workspace.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-workspace.yaml) so pnpm recognizes it as a workspace member.

### 2. Add a [`package.json`](https://github.com/different-ai/openwork/blob/main/package.json) with the OpenWork Scope

Inside the new folder, add a [`package.json`](https://github.com/different-ai/openwork/blob/main/package.json) that uses the `@openwork/` scope and sets `private: true` to prevent accidental publishing. As demonstrated in [`packages/ui/package.json`](https://github.com/different-ai/openwork/blob/main/packages/ui/package.json), you should define entry points, types, and standard scripts.

```json
{
  "name": "@openwork/my-package",
  "version": "0.1.0",
  "private": true,
  "main": "src/index.ts",
  "types": "src/index.d.ts",
  "scripts": {
    "build": "tsc",
    "test": "pnpm test"
  },
  "dependencies": {}
}

```

### 3. Configure TypeScript

Create a local [`tsconfig.json`](https://github.com/different-ai/openwork/blob/main/tsconfig.json) that extends the root configuration. This keeps compiler options aligned with the rest of the monorepo and ensures consistent output directories, following the pattern used by [`packages/ui/tsconfig.react.json`](https://github.com/different-ai/openwork/blob/main/packages/ui/tsconfig.react.json).

```json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "dist"
  },
  "include": ["src"]
}

```

### 4. Run `pnpm install` from the Root

Navigate to the repository root and execute `pnpm install`. pnpm will discover the new package, resolve its dependencies, and wire the appropriate `node_modules` symlinks automatically.

### 5. Register the Package in [`turbo.json`](https://github.com/different-ai/openwork/blob/main/turbo.json)

If the new package must participate in build, lint, or test pipelines, update the root [`turbo.json`](https://github.com/different-ai/openwork/blob/main/turbo.json). Add the package to the relevant pipeline so Turbo includes it in caching and parallel execution. The default build pipeline uses `"dependsOn": ["^build"]` and `"outputs": ["dist/**"]`.

## Complete Scaffolding Example

Run the following from the repository root to generate a minimal package skeleton:

```bash

# 1. Create the directory

mkdir -p packages/my-tool
cd packages/my-tool

# 2. Write package.json

cat > package.json <<'EOF'
{
  "name": "@openwork/my-tool",
  "version": "0.1.0",
  "private": true,
  "main": "src/index.ts",
  "types": "src/index.d.ts",
  "scripts": {
    "build": "tsc",
    "test": "pnpm test"
  },
  "dependencies": {}
}
EOF

# 3. Add a basic TypeScript entry point

mkdir src
cat > src/index.ts <<'EOF'
export function hello(name: string): string {
  return `Hello, ${name}!`;
}
EOF

# 4. Extend the root TS config

cat > tsconfig.json <<'EOF'
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "dist"
  },
  "include": ["src"]
}
EOF

# 5. Install workspace dependencies from root

cd ../..
pnpm install

```

## Consuming the Package Inside the Workspace

To use the new package from another workspace member, reference it with the `workspace:*` protocol in the dependent's [`package.json`](https://github.com/different-ai/openwork/blob/main/package.json). This tells pnpm to link the local version instead of fetching from a registry.

```json
{
  "name": "@openwork/another-package",
  "private": true,
  "dependencies": {
    "@openwork/my-tool": "workspace:*"
  }
}

```

## Key Files That Power the OpenWork Monorepo

- **[`pnpm-workspace.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-workspace.yaml)**: Declares the `packages/*` and `apps/*` globs that define workspace boundaries. Any folder matching these patterns is automatically linked during installation.
- **[`turbo.json`](https://github.com/different-ai/openwork/blob/main/turbo.json)**: Drives CI/CD pipelines, caching, and parallel task execution across workspace members.
- **[`tsconfig.base.json`](https://github.com/different-ai/openwork/blob/main/tsconfig.base.json)**: Central TypeScript configuration that individual packages extend to stay aligned on compiler options.
- **Root [`package.json`](https://github.com/different-ai/openwork/blob/main/package.json)**: Houses workspace-wide dev dependencies and shared scripts used across the monorepo.

## Summary

- Create a directory under `packages/` or `apps/` that matches the globs in [`pnpm-workspace.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-workspace.yaml).
- Write a scoped, private [`package.json`](https://github.com/different-ai/openwork/blob/main/package.json) using the `@openwork/` namespace to prevent accidental publishing.
- Extend [`../../tsconfig.base.json`](https://github.com/different-ai/openwork/blob/main/../../tsconfig.base.json) for consistent TypeScript settings.
- Run `pnpm install` from the root to link the new package into the workspace graph.
- Update [`turbo.json`](https://github.com/different-ai/openwork/blob/main/turbo.json) when the package needs custom build, lint, or test pipeline behavior.

## Frequently Asked Questions

### Does OpenWork use npm or yarn for its monorepo?

No. According to the source configuration in `different-ai/openwork`, the monorepo relies on **pnpm workspaces** for dependency linking and task execution. The root [`pnpm-workspace.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-workspace.yaml) and lockfile behavior confirm this choice.

### What naming convention should new packages follow?

New packages should use the **`@openwork/` scope** in their `name` field and set `"private": true` to avoid accidental publishing. This convention is consistent with existing packages such as [`packages/ui/package.json`](https://github.com/different-ai/openwork/blob/main/packages/ui/package.json).

### Do I need to manually edit [`pnpm-workspace.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-workspace.yaml) for every new package?

No. The root [`pnpm-workspace.yaml`](https://github.com/different-ai/openwork/blob/main/pnpm-workspace.yaml) uses directory globs such as `packages/*` and `apps/*`. As long as your new folder matches those patterns, pnpm will discover it automatically during the next `pnpm install`.

### How does Turbo know to build a new package?

Turbo reads the root [`turbo.json`](https://github.com/different-ai/openwork/blob/main/turbo.json) pipeline definitions. If your new package exposes a `build`, `test`, or `lint` script that must participate in the monorepo CI, ensure the pipeline configuration covers that task so Turbo can cache and parallelize it correctly.