pmpt-cli 1.15.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,8 @@
10
10
 
11
11
  Plan with 5 questions. Build with AI. Save every version. Share and reproduce.
12
12
 
13
+ Every session, every decision, every constraint — accumulated in one file your AI can always read.
14
+
13
15
  [Quick Start](#quick-start) · [Commands](#commands) · [MCP Server](#mcp-server) · [Explore Projects](#explore-projects)
14
16
 
15
17
  </div>
@@ -65,6 +67,7 @@ pmpt explore
65
67
  | | Without pmpt | With pmpt |
66
68
  |---|---|---|
67
69
  | **Planning** | Stare at blank screen, write vague prompts | Answer 5 guided questions, get structured AI prompt |
70
+ | **Context** | Re-explain the same decisions every AI session | AI reads pmpt.md and knows why things are the way they are |
68
71
  | **Tracking** | Lose track of what you built and how | Every version auto-saved with full history |
69
72
  | **Sharing** | Share finished code only | Share the entire journey — others can reproduce it |
70
73
 
@@ -92,8 +95,14 @@ The generated prompt is **automatically copied to your clipboard**. Just paste i
92
95
 
93
96
  | Command | Description |
94
97
  |---------|-------------|
95
- | `pmpt init` | Initialize project and start tracking |
98
+ | `pmpt init` | Initialize project sets up `.pmpt/`, selects AI tool, creates entry points |
99
+ | `pmpt harness` | Add harness to existing project — missing pmpt.md sections + index.md + tool entry points |
96
100
  | `pmpt plan` | 5 questions → AI prompt (auto-copied to clipboard) |
101
+ | `pmpt plan --template` | Generate a fillable `answers.json` (Windows/PowerShell friendly) |
102
+ | `pmpt plan --answers-file <f>` | Run plan non-interactively from a JSON file |
103
+ | `pmpt constraint add "<rule>"` | Add an architecture rule to pmpt.md |
104
+ | `pmpt constraint list` | List all constraints |
105
+ | `pmpt constraint remove <n>` | Remove a constraint by index |
97
106
  | `pmpt save` | Save current state as a snapshot |
98
107
  | `pmpt watch` | Auto-detect file changes and save versions |
99
108
  | `pmpt status` | Check project status, tracked files, and quality score |
@@ -213,18 +222,37 @@ All tools accept an optional `projectPath` parameter (defaults to cwd).
213
222
 
214
223
  ```
215
224
  your-project/
225
+ ├── CLAUDE.md # Claude Code entry point → points to .pmpt/index.md
226
+ ├── .cursorrules # Cursor entry point → points to .pmpt/index.md
227
+ ├── AGENTS.md # Codex entry point → points to .pmpt/index.md
216
228
  └── .pmpt/
229
+ ├── index.md # AI context map (entry point for all tools)
217
230
  ├── config.json # Project configuration
218
- ├── docs/ # Generated documents
231
+ ├── docs/
232
+ │ ├── pmpt.md # Single source of truth — architecture, constraints,
233
+ │ │ # decisions, lessons, progress, snapshot log
219
234
  │ ├── plan.md # Product plan (features checklist)
220
- ├── pmpt.md # Progress tracking & decisions
221
- │ └── pmpt.ai.md # AI-ready prompt (project context & instructions)
235
+ └── pmpt.ai.md # AI-ready prompt (paste into your AI tool)
222
236
  └── .history/ # Auto-saved version history
223
237
  ├── v1-2024-02-20/
224
238
  ├── v2-2024-02-21/
225
239
  └── ...
226
240
  ```
227
241
 
242
+ ### pmpt.md — Single Source of Truth
243
+
244
+ `pmpt.md` is the living document that your AI reads at the start of every session. It accumulates everything the AI needs to understand your project:
245
+
246
+ | Section | What to record |
247
+ |---------|---------------|
248
+ | `## Architecture` | High-level structure — update as it evolves |
249
+ | `## Active Work` | What's currently being built (clear when done) |
250
+ | `## Decisions` | WHY, not just WHAT — include what led to each decision |
251
+ | `## Constraints` | Platform/library limitations and workarounds |
252
+ | `## Lessons` | Anti-patterns: what failed → root cause → fix applied |
253
+
254
+ The more you fill this in, the less you re-explain to AI every session.
255
+
228
256
  ---
229
257
 
230
258
  ## .pmpt File Format
@@ -0,0 +1,92 @@
1
+ import * as p from '@clack/prompts';
2
+ import { resolve } from 'path';
3
+ import { isInitialized } from '../lib/config.js';
4
+ import { readConstraints, addConstraint, removeConstraint } from '../lib/harness.js';
5
+ export async function cmdConstraint(action, options = {}) {
6
+ const projectPath = resolve(process.cwd());
7
+ if (!isInitialized(projectPath)) {
8
+ p.intro('pmpt constraint');
9
+ p.log.error('Project not initialized. Run `pmpt init` first.');
10
+ process.exit(1);
11
+ }
12
+ if (action === 'list') {
13
+ const constraints = readConstraints(projectPath);
14
+ p.intro('pmpt constraint list');
15
+ if (constraints.length === 0) {
16
+ p.log.info('No constraints defined yet.');
17
+ p.log.message(` pmpt constraint add "<rule>"`);
18
+ }
19
+ else {
20
+ p.log.message('');
21
+ constraints.forEach((rule, i) => {
22
+ p.log.message(` ${i + 1}. ${rule}`);
23
+ });
24
+ p.log.message('');
25
+ p.log.info(`${constraints.length} constraint(s) in .pmpt/docs/constraints.md`);
26
+ }
27
+ p.outro('');
28
+ return;
29
+ }
30
+ if (action === 'add') {
31
+ p.intro('pmpt constraint add');
32
+ let rule = options.rule;
33
+ if (!rule) {
34
+ const input = await p.text({
35
+ message: 'Enter constraint rule:',
36
+ placeholder: 'e.g., UI does not import Service directly',
37
+ validate: (v) => (!v ? 'Rule cannot be empty' : undefined),
38
+ });
39
+ if (p.isCancel(input)) {
40
+ p.cancel('Cancelled');
41
+ process.exit(0);
42
+ }
43
+ rule = input;
44
+ }
45
+ const ok = addConstraint(projectPath, rule);
46
+ if (!ok) {
47
+ p.log.error('Could not find ## Constraints section in .pmpt/docs/pmpt.md');
48
+ process.exit(1);
49
+ }
50
+ p.log.success(`Added: ${rule}`);
51
+ p.log.info('File: .pmpt/docs/pmpt.md');
52
+ p.outro('');
53
+ return;
54
+ }
55
+ if (action === 'remove') {
56
+ p.intro('pmpt constraint remove');
57
+ const constraints = readConstraints(projectPath);
58
+ if (constraints.length === 0) {
59
+ p.log.warn('No constraints to remove.');
60
+ p.outro('');
61
+ return;
62
+ }
63
+ let idx;
64
+ if (options.index) {
65
+ idx = parseInt(options.index, 10);
66
+ }
67
+ else {
68
+ // Interactive selection
69
+ const choice = await p.select({
70
+ message: 'Select constraint to remove:',
71
+ options: constraints.map((rule, i) => ({
72
+ value: String(i + 1),
73
+ label: `${i + 1}. ${rule}`,
74
+ })),
75
+ });
76
+ if (p.isCancel(choice)) {
77
+ p.cancel('Cancelled');
78
+ process.exit(0);
79
+ }
80
+ idx = parseInt(choice, 10);
81
+ }
82
+ const removed = removeConstraint(projectPath, idx);
83
+ if (removed === null) {
84
+ p.log.error(`No constraint at index ${idx}.`);
85
+ }
86
+ else {
87
+ p.log.success(`Removed: ${removed}`);
88
+ }
89
+ p.outro('');
90
+ return;
91
+ }
92
+ }
@@ -0,0 +1,59 @@
1
+ import * as p from '@clack/prompts';
2
+ import { resolve, basename } from 'path';
3
+ import { isInitialized } from '../lib/config.js';
4
+ import { addMissingSections, ensureIndexMd, ensureCursorRules, ensureAgentsMd, ensureClaudeMdRef, } from '../lib/harness.js';
5
+ export async function cmdHarness(path) {
6
+ const projectPath = path ? resolve(path) : process.cwd();
7
+ const projectName = basename(projectPath);
8
+ p.intro('pmpt harness');
9
+ if (!isInitialized(projectPath)) {
10
+ p.log.error('Project not initialized. Run `pmpt init` first.');
11
+ process.exit(1);
12
+ }
13
+ // 1. Add missing sections to pmpt.md
14
+ const added = addMissingSections(projectPath);
15
+ if (added.length > 0) {
16
+ p.log.success(`Added to pmpt.md: ${added.join(', ')}`);
17
+ }
18
+ else {
19
+ p.log.info('pmpt.md already has all harness sections.');
20
+ }
21
+ // 2. Create .pmpt/index.md
22
+ ensureIndexMd(projectPath, projectName);
23
+ p.log.success('Created: .pmpt/index.md');
24
+ // 3. Ask which AI tool
25
+ const toolChoice = await p.select({
26
+ message: 'Which AI coding tool do you use?',
27
+ options: [
28
+ { value: 'claude', label: 'Claude Code', hint: 'CLAUDE.md → .pmpt/index.md' },
29
+ { value: 'cursor', label: 'Cursor', hint: '.cursorrules → .pmpt/index.md' },
30
+ { value: 'codex', label: 'Codex', hint: 'AGENTS.md → .pmpt/index.md' },
31
+ { value: 'all', label: 'All of the above' },
32
+ { value: 'skip', label: 'Skip' },
33
+ ],
34
+ });
35
+ if (p.isCancel(toolChoice) || toolChoice === 'skip') {
36
+ p.outro('Done. .pmpt/index.md created, pmpt.md updated.');
37
+ return;
38
+ }
39
+ const tool = toolChoice;
40
+ const created = [];
41
+ if (tool === 'claude' || tool === 'all') {
42
+ ensureClaudeMdRef(projectPath);
43
+ created.push('CLAUDE.md (updated)');
44
+ }
45
+ if (tool === 'cursor' || tool === 'all') {
46
+ ensureCursorRules(projectPath);
47
+ created.push('.cursorrules');
48
+ }
49
+ if (tool === 'codex' || tool === 'all') {
50
+ ensureAgentsMd(projectPath, projectName);
51
+ created.push('AGENTS.md');
52
+ }
53
+ if (created.length > 0) {
54
+ p.log.success(`Created: ${created.join(', ')}`);
55
+ }
56
+ p.log.message('');
57
+ p.log.info('AI tools will now read .pmpt/index.md → .pmpt/docs/pmpt.md at session start.');
58
+ p.outro('Harness ready.');
59
+ }
@@ -7,6 +7,7 @@ import { cmdPlan } from './plan.js';
7
7
  import { scanProject, scanResultToAnswers } from '../lib/scanner.js';
8
8
  import { savePlanDocuments, initPlanProgress, savePlanProgress, generateAnswersTemplate } from '../lib/plan.js';
9
9
  import { copyToClipboard } from '../lib/clipboard.js';
10
+ import { setupHarnessForTools } from '../lib/harness.js';
10
11
  export async function cmdInit(path, options) {
11
12
  p.intro('pmpt init');
12
13
  const projectPath = path ? resolve(path) : process.cwd();
@@ -100,14 +101,34 @@ export async function cmdInit(path, options) {
100
101
  // Add pmpt MCP instructions to CLAUDE.md and register .mcp.json for Claude Code
101
102
  ensurePmptClaudeMd(projectPath);
102
103
  ensureMcpJson(projectPath);
104
+ // Ask which AI tool to set up harness for
105
+ const toolChoice = await p.select({
106
+ message: 'Which AI coding tool do you use?',
107
+ options: [
108
+ { value: 'claude', label: 'Claude Code', hint: 'CLAUDE.md + .pmpt/index.md' },
109
+ { value: 'cursor', label: 'Cursor', hint: '.cursorrules + .pmpt/index.md' },
110
+ { value: 'codex', label: 'Codex', hint: 'AGENTS.md + .pmpt/index.md' },
111
+ { value: 'all', label: 'All of the above', hint: 'Create all entry points' },
112
+ { value: 'skip', label: 'Skip', hint: 'Set up later with `pmpt harness`' },
113
+ ],
114
+ });
115
+ if (p.isCancel(toolChoice)) {
116
+ p.cancel('Cancelled');
117
+ process.exit(0);
118
+ }
119
+ if (toolChoice !== 'skip') {
120
+ setupHarnessForTools(projectPath, basename(projectPath), toolChoice);
121
+ }
103
122
  // Build folder structure display
104
123
  const notes = [
105
124
  `Path: ${config.projectPath}`,
106
125
  '',
107
126
  'Folder structure:',
108
127
  ` .pmpt/`,
128
+ ` ├── index.md AI entry point`,
109
129
  ` ├── config.json Config`,
110
- ` ├── docs/ Your docs`,
130
+ ` ├── docs/`,
131
+ ` │ └── pmpt.md Source of truth (architecture, constraints, decisions)`,
111
132
  ` └── .history/ Snapshots`,
112
133
  ];
113
134
  if (config.repo) {
@@ -301,16 +322,25 @@ function ensureMinimalDocs(projectPath) {
301
322
  const skeleton = [
302
323
  `# ${name}`,
303
324
  '',
325
+ '## Architecture',
326
+ '<!-- High-level structure. Update as it evolves. -->',
327
+ '',
328
+ '## Active Work',
329
+ '<!-- What\'s currently being built. Clear when done, move to Snapshot Log. -->',
330
+ '',
304
331
  '## Progress',
305
332
  '- Project initialized',
306
333
  '',
307
334
  '## Snapshot Log',
308
335
  '',
309
336
  '## Decisions',
337
+ '<!-- WHY, not just WHAT. Format: - [Decision] → [Reason] -->',
310
338
  '',
311
339
  '## Constraints',
340
+ '<!-- Platform/library limitations. Format: - [Tool]: limitation → workaround -->',
312
341
  '',
313
342
  '## Lessons',
343
+ '<!-- Anti-patterns. Format: - [What failed] → [Root cause] → [Fix applied] -->',
314
344
  '',
315
345
  ].join('\n');
316
346
  writeFileSync(pmptMdPath, skeleton, 'utf-8');
package/dist/index.js CHANGED
@@ -46,6 +46,8 @@ import { cmdDiff } from './commands/diff.js';
46
46
  import { cmdInternalSeed } from './commands/internal-seed.js';
47
47
  import { cmdMcpSetup } from './commands/mcp-setup.js';
48
48
  import { cmdDoctor } from './commands/doctor.js';
49
+ import { cmdConstraint } from './commands/constraint.js';
50
+ import { cmdHarness } from './commands/harness.js';
49
51
  import { trackCommand } from './lib/api.js';
50
52
  import { checkForUpdates } from './lib/update-check.js';
51
53
  import { createRequire } from 'module';
@@ -153,6 +155,27 @@ program
153
155
  ...options,
154
156
  template: options.template === true ? 'answers.json' : options.template,
155
157
  }));
158
+ program
159
+ .command('harness [path]')
160
+ .description('Set up AI context harness for existing projects — adds missing pmpt.md sections and creates tool entry points')
161
+ .action(cmdHarness);
162
+ program
163
+ .command('constraint <action>')
164
+ .description('Manage architecture constraints — add, list, or remove rules')
165
+ .option('-r, --rule <rule>', 'Rule text (for add)')
166
+ .option('-i, --index <n>', 'Rule index (for remove)')
167
+ .addHelpText('after', `
168
+ Actions:
169
+ add Add a constraint rule
170
+ list List all constraints
171
+ remove Remove a constraint by index
172
+
173
+ Examples:
174
+ pmpt constraint add "UI does not import Service directly"
175
+ pmpt constraint list
176
+ pmpt constraint remove 2
177
+ `)
178
+ .action((action, options) => cmdConstraint(action, options));
156
179
  program
157
180
  .command('logout')
158
181
  .description('Clear saved GitHub authentication')
@@ -0,0 +1,230 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { getConfigDir, getDocsDir } from './config.js';
4
+ // ─── index.md — lightweight map pointing to pmpt.md ───────────────
5
+ export function generateIndexMd(projectName) {
6
+ return `# ${projectName} — Project Context
7
+
8
+ > AI entry point. Read this first, then follow the links below.
9
+
10
+ ## Map
11
+
12
+ | File | Purpose |
13
+ |------|---------|
14
+ | [.pmpt/docs/pmpt.md](.pmpt/docs/pmpt.md) | **Source of truth** — architecture, constraints, decisions, progress |
15
+ | [.pmpt/docs/pmpt.ai.md](.pmpt/docs/pmpt.ai.md) | Full AI prompt — paste into your AI tool to get started |
16
+
17
+ ## Rules for AI
18
+
19
+ 1. Read \`.pmpt/docs/pmpt.md\` before making any code changes
20
+ 2. Follow every rule listed in the **## Constraints** section of pmpt.md
21
+ 3. After milestones, call \`mcp__pmpt__pmpt_save\` (or \`pmpt save\` in terminal)
22
+ 4. Update pmpt.md when architecture, constraints, or features change
23
+ `;
24
+ }
25
+ // ─── Tool-specific entry points ────────────────────────────────────
26
+ export function generateCursorRules() {
27
+ return `# Project Rules
28
+
29
+ See \`.pmpt/index.md\` for the project context map.
30
+
31
+ The single source of truth is \`.pmpt/docs/pmpt.md\`.
32
+ Always check the **## Constraints** section before making code changes.
33
+ After completing milestones, run \`pmpt save\` in terminal.
34
+ `;
35
+ }
36
+ export function generateAgentsMd(projectName) {
37
+ return `# ${projectName} — Agent Instructions
38
+
39
+ See \`.pmpt/index.md\` for the project context map.
40
+
41
+ The single source of truth is \`.pmpt/docs/pmpt.md\`.
42
+ Always check the **## Constraints** section before making code changes.
43
+ After completing milestones, run \`pmpt save\` in terminal.
44
+ `;
45
+ }
46
+ // ─── Setup functions ───────────────────────────────────────────────
47
+ export function ensureIndexMd(projectPath, projectName) {
48
+ const configDir = getConfigDir(projectPath);
49
+ mkdirSync(configDir, { recursive: true });
50
+ const indexPath = join(configDir, 'index.md');
51
+ if (!existsSync(indexPath)) {
52
+ writeFileSync(indexPath, generateIndexMd(projectName), 'utf-8');
53
+ }
54
+ }
55
+ export function ensureCursorRules(projectPath) {
56
+ const path = join(projectPath, '.cursorrules');
57
+ if (!existsSync(path)) {
58
+ writeFileSync(path, generateCursorRules(), 'utf-8');
59
+ }
60
+ }
61
+ export function ensureAgentsMd(projectPath, projectName) {
62
+ const path = join(projectPath, 'AGENTS.md');
63
+ if (!existsSync(path)) {
64
+ writeFileSync(path, generateAgentsMd(projectName), 'utf-8');
65
+ }
66
+ }
67
+ export function setupHarnessForTools(projectPath, projectName, tools) {
68
+ // index.md is always created — it's the lightweight map
69
+ ensureIndexMd(projectPath, projectName);
70
+ if (tools === 'cursor' || tools === 'all') {
71
+ ensureCursorRules(projectPath);
72
+ }
73
+ if (tools === 'codex' || tools === 'all') {
74
+ ensureAgentsMd(projectPath, projectName);
75
+ }
76
+ if (tools === 'claude' || tools === 'all') {
77
+ ensureClaudeMdIndexRef(projectPath);
78
+ }
79
+ }
80
+ export function ensureClaudeMdRef(projectPath) {
81
+ ensureClaudeMdIndexRef(projectPath);
82
+ }
83
+ function ensureClaudeMdIndexRef(projectPath) {
84
+ const claudeMdPath = join(projectPath, 'CLAUDE.md');
85
+ const marker = '<!-- pmpt-index -->';
86
+ const section = `${marker}\nSee \`.pmpt/index.md\` for project context. Single source of truth: \`.pmpt/docs/pmpt.md\`.\n<!-- /pmpt-index -->`;
87
+ if (!existsSync(claudeMdPath))
88
+ return;
89
+ const content = readFileSync(claudeMdPath, 'utf-8');
90
+ if (content.includes(marker))
91
+ return;
92
+ const pmptMarker = '<!-- pmpt -->';
93
+ if (content.includes(pmptMarker)) {
94
+ writeFileSync(claudeMdPath, content.replace(pmptMarker, section + '\n\n' + pmptMarker), 'utf-8');
95
+ }
96
+ else {
97
+ writeFileSync(claudeMdPath, section + '\n\n' + content, 'utf-8');
98
+ }
99
+ }
100
+ // ─── pmpt.md section migration ────────────────────────────────────
101
+ const HARNESS_SECTIONS = [
102
+ {
103
+ heading: '## Architecture',
104
+ comment: '<!-- High-level structure. Update as it evolves. -->\n<!-- Example: "Next.js frontend → Cloudflare Workers API → D1 database" -->',
105
+ },
106
+ {
107
+ heading: '## Active Work',
108
+ comment: '<!-- What\'s currently being built. Clear when done, move to Snapshot Log. -->',
109
+ },
110
+ {
111
+ heading: '## Constraints',
112
+ comment: '<!-- Platform or library limitations discovered during development. -->\n<!-- Format: - [Platform/Tool]: what doesn\'t work → workaround used -->',
113
+ },
114
+ {
115
+ heading: '## Lessons',
116
+ comment: '<!-- Anti-patterns and "tried X, broke because Y" discoveries. -->\n<!-- Format: - [What failed] → [Root cause] → [Fix applied] -->',
117
+ },
118
+ ];
119
+ /**
120
+ * Add missing harness sections to an existing pmpt.md.
121
+ * Returns list of section headings that were added.
122
+ */
123
+ export function addMissingSections(projectPath) {
124
+ const pmptMdPath = join(getDocsDir(projectPath), 'pmpt.md');
125
+ if (!existsSync(pmptMdPath))
126
+ return [];
127
+ let content = readFileSync(pmptMdPath, 'utf-8');
128
+ const added = [];
129
+ for (const section of HARNESS_SECTIONS) {
130
+ if (content.includes(section.heading))
131
+ continue;
132
+ // Insert before ## Decisions if it exists, otherwise append
133
+ const insertBefore = '## Decisions';
134
+ const block = `${section.heading}\n${section.comment}\n`;
135
+ if (content.includes(insertBefore)) {
136
+ content = content.replace(insertBefore, block + '\n' + insertBefore);
137
+ }
138
+ else {
139
+ content = content.trimEnd() + '\n\n' + block;
140
+ }
141
+ added.push(section.heading);
142
+ }
143
+ if (added.length > 0) {
144
+ writeFileSync(pmptMdPath, content, 'utf-8');
145
+ }
146
+ return added;
147
+ }
148
+ // ─── Constraint management — reads/writes pmpt.md ## Constraints ──
149
+ export function readConstraints(projectPath) {
150
+ const pmptMdPath = join(getDocsDir(projectPath), 'pmpt.md');
151
+ if (!existsSync(pmptMdPath))
152
+ return [];
153
+ const lines = readFileSync(pmptMdPath, 'utf-8').split('\n');
154
+ const inSection = { value: false };
155
+ const rules = [];
156
+ for (const line of lines) {
157
+ if (line.trim() === '## Constraints') {
158
+ inSection.value = true;
159
+ continue;
160
+ }
161
+ if (inSection.value && line.startsWith('## '))
162
+ break;
163
+ if (inSection.value && line.trimStart().startsWith('- ') && !line.includes('<!--')) {
164
+ rules.push(line.trimStart().slice(2).trim());
165
+ }
166
+ }
167
+ return rules;
168
+ }
169
+ export function addConstraint(projectPath, rule) {
170
+ const pmptMdPath = join(getDocsDir(projectPath), 'pmpt.md');
171
+ if (!existsSync(pmptMdPath))
172
+ return false;
173
+ const lines = readFileSync(pmptMdPath, 'utf-8').split('\n');
174
+ let sectionEnd = -1;
175
+ let inSection = false;
176
+ for (let i = 0; i < lines.length; i++) {
177
+ if (lines[i].trim() === '## Constraints') {
178
+ inSection = true;
179
+ continue;
180
+ }
181
+ if (inSection && lines[i].startsWith('## ')) {
182
+ sectionEnd = i;
183
+ break;
184
+ }
185
+ }
186
+ const newLine = `- ${rule}`;
187
+ if (sectionEnd !== -1) {
188
+ // Insert before next section, after any existing content
189
+ lines.splice(sectionEnd, 0, newLine);
190
+ }
191
+ else if (inSection) {
192
+ lines.push(newLine);
193
+ }
194
+ else {
195
+ return false;
196
+ }
197
+ writeFileSync(pmptMdPath, lines.join('\n'), 'utf-8');
198
+ return true;
199
+ }
200
+ export function removeConstraint(projectPath, index) {
201
+ const pmptMdPath = join(getDocsDir(projectPath), 'pmpt.md');
202
+ if (!existsSync(pmptMdPath))
203
+ return null;
204
+ const lines = readFileSync(pmptMdPath, 'utf-8').split('\n');
205
+ let inSection = false;
206
+ let ruleCount = 0;
207
+ let removedRule = null;
208
+ const newLines = lines.filter((line) => {
209
+ if (line.trim() === '## Constraints') {
210
+ inSection = true;
211
+ return true;
212
+ }
213
+ if (inSection && line.startsWith('## ')) {
214
+ inSection = false;
215
+ return true;
216
+ }
217
+ if (inSection && line.trimStart().startsWith('- ') && !line.includes('<!--')) {
218
+ ruleCount++;
219
+ if (ruleCount === index) {
220
+ removedRule = line.trimStart().slice(2).trim();
221
+ return false;
222
+ }
223
+ }
224
+ return true;
225
+ });
226
+ if (removedRule === null)
227
+ return null;
228
+ writeFileSync(pmptMdPath, newLines.join('\n'), 'utf-8');
229
+ return removedRule;
230
+ }
package/dist/lib/plan.js CHANGED
@@ -118,17 +118,27 @@ After completing each feature above:
118
118
 
119
119
  ### What to Record in pmpt.md
120
120
 
121
- **## Decisions** Record WHY, not just WHAT. Include the data or observation that led to the decision.
122
- - Bad: "Set minimum description length to 150 chars"
123
- - Good: "Set minimum description length to 150 chars (50-char threshold caused 60% low-quality entries)"
121
+ pmpt.md is the **single source of truth** for this project. AI tools read it to understand context before every session. Keep it accurate.
124
122
 
125
- **## Constraints** — Record platform/library limitations discovered during development.
126
- - Examples: DB quirks, API limits, framework restrictions, version incompatibilities
127
- - Format: \`- [Platform]: what doesn't work workaround used\`
123
+ **## Architecture** — High-level structure. Update when the architecture changes.
124
+ - Example: \`Next.js (SSG) Cloudflare Workers API D1 database\`
125
+ - Include the WHY if the stack choice was non-obvious
128
126
 
129
- **## Lessons** — Record anti-patterns and "we tried X, it broke because Y" discoveries.
130
- - Examples: wrong deletion order causing FK errors, caching issues, race conditions
127
+ **## Active Work** — What's currently being built. One or two items max.
128
+ - Clear this section when done, then move to Snapshot Log
129
+ - Example: \`- Implementing user auth (started 2025-03-17)\`
130
+
131
+ **## Decisions** — Record WHY, not just WHAT. Include what led to the decision.
132
+ - Bad: "Switched to SQLite"
133
+ - Good: "Switched SQLite → Postgres: deploy target moved to serverless, needed connection pooling"
134
+
135
+ **## Constraints** — Platform or library limitations discovered during development.
136
+ - Format: \`- [Platform/Tool]: what doesn't work → workaround used\`
137
+ - Example: \`- Cloudflare Workers: no native fs access → use KV for file storage\`
138
+
139
+ **## Lessons** — Anti-patterns and "tried X, broke because Y" discoveries.
131
140
  - Format: \`- [What failed] → [Root cause] → [Fix applied]\`
141
+ - Example: \`- JWT refresh on mobile broke → tokens expired before retry → added sliding expiry\`
132
142
  `;
133
143
  }
134
144
  // Generate human-facing project document (pmpt.md)
@@ -153,24 +163,38 @@ ${contextSection}
153
163
  ## Features
154
164
  ${features}
155
165
  ${techSection}
166
+ ## Architecture
167
+ <!-- High-level structure. Update as it evolves. -->
168
+ <!-- Example: "Next.js frontend → Express API → PostgreSQL" -->
169
+
170
+ ## Active Work
171
+ <!-- What's currently being built. Clear when done, move to Snapshot Log. -->
172
+
156
173
  ## Progress
157
174
  - [ ] Project setup
158
175
  - [ ] Core features implementation
159
176
  - [ ] Testing & polish
160
177
 
161
178
  ## Snapshot Log
162
- ### v1 - Initial Setup
179
+ ### v1 Initial Setup
163
180
  - Project initialized with pmpt
164
181
 
165
182
  ## Decisions
183
+ <!-- WHY, not just WHAT. Include what led to the decision. -->
184
+ <!-- Format: - [Decision] → [Reason / data that led to it] -->
166
185
 
167
186
  ## Constraints
187
+ <!-- Platform or library limitations discovered during development. -->
188
+ <!-- Format: - [Platform/Tool]: what doesn't work → workaround used -->
168
189
 
169
190
  ## Lessons
191
+ <!-- Anti-patterns and "tried X, broke because Y" discoveries. -->
192
+ <!-- Format: - [What failed] → [Root cause] → [Fix applied] -->
170
193
 
171
194
  ---
172
- *This document tracks your project progress. Update it as you build.*
173
- *AI instructions are in \`pmpt.ai.md\` paste that into your AI tool.*
195
+ *This document is the single source of truth for this project.*
196
+ *AI tools read this to understand context, constraints, and current state.*
197
+ *AI instructions are in \`pmpt.ai.md\` — paste that into your AI tool to get started.*
174
198
  `;
175
199
  }
176
200
  // Generate plan document
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmpt-cli",
3
- "version": "1.15.0",
3
+ "version": "1.18.0",
4
4
  "description": "Record and share your AI-driven product development journey",
5
5
  "type": "module",
6
6
  "bin": {