@ap/ Package Conventions

Scope: All repositories under the @ap/ npm scope. Source: Build Plan - Phase 1.md, Tool Shed Master Plan.md Decisions: reconciled with CGD-01 to CGD-04, CGD-18, CGD-19 on 2026-10-02. Agent-facing versions of these requirements live in Rules.

These are hard requirements — not guidelines. Every @ap/ package must satisfy all of them before being considered publish-ready.


The Non-Negotiables

RuleRequirement
Zero runtime dependenciesdependencies in package.json must be empty. devDependencies only.
100% TypeScriptNo any, no @ts-ignore. strict: true in tsconfig.json.
Immutable APIsNever mutate caller inputs. Return new values.
Side-effect freeEvery export must be independently tree-shakeable (no top-level side effects).
ESM-onlyShip ESM plus .d.ts in dist/, built by tsc. No CJS build, no tsup (CGD-03).
Node floorengines.node is >=22.12; CI tests Node 22 and 24 (CGD-19).
npmpackage-lock.json committed; install with npm ci --ignore-scripts (CGD-18).
Vitest testsTest suite uses vitest.config.ts, not Jest. Agent tests in tests/unit/, owner acceptance tests in protected tests/acceptance/ (CGD-04).
AC coverageEvery Acceptance Criterion in the PRD maps to a named test case.

Bundle Size Targets (gzipped)

PackageLimit
@ap/event-bus< 1.5 KB
@ap/schema< 2 KB
@ap/state-machine< 2 KB
@ap/diff< 3 KB
All other @ap/ packages< 5 KB unless PRD specifies otherwise

Size is checked in CI via a bundle size action step. Exceeding the limit blocks the build.


Package Structure

{repo}/
├── .planning/PRD.md              # Read before writing any code
├── .github/workflows/
│   ├── ci.yml                    # lint → typecheck → test → build → size check
│   └── release.yml               # npm publish on tag
├── src/
│   ├── index.ts                  # Public API surface (named exports only)
│   └── {module}.ts               # Internal modules
├── tests/
│   ├── unit/{module}.test.ts     # Vitest tests, one file per module (agent may add)
│   └── acceptance/               # Owner-authored, protected
├── dist/                         # Built ESM + .d.ts (gitignored)
├── package.json
├── package-lock.json
├── tsconfig.json                 # Typecheck: src + tests
├── tsconfig.build.json           # Emit: src only
├── vitest.config.ts
├── eslint.config.js              # Flat config (CGD-02)
├── .prettierrc.json
├── .gitignore
├── README.md
├── LICENSE                       # MIT
├── CONTRIBUTING.md
├── SECURITY.md
└── CLAUDE.md

package.json Template

{
  "name": "@ap/{package-name}",
  "version": "0.1.0",
  "type": "module",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  },
  "files": ["dist"],
  "sideEffects": false,
  "engines": { "node": ">=22.12" },
  "scripts": {
    "build": "tsc -p tsconfig.build.json",
    "test": "vitest run",
    "test:watch": "vitest",
    "lint": "eslint src tests",
    "typecheck": "tsc --noEmit",
    "size": "size-limit"
  },
  "devDependencies": {
    "typescript": "<pinned>",
    "vitest": "<pinned>",
    "eslint": "<pinned>",
    "typescript-eslint": "<pinned>",
    "prettier": "<pinned>",
    "@size-limit/preset-small-lib": "<pinned>",
    "size-limit": "<pinned>"
  }
}

Versions are pinned exactly from the A7 archetype kernel lockfile, not chosen per repo. types must be the first condition in exports; TypeScript stops at the first matching condition.

Key rules:

  • name must be scoped to @ap/
  • type: "module" always
  • exports has no require condition (ESM-only)
  • files: ["dist"] — never ship src/ or tests/
  • No dependencies key — or empty if present

tsconfig.json Requirements

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "rootDir": "src",
    "outDir": "dist"
  },
  "include": ["src"]
}

This is tsconfig.build.json. The root tsconfig.json extends it, sets "noEmit": true, drops rootDir, and includes tests for typechecking. NodeNext requires .js extensions on relative imports (CGD-01).

All strict flags enabled. noUncheckedIndexedAccess and exactOptionalPropertyTypes are required in addition to strict: true.


CI Pipeline (ci.yml)

name: CI
on: [push, pull_request]
jobs:
  ci:
    runs-on: ubuntu-latest
    steps:
    strategy:
      matrix:
        node: [22, 24]
    steps:
      # Pin every action to a full commit SHA in the real workflow.
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '${{ matrix.node }}', cache: 'npm' }
      - run: npm ci --ignore-scripts
      - run: npm run lint
      - run: npm run typecheck
      - run: npm test -- --coverage
      - run: npm run build
      - run: npm run size

CI must pass green before any PR is merged. Size check step must be present.


Package Manager

Use npm (CGD-18). It matches the A7 governance checker, fixtures and CI commands, and ships with Node. Revisit only if the packages consolidate into a workspace monorepo.

# Install exactly what the lockfile records
npm ci --ignore-scripts
 
# Add a dev dependency (owner only; agents escalate with ESC-DEP)
npm install -D --save-exact vitest
 
# Publish (done by release.yml, not manually)
npm publish --access public

Governance Scaffold

Every @ap/ package needs these files before it is considered public-ready:

FileContent
README.mdInstall, API docs, examples, bundle size badge
LICENSEMIT
CONTRIBUTING.mdStandard AP contribution guide
SECURITY.mdSecurity contact and disclosure policy
CLAUDE.mdAI context: package purpose, key design decisions, what NOT to change
.github/workflows/ci.ymlSee template above
.github/workflows/release.ymlTriggered on v* tags; runs npm publish

repo-score audits for all of these and grades A–F. Target: B or higher within 6 months of implementation.


Wave 1 @ap/ Packages (P0 — Build First)

PackageBundle LimitKey Functionality
@ap/schema< 2 KBRuntime type validation, Zod-like API
@ap/diff< 3 KBText + JSON structural diff, patch generation
@ap/event-bus< 1.5 KBTyped pub/sub, wildcards, replay
@ap/state-machine< 2 KBFSM with typed transitions, guards, history

These four must be implemented before any other repo in the ecosystem — repo-score, ap-cli, ci-monitor, VaultKeep, and acg-assessment all depend on them.