packmind / packages
PackmindHub/packmind/packages/CLAUDE.md
This directory contains reusable domain and infrastructure packages shared across applications. Every packages//project.json declares an env: tag, and @nx/enforce-module-boundaries in the root eslint.config.mjs turns those tags into hard import rules: A lint error about module boundaries usually means code belongs in a differently-tagged package, not that the rule needs an exception. Domain packages (accounts, spaces, standards, skills, commands, deployments, git, coding-agent, llm) follow a common shape. Only the first four lines are present in every one of them; the rest…
# Packages
This directory contains reusable domain and infrastructure packages shared across applications.
## Package Categories
### Core Infrastructure
- **types** - Shared TypeScript types and interfaces used across packages and apps
- **logger** - Logging utilities with console and structured output support
- **node-utils** - Shared backend framework: `BaseHexa`/`HexaRegistry`, scoped repositories, config, cache, jobs, SSE, mail
- **test-utils** - Test factories, fixtures, and utilities for consistent test data creation
- **migrations** - TypeORM database migrations for schema evolution
### Domain Packages
- **accounts** - User account management, authentication, and user profiles
- **spaces** - Workspace management, space members, roles, and permissions
- **standards** - Coding standards creation, storage, and retrieval
- **commands** - Multi-step coding command definitions and execution (formerly "recipes")
- **skills** - AI agent skill definitions and management
- **editions** - Product edition management (OSS, Enterprise, etc.)
- **feature-flags** - Shared, browser-safe feature-flag registry and decision logic (consumed by both frontend and backend)
- **playbook-change-applier** - Applies proposed changes to playbook artifacts (standards, commands, skills)
### Integration & Deployment
- **git** - Git repository operations for standards and command deployment
- **deployments** - Deployment pipeline for distributing standards, commands, and skills to AI agents
- **coding-agent** - AI coding agent integration and rendering for multiple agent types (Claude Code, Cursor, etc.)
### Language Analysis
- **linter-ast** - Abstract syntax tree (AST) analysis and manipulation utilities
- **linter-execution** - Linting rule execution engine for coding standards
- **llm** - Large language model integration for AI-powered features
### Frontend
- **frontend** - Shared `data-testid` enums used by both `apps/frontend` components and `apps/e2e-tests` page objects
- **ui** - The PM design kit — see the `working-with-pm-design-kit` skill
### Supporting
- **assets** - Static assets: fonts, icons, images, styles (tree-sitter WASM grammars live in `linter-ast/res/`, not here)
- **integration-tests** - Cross-package integration test suites (deployments, standards, tracked repositories, etc.)
## Environment Tags and Import Boundaries
Every `packages/*/project.json` declares an `env:*` tag, and `@nx/enforce-module-boundaries` in the
root `eslint.config.mjs` turns those tags into hard import rules:
| Tag | May depend on |
| --- | --- |
| `env:node` | anything |
| `env:shared` | `env:shared`, `env:node` |
| `env:browser` | `env:shared`, `env:browser` — **never** `env:node` |
- `env:shared`: `types`, `assets`, `editions`, `feature-flags`
- `env:browser`: `ui`, `frontend`
- `env:node`: everything else
A lint error about module boundaries usually means code belongs in a differently-tagged package, not
that the rule needs an exception.
## Package Layout
Domain packages (`accounts`, `spaces`, `standards`, `skills`, `commands`, `deployments`, `git`,
`coding-agent`, `llm`) follow a common shape. Only the first four lines are present in every one of
them; the rest exist where the package needs them, so check before assuming a directory is there:
```
src/<Name>Hexa.ts always — entry point, extends BaseHexa
src/application/adapter/<Name>Adapter.ts always — plural `adapters/` in `spaces`
src/application/services/ most — `llm` uses `src/infra/services/` instead
src/index.ts always — public barrel; nothing is importable until exported here
src/application/useCases/<useCaseName>/ most — `spaces` uses flat `src/application/usecases/<UseCaseName>.ts` files instead of one folder per use case
src/domain/repositories|useCases|errors/ most
src/domain/entities/ only accounts and standards
src/infra/schemas/ persistence packages only — index.ts barrel exporting a <name>Schemas array of TypeORM EntitySchemas
src/infra/repositories/ persistence packages, plus `coding-agent` (deployer implementations, not persisted entities)
src/application/jobs/ + src/domain/jobs/ only commands, deployments, git
test/ only the 7 packages listed below
```
`BaseHexa`, `BaseService` and `HexaRegistry` come from `@packmind/node-utils`
(`packages/node-utils/src/hexa/`).
Two of the packages above are **not** persistence domains and diverge most: `coding-agent` has no
`infra/schemas/` and no `test/` (its `infra/repositories/` holds deployer implementations, not
persisted entities — see its own `CLAUDE.md`), and `llm` has schemas but no `test/`.
### Architecture rules live in `packages/.claude/rules/packmind/`
The behavioural conventions for this layout are Packmind standards, not documented here — consult
them rather than inferring from neighbouring code:
- **Use Case Architecture Patterns** — contract-per-file in `packages/types/src/<domain>/contracts/`,
the `AbstractMemberUseCase` / `AbstractAdminUseCase` / `AbstractSpaceMemberUseCase` split
- **Port-Adapter Cross-Domain Integration** — how one domain may reach another
- **Scoped Repository Patterns** — `OrganizationScopedRepository` / `SpaceScopedRepository`
- **Domain Events**
- **Back-end repositories SQL queries using TypeORM**
- **Back-end TypeScript Clean Code Practices**
## Cross-Package Conventions
### Entity factories: the `/test` subpath
Packages that own persisted entities ship their factories in `packages/<pkg>/test/` (an `index.ts`
plus one `<entity>Factory.ts` per entity), imported as `@packmind/<pkg>/test` — for example
`import { standardFactory } from '@packmind/standards/test'`.
**Exactly seven packages have this subpath**: `accounts`, `commands`, `deployments`, `git`, `skills`,
`spaces`, `standards`. There is no `@packmind/coding-agent/test` or `@packmind/llm/test` — don't
import one. (`packages/node-utils/test/` exists but holds shared test suites, not factories, and is
not exposed as a subpath.)
All seven have an explicit `"@packmind/<pkg>/test"` entry in `tsconfig.base.json` (plus the legacy
`@packmind/recipes/test`, which points at `packages/commands/test/index.ts`). If a new `/test`
subpath fails to resolve under Jest, add the alias — `jest.config.ts` maps modules from those
`paths`.
Spec files import factories from there; production code must not. For the split between these and the
generic helpers in `@packmind/test-utils`, see [test-utils/CLAUDE.md](./test-utils/CLAUDE.md).
### Branded IDs
Entity identifiers are never bare strings. Each one is declared in `@packmind/types` as a branded
type plus a creator, following `packages/types/src/skills/SkillId.ts`:
```ts
import { Branded, brandedIdFactory } from '../brandedTypes';
export type SkillId = Branded<'SkillId'>;
export const createSkillId = brandedIdFactory<SkillId>();
```
The `Branded` / `brandedIdFactory` helpers live in `packages/types/src/brandedTypes.ts`.
## Working with Packages
The generic `nx build|test|lint <name>` commands are in the root `CLAUDE.md`, which already covers
packages. What it does not tell you:
> Two Nx project names differ from their directory name: `packages/frontend` is `frontend-lib` (plain
> `frontend` is the **app**) and `packages/integration-tests` is `@packmind/integration-tests`.
>
> Most targets are **inferred** by Nx plugins rather than declared: `@nx/jest/plugin` derives `test`
> from a package's `jest.config.ts` and `@nx/eslint/plugin` derives `lint` (see `plugins` in
> `nx.json`). So a `project.json` that lists only `build` still has a `test` target — check with
> `./node_modules/.bin/nx show project <package-name>` instead of reading `project.json`.
>
> Every package declares `typecheck` (`tsc --noEmit`). Most `build` targets depend on it via the
> `@nx/js:swc` executor's `targetDefaults` in `nx.json`, so building one of those packages type checks
> it; the target is one line — `"typecheck": {}` — inheriting its command from the same file.
> `migrations` has **no** `build` target at all — its esbuild output is produced by `bundle`
> (`@nx/esbuild:esbuild`), whose `targetDefaults` depend on `^build` but not on `typecheck`, so
> `nx bundle migrations` does not type check. Run `nx typecheck migrations` separately.
>
> `ui` is the one package whose `build` is not purely inferred: it declares `dependsOn` so the vite
> build gates on `typecheck` too. Its build output goes to `dist/packages/packmind-ui`.
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
No one has posted yet. Be the first.

