All skills
harlan-zw avatar

/pkg-conform

by Harlan Wiltonharlan-zw/harlan-agent-kit10 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 Updated 1 hour ago

Use this Skill: https://skilld.dev/gh/harlan-zw/harlan-agent-kit/pkg-conform

Raw

Package Conform Skill

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

Worktree isolation

Before any edit, follow the worktree isolation contract. 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 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.


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/*)

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

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

  1. 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
  2. Scripts - dev (nuxi dev), build (nuxi prepare && nuxi build), postinstall (nuxt prepare), lint, lint:fix, typecheck (nuxt typecheck)
  3. pnpm.overrides - vite set to ^8.0.0
  4. nuxt.config.ts - future.compatibilityVersion: 5, compatibilityDate, standard module stack
  5. tsconfig.json - just { "extends": "./.nuxt/tsconfig.json" }
  6. eslint.config.js - antfu config with node/prefer-global/process and node/prefer-global/buffer off
  7. .npmrc - shamefully-hoist=true
  8. .gitignore - includes .nuxt/, .output/, .data/, .wrangler/, wrangler.toml
  9. .editorconfig - 2-space indent, LF, UTF-8, trim trailing whitespace (except .md)
  10. content.config.ts - Zod schemas for content collections (if using @nuxt/content)
  11. app/ directory - Nuxt 4 structure (app.vue, pages/, layouts/, components/, composables/)
  12. .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