# Code Style & Gotchas > Part of [AGENTS.md](../AGENTS.md) โ€” project guidance for AI coding agents. ## Code Style - **install.js:** CommonJS, Node.js built-ins only (no external deps), ANSI colors via `COLORS` constant, readline-based prompts - **plan2code-loop & plan2code-metrics:** TypeScript + ESM, built with tsup (target ES2022, moduleResolution: bundler) - External deps: `@inquirer/prompts`, `chalk`, `execa`, `ora` - Interactive CLI via `@inquirer/prompts` (select, input, confirm) - **File operations:** Synchronous fs in all packages ## Gotchas / Pitfalls - **Version sync:** When adding a new version to `CHANGELOG.md`, also update `version.json` and `package.json` (root) to match. Check `README.md` for any version badges or references that need updating. The installer displays the version from `version.json` in its header. All three files (`CHANGELOG.md`, `version.json`, `package.json`) must always show the same version number. - **CHANGELOG ordering:** Entries in `CHANGELOG.md` must be in reverse-chronological order โ€” newest version at the top, oldest at the bottom. New entries are always inserted immediately after the file header. - **CHANGELOG house format is not Keep a Changelog:** version headings are `## vX.Y.Z` โ€” with a `v` prefix and **no date**. The release date is recorded only in `version.json`'s `releaseDate`. Category headings carry emoji: `### โœจ Added`, `### ๐Ÿ”ง Changed`, `### ๐Ÿ› Fixed`, `### ๐Ÿ’ฅ Breaking`, `### ๐Ÿ—‘๏ธ Removed`, `### ๐Ÿ“š Documentation`. Older entries contain one-off variants (`๐ŸŽ Added`, `๐Ÿ“ฆ Updated`, `๐Ÿ“ Documentation`, `๐ŸŽ๏ธ Improved`, `๐Ÿงช Testing`) โ€” do not introduce new ones. The `.claude/skills/plan2code-changelog/` skill automates version selection and formatting; use it rather than hand-rolling an entry. - **PowerShell mangles the CHANGELOG emoji:** `Get-Content` / `Select-String` render the `###` heading emoji as `?` under the default Windows console encoding, so a heading audit done that way reports garbage. Read `CHANGELOG.md` with a file-read or grep tool instead. - **`.claude/skills/` is tracked, not ignored:** repo-local skills (`plan2code-changelog`, `plan2code-publish`, `sync-repo`) live there and are committed. Nothing in `.gitignore` touches `.claude/`, so a new skill only needs `git add`. Per the Failure Log convention in `AGENTS.md`, a correction that is a *workflow* rather than a rule belongs here as a skill, linked from AGENTS.md โ€” not as a Failure log line. - **Loop `.gitignore` setup:** `ensureGitignore()` runs at startup in `Controller.run()` as a pre-flight step, not just inside `createTaskCommit()`. This is critical for phase mode where the Node controller doesn't handle commits โ€” without it, `git add -A` would stage spec files. - **Workflow file character limit:** All `src/plan2code-*.md` files must be โ‰ค 11,000 characters. A husky pre-commit hook enforces this. The 11,000 limit leaves buffer for platform-specific YAML headers (106-142 chars) to stay under Windsurf's 12,000 char limit. - **Metrics internal prompts have no char limit:** Files in `plan2code-metrics/src/prompts/` are NOT subject to the 11,000 char limit โ€” only `src/plan2code-*.md` consumer-facing prompts are. - **User Feedback table format:** The `## User Feedback` markdown table in `overview.md` has a strict format the collector regex depends on. Field names must be exactly `Rating`, `Reason`, `Went Well`, `Went Poorly`. Pipe characters in values must be escaped as `\|`. - **PLAN-DRAFT confidence numbers are scraped by regex:** when a `specs//PLAN-DRAFT-*.md` contains no `` comment, `collector.ts` falls back to prose scraping (`collector.ts:186-241`). The overall-confidence pattern requires a literal `%`, but the four *breakdown* patterns (`collector.ts:201-204`) do **not** โ€” `/[Rr]equirements?[:\s|]+(\d{1,2})/` and its siblings match a bare dimension word followed by whitespace, a colon, or a pipe and then digits. So a PLAN-DRAFT written by anything other than `/plan2code-1-plan` Phase 7 must keep both the `%` sign **and** bare `Requirements` / `Feasibility` / `Integration` / `Risk` followed by a number off the page โ€” including innocent table rows like `| Requirements | 11 |`. Otherwise the metrics pipeline records a planning-step confidence that no planning step produced. `/plan2code-0-pathfinder` works around this by hyphenating the labels (`Requirements-clarity 22/25`), which breaks the character class. - **Reference file sizing guideline:** Files in `src/plan2code-*-references/` directories target ~100-200 lines each (soft guideline; evaluate splitting above 300). They are NOT subject to the 11,000 character limit. The pre-commit hook (`validate-char-count.js`) only checks `src/plan2code-*.md` flat files โ€” subdirectory contents are automatically excluded. - **The splitting guideline has a hard ceiling โ€” reference files cannot always be split:** two constraints bound it. (1) Each new reference costs the orchestrator a column-0 `Read references/.md` line plus its fallback blockquote (~150-200 chars), and orchestrators near the 11,000 limit have no room to spend. (2) **The path rewrite is not recursive** โ€” `syncPrompts()` rewrites `Read references/โ€ฆ` paths on the *orchestrator's* content only, so a `Read references/โ€ฆ` directive placed *inside* a reference file is never rewritten for flat-file targets; it ships as a dangling instruction pointing at a path that does not exist there. When a reference legitimately exceeds 300 lines (e.g. `plan2code-0-pathfinder-references/chart.md`), that is an accepted trade-off, not an oversight.