---
title: "pkg-conform by harlan-zw · skilld"
canonical_url: "https://skilld.dev/gh/harlan-zw/harlan-agent-kit/pkg-conform/-/references/site-github-actions"
meta:
  description: "Conform or scaffold TypeScript packages and Nuxt modules. Use for workspace catalogs, package config, CI, ESLint, Vitest, playgrounds, fixtures, or Nuxt module setup. From harlan-zw/harlan-agent-kit."
  "og:description": "Conform or scaffold TypeScript packages and Nuxt modules. Use for workspace catalogs, package config, CI, ESLint, Vitest, playgrounds, fixtures, or Nuxt module setup. From harlan-zw/harlan-agent-kit."
  "og:title": "pkg-conform by harlan-zw"
  "twitter:description": "Conform or scaffold TypeScript packages and Nuxt modules. Use for workspace catalogs, package config, CI, ESLint, Vitest, playgrounds, fixtures, or Nuxt module setup. From harlan-zw/harlan-agent-kit."
  "twitter:title": "pkg-conform by harlan-zw"
---

`

[All skills](https://skilld.dev/skills)

[![harlan-zw avatar](https://skilld.dev/_img/avatar?url=https%3A%2F%2Fgithub.com%2Fharlan-zw.png%3Fsize%3D96)](https://skilld.dev/gh/harlan-zw)

# **/pkg-conform**

by [Harlan Wilton](https://skilld.dev/gh/harlan-zw)· [harlan-zw](https://skilld.dev/gh/harlan-zw)/ [harlan-agent-kit](https://skilld.dev/gh/harlan-zw/harlan-agent-kit)·10 stars

 1

Conform or scaffold TypeScript packages and Nuxt modules. Use for workspace catalogs, package config, CI, ESLint, Vitest, playgrounds, fixtures, or Nuxt module setup.

[GitHub](https://github.com/harlan-zw/harlan-agent-kit/blob/491d032ad2b040c879097c10fe563c1a4655be6d/harlan-agent-kit/skills/pkg-conform/SKILL.md "View SKILL.md on GitHub") Updated 2 hours ago

## Skill content

[Raw](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/pkg-conform)

## Package Conform Skill

Conform a package to standardized architecture, or scaffold a new one.

### Worktree isolation

Before any edit, follow the [worktree isolation contract](https://github.com/harlan-zw/harlan-agent-kit/blob/main/harlan-agent-kit/references/worktree-isolation.md). It provides the atomic live-agent claim used below.

An existing worktree alone does not prove another agent is active.

`wt` is the only worktree tool. Never run `git worktree add`, and never use a harness worktree option such as `EnterWorktree` or `isolation: "worktree"`. Those write to `.claude/worktrees/`, which is banned. `wt` places every worktree at `<parent>/<repo>.<branch-slug>`.

Keep the primary checkout read only. Before mutation, run `wt list --format=json`. Reuse the task's worktree with `wt switch <branch>`, or create one with `wt switch --create <branch> --base <base>`. Read its absolute `path` from the JSON, then pass that path as `workdir` to every later command. Never share a mutation worktree between tasks.

### Usage

```
/pkg-conform              # conform existing project
/pkg-conform my-package   # scaffold new package
```

### Behavior

1. **New project**: scaffold with all standards below
2. **Existing project**: compare and offer to sync each component

### Detection

Check for `package.json` in cwd to determine new vs existing. Check for `packages:` in `pnpm-workspace.yaml` to detect monorepo vs single repo. Check for `@nuxt/module-builder` in devDependencies to detect Nuxt module -> apply Nuxt-specific patterns.

#### Project Type Detection

Determine project type from the **absolute path** of the working directory:

| Path pattern | Type | Description |
| --- | --- | --- |
| `*/pkg/*` | **Package** | Published library/module -- needs exports, build, release |
| `*/sites/*` or `*/site/*` | **Site** | Nuxt app -- private, no exports, deploy not publish |

If path doesn't match either pattern, fall back to heuristics: `private: true` + `nuxt` in deps -> Site, otherwise Package.

The project type selects the rule set. Package-only rules (exports, obuild, test:attw, prepack, release) never apply to Sites. Site-only rules (nuxi scripts, generate, preview) never apply to Packages.

---

### Gotchas

- **Catalog version conflicts** -- when migrating deps to `catalog:`, check that the catalog version satisfies all consumers in the monorepo. A single `catalog:` entry shared across packages with different version requirements will break.
- **obuild vs tsc** -- obuild doesn't do type-checking. If you remove `tsc` from the build, types won't be validated. Always keep `typecheck` as a separate script.
- **`module: preserve` in tsconfig** -- this is correct for packages built with obuild, but breaks Nuxt apps that need `module: esnext` or defer to `.nuxt/tsconfig.json`. Don't apply package tsconfig rules to sites.
- **ESM-only exports trap** -- removing CJS exports breaks consumers that haven't migrated to ESM. For public packages, confirm the audience before dropping `.cjs`.
- **`pnpm install` after catalog changes** -- lockfile must be regenerated. If you edit `pnpm-workspace.yaml` catalogs, always run `pnpm install` before running any other commands.
- **Nuxt module `dev:prepare` order** -- must run before `typecheck` or `test`. Missing this causes confusing "module not found" errors from auto-generated types.
- **Site vs Package misdetection** -- path-based detection ( `*/pkg/*` vs `*/sites/*`) can fail for unusual directory structures. Always verify the detected type before applying rules.
- **Markdown-only CI**: Test, build, and deploy events ignore `**/*.md` by default. An explicit `paths` list may include Markdown. GitHub forbids `paths` and `paths-ignore` on the same event.

---

### UnJS Conventions

Always prefer UnJS ecosystem packages over Node.js builtins:

| Instead of | Use | Import |
| --- | --- | --- |
| `path` | `pathe` | `import { join, resolve } from 'pathe'` |
| `console.log/warn/error` | `consola` | `import { consola } from 'consola'` |
| `fetch` | `ofetch` | `import { $fetch } from 'ofetch'` |
| `fs.readFile` (JSON) | `pkg-types` | `import { readPackageJSON } from 'pkg-types'` |
| `Object.assign` defaults | `defu` | `import { defu } from 'defu'` |
| `require.resolve` | `mlly` | `import { resolveImports } from 'mlly'` |
| `EventEmitter` | `hookable` | `import { createHooks } from 'hookable'` |
| `yargs/commander` | `citty` | `import { defineCommand } from 'citty'` |
| `cosmiconfig` | `c12` | `import { loadConfig } from 'c12'` |
| `git clone` templates | `giget` | `import { downloadTemplate } from 'giget'` |

**Principles:** ESM-only, minimal deps, full TypeScript, universal (Node/browser/edge)

---

### Root docs

Every project carries the same root documents and the same docs lifecycle. Read [root-docs.md](https://github.com/harlan-zw/harlan-agent-kit/blob/main/harlan-agent-kit/references/root-docs.md) before creating, moving, or renaming any Markdown at the root or under `docs/`.

`AGENTS.md` is the only file an agent loads every turn, so it routes rather than explains. Scaffold it from [templates/AGENTS.md](https://skilld.dev/gh/harlan-zw/harlan-agent-kit/pkg-conform/-/templates/AGENTS.md).

---

### Package.json

#### Package (single repo / monorepo)

See `references/pkg-package-json.md` for single repo and monorepo root templates.

#### Site (Nuxt app)

See `references/site-package-json.md` for template, optional scripts, and rules.

See `references/site-structure.md` for Nuxt 4 directory layout.

See `references/site-configs.md` for nuxt.config.ts, tsconfig, eslint, .npmrc, .gitignore templates.

---

### Test Structure

```
test/
  unit/           # unit tests
    *.test.ts
  e2e/            # e2e/integration tests
    *.test.ts
  fixtures/       # test data
```

---

### Nuxt Module (when `@nuxt/module-builder` detected)

#### Build-time vs Runtime

| Context | Location | Access | Registration |
| --- | --- | --- | --- |
| Build-time | `src/module.ts` | `@nuxt/kit`, nuxt config | runs during `nuxi build` |
| App runtime | `src/runtime/app/` | Vue, `useNuxtApp()` | `addPlugin()`, `addImports()` |
| Server runtime | `src/runtime/server/` | H3, Nitro | `addServerHandler()`, `addServerPlugin()` |
| Shared | `src/runtime/shared/` | Pure JS only | import via alias |

See `references/nuxt-module-template.md` for full module.ts template with registration examples.

See `references/nuxt-module-structure.md` for directory layout and runtime rules.

---

### References

See `references/` for detailed templates:

- `../../references/code-comments.md` - the comment contract for any code this skill writes
- `references/pkg-package-json.md` - single repo and monorepo package.json templates
- `references/catalogs.md` - pnpm workspace catalogs
- `references/configs.md` - package config file templates (eslint, vitest, tsconfig, obuild)
- `references/github-actions.md` - CI/CD workflows (Package only)

**Site references** (when project type is Site):

- `references/site-package-json.md` - package.json template, rules, optional scripts
- `references/site-structure.md` - Nuxt 4 directory layout and conventions
- `references/site-configs.md` - nuxt.config.ts, tsconfig, eslint, npmrc, editorconfig, gitignore
- `references/site-github-actions.md` - the shared CI gate, deploy gating, self-hosted runner rules

**Nuxt module references** (when `@nuxt/module-builder` detected):

- `references/nuxt-module-structure.md` - directory layout and runtime rules
- `references/nuxt-module-template.md` - full src/module.ts template
- `references/nuxt-configs.md` - vitest, tsconfig, build.config, package.json for Nuxt
- `references/nuxt-test-patterns.md` - playground, fixtures, e2e tests
- `../../references/root-docs.md` - the root document set, docs lifecycle, and brief contract
- `templates/AGENTS.md` - the router template

---

### Sync Checklist

#### Shared (all project types)

1. `pnpm-workspace.yaml` - default catalog, `ignoredBuiltDependencies`, `shellEmulator`
2. `package.json` - `type: module`, migrate deps to `catalog:`, add `packageManager`
3. `.github/workflows/test.yml` - action versions and Markdown path filtering
4. `.editorconfig` - standard config
5. `.gitignore` - standard patterns
6. ESLint config - antfu + `eslint-plugin-harlanzw`. Package: `eslint.config.mjs`; Site: `eslint.config.js`
7. `tsconfig.json` - Package: `module: preserve`, `moduleDetection: force`; Site: `extends .nuxt/tsconfig.json`
8. Git hooks - `lint-staged` in devDeps, `pre-commit` runs `lint-staged`
9. `AGENTS.md` - router shape, 30 to 80 lines. No `CLAUDE.md`, no `CONTEXT.md`. See `../../references/root-docs.md`
10. Root Markdown - only the allowed set. Reference docs move to `docs/arch/`, open work to `docs/work/`

#### Package-only (when in `*/pkg/*`)

11. `vitest.config.ts` - coverage config, projects if unit + e2e
12. `tsconfig.json` - add `types: ["node", "vitest/globals"]`
13. `build.config.ts` - obuild with explicit entry points
14. Package exports - ESM-only ( `.d.mts` + `.mjs`), no CJS
15. Package scripts - `obuild`, `dev:prepare`, `test:attw`, `lint:fix`, `prepack`, `release`
16. `.github/workflows/release.yml` - action versions, `bumpp --output=CHANGELOG.md`

#### Site-only (when in `*/sites/*` or `*/site/*`)

11. `package.json` - `private: true`, `engines.node` set to latest stable even-numbered Node (e.g. `>=22.0.0`, `>=24.0.0`), no `exports`/ `main`/ `types`/ `files`
12. Scripts - `dev` (nuxi dev), `build` (nuxi prepare && nuxi build), `postinstall` (nuxt prepare), `lint`, `lint:fix`, `typecheck` (nuxt typecheck)
13. `pnpm.overrides` - `vite` set to `^8.0.0`
14. `nuxt.config.ts` - `future.compatibilityVersion: 5`, `compatibilityDate`, standard module stack
15. `tsconfig.json` - just `{ "extends": "./.nuxt/tsconfig.json" }`
16. `eslint.config.js` - antfu config with `node/prefer-global/process` and `node/prefer-global/buffer` off
17. `.npmrc` - `shamefully-hoist=true`
18. `.gitignore` - includes `.nuxt/`, `.output/`, `.data/`, `.wrangler/`, `wrangler.toml`
19. `.editorconfig` - 2-space indent, LF, UTF-8, trim trailing whitespace (except `.md`)
20. `content.config.ts` - Zod schemas for content collections (if using `@nuxt/content`)
21. `app/` directory - Nuxt 4 structure ( `app.vue`, `pages/`, `layouts/`, `components/`, `composables/`)
22. `.github/workflows/ci.yml` - calls the shared gate and ignores Markdown-only changes. See `references/site-github-actions.md`.

#### Additional Nuxt Module Checklist

When `@nuxt/module-builder` detected, also check (extends Package checklist):

**Structure:** 17. \[ ] `src/module.ts` - main module entry exists 18. \[ ] `src/runtime/app/` - client/SSR code directory 19. \[ ] `src/runtime/server/` - Nitro server code directory 20. \[ ] `src/types.ts` - module options types 21. \[ ] `playground/` - nuxt.config.ts, app.vue, pages/ 22. \[ ] `test/fixtures/basic/` - nuxt.config.ts

**Config:** 23. \[ ] `pnpm-workspace.yaml` - add `nuxt:` catalog 24. \[ ] `package.json` - nuxt module exports, peerDependencies 25. \[ ] `tsconfig.json` - extends `.nuxt/tsconfig.json` 26. \[ ] `vitest.config.ts` - use `defineVitestProject` for e2e 27. \[ ] `build.config.ts` - nuxt externals including `#imports` 28. \[ ] `eslint.config.mjs` - ignore fixtures/playground 29. \[ ] `.gitignore` - nuxt build dirs

**Scripts:** 30. \[ ] `typecheck` - uses `nuxt typecheck` (not `tsc`) 31. \[ ] `dev:prepare` - prepares module + playground 32. \[ ] `prepare:fixtures` - prepares test fixtures 33. \[ ] `.github/workflows/test.yml` - includes the prepare step and Markdown path filtering

### Sync Process

#### Phase 0: Detect Project Type

Determine from cwd path whether this is a **Package** (`*/pkg/*`) or **Site** (`*/sites/*`, `*/site/*`).

#### Phase 1: Config Review

Read the config files directly (one batch of parallel Read calls) and compare against the checklist. The comparison is cross-cutting (catalog ↔ lockfile ↔ exports ↔ tsconfig interact), so read inline to keep the whole picture in context. Exception: for a large monorepo where one read pass is unwieldy, delegate per-package walks to `subagent_type=Explore`.

Read for **all project types**:

- `pnpm-workspace.yaml`, `package.json` — deps, catalogs, `packageManager`, `type`
- `.github/workflows/*.yml` — action versions against v6 standards
- `eslint.config.{js,mjs}`, `tsconfig.json`, `.editorconfig`, `.gitignore`

**If Package**, also read: `build.config.ts`, `vitest.config.ts`, package `exports`, release scripts.

**If Site**, also read: `nuxt.config.ts`, `app/` structure (`pages/`, `layouts/`, `components/`), `.npmrc`.

**If Nuxt module** (Package + `@nuxt/module-builder`), also read: `src/module.ts` (registration methods, resolver, options), `src/runtime/app/` (composables/plugins/imports), `src/runtime/server/` (handlers/plugins/middleware — verify no Vue deps), `playground/` + `test/fixtures/` (nuxt.config, prepare scripts, test patterns).

#### Phase 2: Apply Changes

Based on the review, apply necessary updates using the appropriate checklist (Package or Site).

#### Phase 3: Parallel Verification

**Package** verification:

```
Bash(background): pnpm install
Bash(background): pnpm lint
Bash(background): pnpm typecheck
```

Then sequentially (depends on install):

```
Bash: pnpm build
Bash: pnpm test --run
```

**Site** verification:

```
Bash(background): pnpm install
Bash(background): pnpm lint
Bash(background): pnpm typecheck  # Uses nuxt typecheck
```

Then sequentially:

```
Bash: pnpm build  # nuxi build
```

**Nuxt module** verification:

```
Bash: pnpm dev:prepare && pnpm prepare:fixtures
Bash(background): pnpm lint
Bash(background): pnpm typecheck  # Uses nuxt typecheck
Bash: pnpm test:run
```

Source: [SKILL.md on GitHub](https://github.com/harlan-zw/harlan-agent-kit/blob/491d032ad2b040c879097c10fe563c1a4655be6d/harlan-agent-kit/skills/pkg-conform/SKILL.md)

## Related skills

-
-
-
-
-
-