@aprimediet/codewalker 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aprimediet
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # @aprimediet/codewalker
2
+
3
+ Systematic **project intelligence** for the [pi coding agent](https://www.npmjs.com/package/@earendil-works/pi-coding-agent): analyze tech stack, goals, boundaries, status, and technical issues, then generate a **PRD** for humans and **AGENTS.md** / **CLAUDE.md** for coding agents — plus integration with `@aprimediet/minion` and `@aprimediet/memory`.
4
+
5
+ Documentation is split by audience: `docs/PRD.md` holds the product *what & why* (overview, goals, users, features, metrics); `AGENTS.md` holds the engineering *how* (tech stack, structure, commands, conventions, technical boundaries, gotchas); `CLAUDE.md` is a thin pointer that imports `AGENTS.md` as the single source of truth.
6
+
7
+ ## Phases
8
+
9
+ | Phase | What it does |
10
+ |-------|---|
11
+ | Phase 1 | Detect primary language, frameworks, infrastructure, and package manager from manifest files |
12
+ | Phase 2 | Find or gather project goals and non-goals (interactively, one question at a time) |
13
+ | Phase 3 | Document key entry points, external services, exposed interfaces, and technical constraints |
14
+ | Phase 4 | Scan recent commit history and search for technical debt markers (TODO/FIXME/HACK/BUG) |
15
+ | Phase 5 | Detect missing test directories, broken env files, invalid configs, and TypeScript strictness issues |
16
+ | Phase 6 | Generate docs, split by audience: `docs/PRD.md` (product), `AGENTS.md` (engineering), `CLAUDE.md` (pointer to AGENTS.md) — each with user confirmation |
17
+ | Phase 7 | Detect active `@aprimediet/minion` and `@aprimediet/memory` integrations via the shared `.pi/<id>.md` marker |
18
+ | Phase 8 | Compile full project intelligence document with all sections |
19
+ | Phase 9 | Store summary to memory (if active) or save to local file |
20
+
21
+ ## Install
22
+
23
+ ```bash
24
+ pi install npm:@aprimediet/codewalker
25
+ pi list
26
+ ```
27
+
28
+ ## Quick try
29
+
30
+ ```bash
31
+ pi -e ./extensions/codewalker/index.ts
32
+ ```
33
+
34
+ Then run `/learn-this` in any project.
35
+
36
+ ## Integration
37
+
38
+ codewalker automatically detects the presence of two companion extensions via a shared project marker:
39
+
40
+ **Minion Integration (read-only):**
41
+ - Reads the `.pi/<project-id>.md` marker file from the current working directory
42
+ - Checks `~/.pi/projects/<id>/tasks/` for open kanban cards (backlog, todo, in_progress, blocked, review)
43
+ - Counts and reports open task count during the `/learn-this` summary
44
+
45
+ **Memory Integration (read-only + write):**
46
+ - Reads the same `.pi/<project-id>.md` marker file
47
+ - Checks `~/.pi/projects/<id>/memory/` for active memory (MEMORY.md + entries/)
48
+ - Counts memory entries and reads the index during Phase 7
49
+ - In Phase 9, if memory is active, calls `memory_write` with scope `"project"` to store the full intelligence snapshot
50
+
51
+ Both integrations use **read-only detection** (no creation of files or directories); the marker file is created and managed by minion or memory when activated. codewalker coexists with them seamlessly in the same `~/.pi/projects/<id>/` workspace.
52
+
53
+ ## Layout
54
+
55
+ ```
56
+ codewalker/ # @aprimediet/codewalker
57
+ ├── package.json # pi manifest: extensions + skills
58
+ ├── index.ts # extension factory: /learn-this command (probes + triggers the workflow)
59
+ ├── compat.ts # minion + memory integration detection
60
+ ├── detect.ts # phase-specific file and marker detection
61
+ ├── prd.ts # PRD (human) search, read, and generation
62
+ ├── agents.ts # AGENTS.md + CLAUDE.md (agent) search and generation
63
+ └── skills/
64
+ └── learn-this/
65
+ └── SKILL.md # 9-phase intelligence gathering workflow + checklist
66
+ ```
67
+
68
+ The `/learn-this` command probes integration status, shows it, then sends a user message
69
+ that triggers the agent to invoke the `learn-this` skill and run all 9 phases.
70
+
71
+ No third-party runtime deps — only the pi-core packages (peer, bundled by pi).
package/agents.ts ADDED
@@ -0,0 +1,126 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+
4
+ // Agent-facing guide lives at the repo root by convention (AGENTS.md), with a thin
5
+ // CLAUDE.md pointer next to it so Claude Code auto-imports the same source of truth.
6
+ const AGENTS_CANDIDATES = ["AGENTS.md", ".agents/AGENTS.md", "docs/AGENTS.md"];
7
+ const CLAUDE_CANDIDATES = ["CLAUDE.md", ".claude/CLAUDE.md"];
8
+
9
+ export function findExistingAgentsMd(root: string): string | null {
10
+ for (const p of AGENTS_CANDIDATES) {
11
+ const filePath = path.join(root, p);
12
+ if (fs.existsSync(filePath)) {
13
+ return filePath;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+
19
+ export function findExistingClaudeMd(root: string): string | null {
20
+ for (const p of CLAUDE_CANDIDATES) {
21
+ const filePath = path.join(root, p);
22
+ if (fs.existsSync(filePath)) {
23
+ return filePath;
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+
29
+ export function createAgentsMd(root: string, content: string): string {
30
+ const outPath = path.join(root, "AGENTS.md");
31
+ fs.writeFileSync(outPath, content, "utf-8");
32
+ return outPath;
33
+ }
34
+
35
+ export function createClaudeMd(root: string, content: string): string {
36
+ const outPath = path.join(root, "CLAUDE.md");
37
+ fs.writeFileSync(outPath, content, "utf-8");
38
+ return outPath;
39
+ }
40
+
41
+ /**
42
+ * The agent-facing engineering guide. This is the "how to work in this repo" document:
43
+ * tech stack, structure, commands, conventions, technical boundaries, gotchas, and how
44
+ * the agent should use the minion/memory companion extensions. Product "what & why"
45
+ * (goals, users, features, metrics) belongs in the PRD, not here.
46
+ */
47
+ export function agentsMdTemplate(p: {
48
+ projectName: string;
49
+ summary: string;
50
+ techStack: string;
51
+ structure: string;
52
+ commands: { setup?: string; build?: string; test?: string; run?: string; lint?: string };
53
+ conventions: string;
54
+ boundaries: string;
55
+ knownIssues: string[];
56
+ integration: string;
57
+ currentFocus: string;
58
+ prdPath: string | null;
59
+ }): string {
60
+ const cmd = p.commands;
61
+ const commandRows = [
62
+ cmd.setup ? `- **Setup:** \`${cmd.setup}\`` : null,
63
+ cmd.build ? `- **Build:** \`${cmd.build}\`` : null,
64
+ cmd.test ? `- **Test:** \`${cmd.test}\`` : null,
65
+ cmd.run ? `- **Run:** \`${cmd.run}\`` : null,
66
+ cmd.lint ? `- **Lint:** \`${cmd.lint}\`` : null,
67
+ ]
68
+ .filter(Boolean)
69
+ .join("\n");
70
+ const commandsSection = commandRows || "_(none detected — ask the user)_";
71
+ const issuesSection = p.knownIssues.length
72
+ ? p.knownIssues.map((i) => `- ${i}`).join("\n")
73
+ : "_(none known)_";
74
+ const productLink = p.prdPath
75
+ ? `Product context (goals, users, features, success metrics): see [${p.prdPath}](${p.prdPath}).`
76
+ : "Product context: no PRD found.";
77
+
78
+ return `# AGENTS.md — ${p.projectName}
79
+
80
+ Guide for coding agents working in this repository. ${productLink}
81
+
82
+ ## Summary
83
+ ${p.summary}
84
+
85
+ ## Tech Stack
86
+ ${p.techStack}
87
+
88
+ ## Project Structure
89
+ ${p.structure}
90
+
91
+ ## Commands
92
+ ${commandsSection}
93
+
94
+ ## Conventions
95
+ ${p.conventions}
96
+
97
+ ## Boundaries (technical)
98
+ ${p.boundaries}
99
+
100
+ ## Known Issues & Gotchas
101
+ ${issuesSection}
102
+
103
+ ## Companion Extensions
104
+ ${p.integration}
105
+
106
+ ## Current Focus
107
+ ${p.currentFocus}
108
+ `;
109
+ }
110
+
111
+ /**
112
+ * A thin CLAUDE.md that points Claude Code at AGENTS.md as the single source of truth.
113
+ * The `@AGENTS.md` line triggers Claude Code's file-import so the content is pulled in.
114
+ */
115
+ export function claudeMdTemplate(projectName: string): string {
116
+ return `# CLAUDE.md — ${projectName}
117
+
118
+ Guidance for Claude Code in this repository.
119
+
120
+ All project conventions, architecture, build/test commands, and boundaries live in
121
+ **[AGENTS.md](./AGENTS.md)** — the shared guide for every coding agent. Keep that file
122
+ as the single source of truth; do not duplicate its content here.
123
+
124
+ @AGENTS.md
125
+ `;
126
+ }
package/compat.ts ADDED
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Compatibility probe: detect if @aprimediet/minion and @aprimediet/memory are active
3
+ * for this project by reading the shared .pi/<project-id>.md marker and probing
4
+ * global directories.
5
+ */
6
+
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import { CONFIG_DIR_NAME, getAgentDir, parseFrontmatter } from "@earendil-works/pi-coding-agent";
10
+
11
+ export interface CompatResult {
12
+ projectId: string | null;
13
+ minionActive: boolean;
14
+ memoryActive: boolean;
15
+ memoryEntries: number;
16
+ openTaskCount: number;
17
+ openTaskSummary: string;
18
+ memorySummary: string;
19
+ }
20
+
21
+ /**
22
+ * Walk upward from cwd until we find a dir containing .pi/ or .git/.
23
+ * Return cwd if root is reached without finding either.
24
+ */
25
+ function findProjectRoot(cwd: string): string {
26
+ let dir = cwd;
27
+ for (;;) {
28
+ const piPath = path.join(dir, CONFIG_DIR_NAME);
29
+ const gitPath = path.join(dir, ".git");
30
+ if (fs.existsSync(piPath) || fs.existsSync(gitPath)) {
31
+ return dir;
32
+ }
33
+ const parent = path.dirname(dir);
34
+ if (parent === dir) {
35
+ // reached filesystem root
36
+ return cwd;
37
+ }
38
+ dir = parent;
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Scan <configDir>/*.md files for one with frontmatter containing pi-project: true.
44
+ * Return that file's id: value, or null if none found.
45
+ */
46
+ function readMarkerId(configDir: string): string | null {
47
+ if (!fs.existsSync(configDir)) {
48
+ return null;
49
+ }
50
+
51
+ let names: string[];
52
+ try {
53
+ names = fs.readdirSync(configDir).filter((n) => n.endsWith(".md"));
54
+ } catch {
55
+ return null;
56
+ }
57
+
58
+ for (const name of names) {
59
+ const file = path.join(configDir, name);
60
+ try {
61
+ const content = fs.readFileSync(file, "utf-8");
62
+ const { frontmatter } = parseFrontmatter<Record<string, string>>(content);
63
+ if (frontmatter && String(frontmatter["pi-project"]) === "true" && frontmatter.id) {
64
+ return frontmatter.id;
65
+ }
66
+ } catch {
67
+ // not a valid marker, skip
68
+ }
69
+ }
70
+
71
+ return null;
72
+ }
73
+
74
+ /**
75
+ * Extract status and title from task frontmatter.
76
+ * Return { status, title } or null if cannot parse.
77
+ * title may be undefined if missing from frontmatter; callers should supply a fallback.
78
+ */
79
+ function parseTaskMetadata(content: string): { status: string; title: string | undefined } | null {
80
+ try {
81
+ const { frontmatter } = parseFrontmatter<Record<string, string>>(content);
82
+ if (!frontmatter) return null;
83
+ const status = frontmatter.status || "";
84
+ const title = frontmatter.title || undefined;
85
+ if (!status) return null;
86
+ return { status, title };
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Probe minion integration: check if <globalDir>/tasks/ exists and has open tasks.
94
+ * Return { openTasks, openTaskSummary } or null if minion is not active.
95
+ */
96
+ function probeMinionTasks(globalDir: string): { openTasks: number; openTaskSummary: string } | null {
97
+ const tasksDir = path.join(globalDir, "tasks");
98
+
99
+ // If tasks dir doesn't exist, minion is not active for this project
100
+ if (!fs.existsSync(tasksDir)) {
101
+ return null;
102
+ }
103
+
104
+ const OPEN_STATUSES = new Set(["backlog", "todo", "in_progress", "blocked", "review"]);
105
+ const openTasks: string[] = [];
106
+
107
+ try {
108
+ const names = fs.readdirSync(tasksDir);
109
+ for (const name of names) {
110
+ if (!name.endsWith(".md")) continue;
111
+ const file = path.join(tasksDir, name);
112
+ try {
113
+ const content = fs.readFileSync(file, "utf-8");
114
+ const meta = parseTaskMetadata(content);
115
+ if (meta && OPEN_STATUSES.has(meta.status)) {
116
+ const taskTitle = meta.title ?? name.replace(/\.md$/, "");
117
+ openTasks.push(`${meta.status}: ${taskTitle}`);
118
+ if (openTasks.length >= 10) break;
119
+ }
120
+ } catch {
121
+ // skip unparseable files
122
+ }
123
+ }
124
+ } catch {
125
+ // tasks dir exists but is unreadable — still report as active
126
+ }
127
+
128
+ const summary = openTasks.length > 0 ? openTasks.join("\n") : "(no open tasks)";
129
+ return { openTasks: openTasks.length, openTaskSummary: summary };
130
+ }
131
+
132
+ /**
133
+ * Probe memory integration: check if <globalDir>/memory/ exists and count entries.
134
+ * Also read MEMORY.md (up to 3000 chars).
135
+ * Return { entries, memorySummary } or null if memory is not active.
136
+ */
137
+ function probeMemoryIntegration(globalDir: string): { entries: number; memorySummary: string } | null {
138
+ const memoryDir = path.join(globalDir, "memory");
139
+
140
+ // If memory dir doesn't exist, memory is not active for this project
141
+ if (!fs.existsSync(memoryDir)) {
142
+ return null;
143
+ }
144
+
145
+ // Count entries in memory/entries/
146
+ let entriesCount = 0;
147
+ const entriesDir = path.join(memoryDir, "entries");
148
+ try {
149
+ if (fs.existsSync(entriesDir)) {
150
+ const files = fs.readdirSync(entriesDir);
151
+ entriesCount = files.filter((f) => f.endsWith(".md")).length;
152
+ }
153
+ } catch {
154
+ // entries dir unreadable, but memory is still active
155
+ }
156
+
157
+ // Read MEMORY.md (truncated at 3000 chars)
158
+ let memorySummary = "";
159
+ const memoryFile = path.join(memoryDir, "MEMORY.md");
160
+ try {
161
+ if (fs.existsSync(memoryFile)) {
162
+ const content = fs.readFileSync(memoryFile, "utf-8");
163
+ memorySummary = content.length > 3000 ? content.slice(0, 3000) : content;
164
+ }
165
+ } catch {
166
+ // MEMORY.md unreadable
167
+ }
168
+
169
+ return { entries: entriesCount, memorySummary };
170
+ }
171
+
172
+ /**
173
+ * Probe compatibility: detect minion and memory integration for the project at cwd.
174
+ * Return detailed status for both extensions in a flat structure.
175
+ */
176
+ export function probeCompat(cwd: string): CompatResult {
177
+ const root = findProjectRoot(cwd);
178
+ const configDir = path.join(root, CONFIG_DIR_NAME);
179
+ const projectId = readMarkerId(configDir);
180
+
181
+ // Initialize with defaults
182
+ const base: CompatResult = {
183
+ projectId,
184
+ minionActive: false,
185
+ memoryActive: false,
186
+ memoryEntries: 0,
187
+ openTaskCount: 0,
188
+ openTaskSummary: "",
189
+ memorySummary: "",
190
+ };
191
+
192
+ // If no project marker, return defaults
193
+ if (!projectId) {
194
+ return base;
195
+ }
196
+
197
+ const piHome = path.dirname(getAgentDir());
198
+ const globalDir = path.join(piHome, "projects", projectId);
199
+
200
+ // Probe minion
201
+ const minionProbe = probeMinionTasks(globalDir);
202
+ if (minionProbe) {
203
+ base.minionActive = true;
204
+ base.openTaskCount = minionProbe.openTasks;
205
+ base.openTaskSummary = minionProbe.openTaskSummary;
206
+ }
207
+
208
+ // Probe memory
209
+ const memoryProbe = probeMemoryIntegration(globalDir);
210
+ if (memoryProbe) {
211
+ base.memoryActive = true;
212
+ base.memoryEntries = memoryProbe.entries;
213
+ base.memorySummary = memoryProbe.memorySummary;
214
+ }
215
+
216
+ return base;
217
+ }
package/detect.ts ADDED
@@ -0,0 +1,188 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { execSync } from "node:child_process";
4
+
5
+ export interface TechStack {
6
+ primary: string[];
7
+ frameworks: string[];
8
+ infrastructure: string[];
9
+ packageManagers: string[];
10
+ }
11
+
12
+ export interface TechIssue {
13
+ severity: "error" | "warning" | "info";
14
+ location: string;
15
+ message: string;
16
+ }
17
+
18
+ export interface ProjectStatus {
19
+ recentCommits: string;
20
+ hasChangelog: boolean;
21
+ todoCount: number;
22
+ }
23
+
24
+ const LANG_FILES: Array<{ file: string; lang: string }> = [
25
+ { file: "package.json", lang: "Node.js" },
26
+ { file: "tsconfig.json", lang: "TypeScript" },
27
+ { file: "requirements.txt", lang: "Python" },
28
+ { file: "pyproject.toml", lang: "Python" },
29
+ { file: "go.mod", lang: "Go" },
30
+ { file: "Cargo.toml", lang: "Rust" },
31
+ { file: "pom.xml", lang: "Java" },
32
+ { file: "build.gradle", lang: "Java/Kotlin" },
33
+ { file: "build.gradle.kts", lang: "Kotlin" },
34
+ { file: "Gemfile", lang: "Ruby" },
35
+ { file: "composer.json", lang: "PHP" },
36
+ { file: "mix.exs", lang: "Elixir" },
37
+ ];
38
+
39
+ const FRAMEWORK_FILES: Array<{ file: string; name: string; infra?: boolean }> = [
40
+ { file: "next.config.js", name: "Next.js" },
41
+ { file: "next.config.ts", name: "Next.js" },
42
+ { file: "next.config.mjs", name: "Next.js" },
43
+ { file: "vite.config.ts", name: "Vite" },
44
+ { file: "vite.config.js", name: "Vite" },
45
+ { file: "nuxt.config.ts", name: "Nuxt.js" },
46
+ { file: "svelte.config.js", name: "SvelteKit" },
47
+ { file: "astro.config.mjs", name: "Astro" },
48
+ { file: "remix.config.js", name: "Remix" },
49
+ { file: "angular.json", name: "Angular" },
50
+ { file: "tailwind.config.ts", name: "Tailwind CSS" },
51
+ { file: "tailwind.config.js", name: "Tailwind CSS" },
52
+ { file: "biome.json", name: "Biome" },
53
+ { file: "Dockerfile", name: "Docker", infra: true },
54
+ { file: "docker-compose.yml", name: "Docker Compose", infra: true },
55
+ { file: ".github/workflows", name: "GitHub Actions", infra: true },
56
+ { file: ".gitlab-ci.yml", name: "GitLab CI", infra: true },
57
+ ];
58
+
59
+ const NPM_FRAMEWORKS: Record<string, string> = {
60
+ react: "React",
61
+ vue: "Vue",
62
+ express: "Express",
63
+ fastify: "Fastify",
64
+ hono: "Hono",
65
+ "@nestjs/core": "NestJS",
66
+ prisma: "Prisma",
67
+ "@prisma/client": "Prisma",
68
+ "drizzle-orm": "Drizzle ORM",
69
+ "@trpc/server": "tRPC",
70
+ };
71
+
72
+ export function detectTechStack(root: string): TechStack {
73
+ const primary = new Set<string>();
74
+ const frameworks = new Set<string>();
75
+ const infrastructure = new Set<string>();
76
+ const packageManagers = new Set<string>();
77
+
78
+ for (const d of LANG_FILES) {
79
+ if (fs.existsSync(path.join(root, d.file))) primary.add(d.lang);
80
+ }
81
+
82
+ for (const d of FRAMEWORK_FILES) {
83
+ if (fs.existsSync(path.join(root, d.file))) {
84
+ if (d.infra) infrastructure.add(d.name);
85
+ else frameworks.add(d.name);
86
+ }
87
+ }
88
+
89
+ if (fs.existsSync(path.join(root, "package-lock.json"))) packageManagers.add("npm");
90
+ if (fs.existsSync(path.join(root, "yarn.lock"))) packageManagers.add("yarn");
91
+ if (fs.existsSync(path.join(root, "pnpm-lock.yaml"))) packageManagers.add("pnpm");
92
+ if (fs.existsSync(path.join(root, "bun.lock"))) packageManagers.add("bun");
93
+
94
+ try {
95
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
96
+ const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) };
97
+ for (const [dep, label] of Object.entries(NPM_FRAMEWORKS)) {
98
+ if (dep in deps) frameworks.add(label);
99
+ }
100
+ } catch {
101
+ /***/
102
+ }
103
+
104
+ return {
105
+ primary: [...primary],
106
+ frameworks: [...frameworks],
107
+ infrastructure: [...infrastructure],
108
+ packageManagers: [...packageManagers],
109
+ };
110
+ }
111
+
112
+ export function detectProjectStatus(root: string): ProjectStatus {
113
+ let recentCommits = "";
114
+ try {
115
+ recentCommits = execSync("git log --oneline -20", {
116
+ cwd: root,
117
+ encoding: "utf-8",
118
+ timeout: 5000,
119
+ }).trim();
120
+ } catch {
121
+ recentCommits = "(git not available or no commits)";
122
+ }
123
+
124
+ const hasChangelog =
125
+ fs.existsSync(path.join(root, "CHANGELOG.md")) || fs.existsSync(path.join(root, "CHANGELOG"));
126
+
127
+ let todoCount = 0;
128
+ try {
129
+ const result = execSync(
130
+ `grep -r --include="*.ts" --include="*.tsx" --include="*.js" --include="*.py" --include="*.go" --include="*.rs" -c "TODO:\\|FIXME:\\|HACK:\\|BUG:" . 2>/dev/null || true`,
131
+ { cwd: root, encoding: "utf-8", timeout: 10000 }
132
+ );
133
+ for (const line of result.split("\n")) {
134
+ const m = line.match(/:(\d+)$/);
135
+ if (m) todoCount += parseInt(m[1], 10);
136
+ }
137
+ } catch {
138
+ /***/
139
+ }
140
+
141
+ return { recentCommits, hasChangelog, todoCount };
142
+ }
143
+
144
+ export function detectTechnicalIssues(root: string): TechIssue[] {
145
+ const issues: TechIssue[] = [];
146
+
147
+ // Invalid tsconfig.json
148
+ const tsconfigPath = path.join(root, "tsconfig.json");
149
+ if (fs.existsSync(tsconfigPath)) {
150
+ try {
151
+ JSON.parse(fs.readFileSync(tsconfigPath, "utf-8"));
152
+ } catch (e) {
153
+ issues.push({
154
+ severity: "error",
155
+ location: "tsconfig.json",
156
+ message: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`,
157
+ });
158
+ }
159
+ }
160
+
161
+ // No test directory or config
162
+ const testDirs = ["test", "tests", "__tests__", "spec"];
163
+ const testConfigs = ["vitest.config.ts", "vitest.config.js", "jest.config.ts", "jest.config.js"];
164
+ const hasTests =
165
+ testDirs.some((d) => fs.existsSync(path.join(root, d))) ||
166
+ testConfigs.some((f) => fs.existsSync(path.join(root, f)));
167
+ if (!hasTests) {
168
+ issues.push({
169
+ severity: "warning",
170
+ location: "root",
171
+ message: "No test directory or test config detected",
172
+ });
173
+ }
174
+
175
+ // .env.example without .env
176
+ if (
177
+ fs.existsSync(path.join(root, ".env.example")) &&
178
+ !fs.existsSync(path.join(root, ".env"))
179
+ ) {
180
+ issues.push({
181
+ severity: "info",
182
+ location: ".env",
183
+ message: ".env.example exists but .env is missing — check environment setup",
184
+ });
185
+ }
186
+
187
+ return issues;
188
+ }
package/docs/PRD.md ADDED
@@ -0,0 +1,78 @@
1
+ # Product Requirements Document: @aprimediet/codewalker
2
+
3
+ **Version:** 1.0
4
+ **Date:** 2026-06-25
5
+ **Status:** Draft
6
+
7
+ ## Overview
8
+ Project intelligence extension for the pi coding agent that systematically analyzes any project — tech stack, goals, boundaries, status, technical issues — and produces structured documentation: a **PRD** for humans and **AGENTS.md** / **CLAUDE.md** for coding agents.
9
+
10
+ ## Problem Statement
11
+ Developers using the pi coding agent need a fast, reliable way to understand a project they're working on without manually reading every file. The coding agent also needs structured project instructions to work effectively. Currently there's no automated way to generate this intelligence snapshot and split the content by audience (human vs. agent).
12
+
13
+ ## Goals
14
+ - Identify tech stack (language, frameworks, infrastructure, package manager)
15
+ - Identify project goals and non-goals (interactively when missing)
16
+ - Identify boundaries, scope, and constraints of a project
17
+ - Generate a human-readable PRD.md with product context
18
+ - Generate an engineering-focused AGENTS.md for coding agents
19
+ - Detect companion extensions (minion, memory) and report their state
20
+ - Store the intelligence snapshot to persistent memory for session continuity
21
+
22
+ ## Non-Goals
23
+ - Give suggestions or recommendations on how to improve the project
24
+ - Try to solve or fix technical issues found during analysis
25
+ - Research how to solve technical issues — diagnose only, no solutions
26
+ - Modify project files beyond the documentation it generates
27
+
28
+ ## Target Users
29
+ Developers who use the pi coding agent and need to quickly get up to speed on a project or generate structured documentation for human and agent consumption.
30
+
31
+ ## Key Features
32
+
33
+ ### Tech Stack Detection
34
+ Automatically scan manifest files (package.json, tsconfig.json, requirements.txt, go.mod, Cargo.toml, etc.) and framework configs to identify primary language, frameworks, infrastructure, and package manager.
35
+
36
+ ### Goals & Non-Goals Gathering
37
+ Search README and docs for existing goals. If not found, interactively gather them from the user one question at a time — problem solved, primary users, key features, out-of-scope items, success metrics.
38
+
39
+ ### Boundary Documentation
40
+ Identify key entry points, external services, exposed interfaces (APIs, CLI flags), and technical constraints (runtime version, env vars, OS requirements).
41
+
42
+ ### Project Status Scanning
43
+ Read recent git commits, check for changelogs/roadmaps, scan for TODO/FIXME/HACK/BUG markers in source code.
44
+
45
+ ### Technical Issue Detection
46
+ Detect missing tests, broken env files, invalid configs, and TypeScript strictness issues — report without trying to fix.
47
+
48
+ ### Audience-Split Documentation
49
+ Generate three documents from the same intelligence, each targeted at its audience:
50
+ - **docs/PRD.md** (humans, product) — overview, problem, goals, users, features, success metrics
51
+ - **AGENTS.md** (coding agents, engineering) — tech stack, commands, conventions, technical boundaries, gotchas
52
+ - **CLAUDE.md** (Claude Code) — thin pointer that imports AGENTS.md
53
+
54
+ ### Integration Detection
55
+ Detect active `@aprimediet/minion` and `@aprimediet/memory` extensions via shared `.pi/<id>.md` project marker. Report open tasks and memory entries without modifying any files.
56
+
57
+ ### Memory Storage
58
+ Store the full project intelligence snapshot to `@aprimediet/memory` (scope: project) for persistent recall across sessions.
59
+
60
+ ## Success Metrics
61
+ - User can read a summary of their current project in PRD.md without reading every file manually
62
+ - Coding agent can read specific project instructions in AGENTS.md to work effectively
63
+ - Pi coding agent can learn and store the latest project snapshot in memory for session continuity
64
+ - Documentation is correctly split by audience with no overlap
65
+
66
+ ## Scope & Boundaries
67
+ - **Runtime:** Node.js with ESM modules (`"type": "module"`)
68
+ - **Peer dependency:** `@earendil-works/pi-coding-agent`
69
+ - **No third-party runtime dependencies** — Node built-ins only (`fs`, `path`, `child_process`)
70
+ - **Exposed interface:** single `/learn-this` command registered with the pi extension API
71
+ - **File system operations:** all detection probes are read-only; writes are confined to documentation files (PRD.md, AGENTS.md, CLAUDE.md) and memory storage
72
+ - **Not a CI tool:** runs on-demand via `/learn-this`, not as a background service
73
+
74
+ ## Open Questions
75
+ - Should AGENTS.md be auto-generated or user-edited after generation?
76
+ - How often should memory snapshots be refreshed — on every `/learn-this` run or on demand?
77
+ - Should the extension support non-Node.js projects (Python, Go, Rust) for full PRD/AGENTS.md generation?
78
+ - Should there be a flag to skip interactive questions when running in non-interactive mode?
package/index.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import { probeCompat } from "./compat.ts";
3
+
4
+ export default function codewalkExtension(pi: ExtensionAPI): void {
5
+ pi.registerCommand("learn-this", {
6
+ description: "Analyze this project: tech stack, goals, status, issues, then generate PRD + AGENTS.md/CLAUDE.md.",
7
+ handler: async (_args, ctx: ExtensionContext) => {
8
+ const compat = probeCompat(ctx.cwd);
9
+
10
+ const minionLine = compat.minionActive
11
+ ? `minion: active (project ${compat.projectId}, ${compat.openTaskCount} open tasks)`
12
+ : "minion: not detected";
13
+
14
+ const memoryLine = compat.memoryActive
15
+ ? `memory: active (${compat.memoryEntries} entries)`
16
+ : "memory: not detected";
17
+
18
+ // Surface the probe result to the user immediately (TUI only).
19
+ if (ctx.hasUI) {
20
+ ctx.ui.notify(
21
+ ["codewalker: starting /learn-this", ` ${minionLine}`, ` ${memoryLine}`].join("\n"),
22
+ "info",
23
+ );
24
+ }
25
+
26
+ // Actually kick off the workflow: send a user message that triggers an agent turn.
27
+ // The agent invokes the learn-this skill and runs all 9 phases. We hand it the
28
+ // integration facts up front so Phase 7 (and Phase 9 storage) start from real data.
29
+ const directive = [
30
+ "Run the /learn-this project intelligence workflow on the current working directory now.",
31
+ "Invoke the `learn-this` skill and complete every phase and checklist item in order.",
32
+ "Do not stop after detection — gather goals interactively (one question at a time) where they are missing, generate the docs (docs/PRD.md for humans, AGENTS.md + CLAUDE.md for coding agents, with the audience-correct content split), and finish with the summary and memory storage steps.",
33
+ "",
34
+ "Integration status detected by codewalker (use these facts in Phase 7 and Phase 9):",
35
+ `- ${minionLine}`,
36
+ `- ${memoryLine}`,
37
+ compat.projectId ? `- project id: ${compat.projectId}` : "- project id: none (no .pi marker found)",
38
+ ].join("\n");
39
+
40
+ pi.sendUserMessage(directive, { deliverAs: "followUp" });
41
+ },
42
+ });
43
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@aprimediet/codewalker",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "Project intelligence snapshot for the pi coding agent — /learn-this",
6
+ "keywords": [
7
+ "pi-package",
8
+ "pi-extension",
9
+ "codewalker",
10
+ "project-intelligence",
11
+ "prd",
12
+ "agents-md"
13
+ ],
14
+ "license": "MIT",
15
+ "author": {
16
+ "name": "aprimediet",
17
+ "url": "https://github.com/aprimediet"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/aprimediet/codewalker.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/aprimediet/codewalker/issues"
25
+ },
26
+ "homepage": "https://github.com/aprimediet/codewalker#readme",
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "pi": {
34
+ "extensions": ["./index.ts"],
35
+ "skills": ["./skills"]
36
+ },
37
+ "files": [
38
+ "*.ts",
39
+ "skills/**",
40
+ "README.md",
41
+ "LICENSE",
42
+ "docs/**"
43
+ ],
44
+ "peerDependencies": {
45
+ "@earendil-works/pi-coding-agent": "*"
46
+ }
47
+ }
package/prd.ts ADDED
@@ -0,0 +1,106 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+
4
+ const PRD_CANDIDATES = [
5
+ "docs/PRD.md",
6
+ "docs/prd.md",
7
+ "PRD.md",
8
+ ".pi/prd.md",
9
+ "PRODUCT.md",
10
+ "SPEC.md",
11
+ ];
12
+
13
+ export function findExistingPRD(root: string): string | null {
14
+ for (const p of PRD_CANDIDATES) {
15
+ const filePath = path.join(root, p);
16
+ if (fs.existsSync(filePath)) {
17
+ return filePath;
18
+ }
19
+ }
20
+
21
+ // README with a goals/requirements heading
22
+ const readme = path.join(root, "README.md");
23
+ if (fs.existsSync(readme)) {
24
+ try {
25
+ const text = fs.readFileSync(readme, "utf-8");
26
+ if (/^##\s+(Goals|Non-Goals|Requirements|Product Requirements)/im.test(text)) {
27
+ return readme;
28
+ }
29
+ } catch {
30
+ // Ignore read errors
31
+ }
32
+ }
33
+
34
+ return null;
35
+ }
36
+
37
+ export function readPRD(filePath: string): string {
38
+ try {
39
+ return fs.readFileSync(filePath, "utf-8");
40
+ } catch {
41
+ return "";
42
+ }
43
+ }
44
+
45
+ export function createPRD(root: string, content: string): string {
46
+ const outPath = path.join(root, "docs", "PRD.md");
47
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
48
+ fs.writeFileSync(outPath, content, "utf-8");
49
+ return outPath;
50
+ }
51
+
52
+ export function prdTemplate(p: {
53
+ projectName: string;
54
+ overview: string;
55
+ problem: string;
56
+ goals: string[];
57
+ nonGoals: string[];
58
+ targetUsers: string;
59
+ keyFeatures: Array<{ name: string; description: string }>;
60
+ successMetrics: string[];
61
+ boundaries: string;
62
+ openQuestions: string[];
63
+ date: string;
64
+ }): string {
65
+ const goalsSection = p.goals.map((g) => `- ${g}`).join("\n");
66
+ const nonGoalsSection = p.nonGoals.map((g) => `- ${g}`).join("\n");
67
+ const featuresSection = p.keyFeatures
68
+ .map((f) => `### ${f.name}\n${f.description}`)
69
+ .join("\n\n");
70
+ const metricsSection = p.successMetrics.map((m) => `- ${m}`).join("\n");
71
+ const questionsSection = p.openQuestions.map((q) => `- ${q}`).join("\n");
72
+
73
+ return `# Product Requirements Document: ${p.projectName}
74
+
75
+ **Version:** 1.0
76
+ **Date:** ${p.date}
77
+ **Status:** Draft
78
+
79
+ ## Overview
80
+ ${p.overview}
81
+
82
+ ## Problem Statement
83
+ ${p.problem}
84
+
85
+ ## Goals
86
+ ${goalsSection}
87
+
88
+ ## Non-Goals
89
+ ${nonGoalsSection}
90
+
91
+ ## Target Users
92
+ ${p.targetUsers}
93
+
94
+ ## Key Features
95
+ ${featuresSection}
96
+
97
+ ## Success Metrics
98
+ ${metricsSection}
99
+
100
+ ## Boundaries & Constraints
101
+ ${p.boundaries}
102
+
103
+ ## Open Questions
104
+ ${questionsSection}
105
+ `;
106
+ }
@@ -0,0 +1,325 @@
1
+ ---
2
+ name: learn-this
3
+ description: Use when the user runs /learn-this or asks to analyze, understand, or get up to speed on the current project. Guides systematic project intelligence gathering across tech stack, goals, status, technical issues, PRD management, and integration detection.
4
+ ---
5
+
6
+ # Learn This — Project Intelligence
7
+
8
+ Build a complete project intelligence snapshot for the current working directory.
9
+ Create a task for each phase listed below before starting any of them.
10
+
11
+ ---
12
+
13
+ ## Phase 1 — Tech Stack
14
+
15
+ Read the following files if they exist and record what you find:
16
+
17
+ | File | Signals |
18
+ |---|---|
19
+ | `package.json` | Node.js / JS / TS; read `dependencies` + `devDependencies` for frameworks |
20
+ | `tsconfig.json` | TypeScript |
21
+ | `bun.lock` / `pnpm-lock.yaml` / `yarn.lock` / `package-lock.json` | Package manager |
22
+ | `requirements.txt` / `pyproject.toml` | Python |
23
+ | `go.mod` | Go |
24
+ | `Cargo.toml` | Rust |
25
+ | `pom.xml` / `build.gradle` / `build.gradle.kts` | Java / Kotlin |
26
+ | `Gemfile` | Ruby |
27
+ | `next.config.*` / `vite.config.*` / `nuxt.config.*` / `astro.config.*` | Frontend framework |
28
+ | `tailwind.config.*` | Tailwind CSS |
29
+ | `Dockerfile` / `docker-compose.yml` | Docker |
30
+ | `.github/workflows/` | GitHub Actions |
31
+ | `.gitlab-ci.yml` | GitLab CI |
32
+
33
+ Also read `package.json` deps for: `react`, `vue`, `express`, `fastify`, `hono`,
34
+ `@nestjs/core`, `prisma`, `@prisma/client`, `drizzle-orm`, `@trpc/server`.
35
+
36
+ Record: primary language(s), frameworks, infrastructure, package manager.
37
+
38
+ ---
39
+
40
+ ## Phase 2 — Goals & Non-Goals
41
+
42
+ Search in order:
43
+ 1. `README.md` — look for Goals, Non-Goals, About, Overview headings
44
+ 2. `docs/PRD.md`, `docs/prd.md`, `PRD.md`, `.pi/prd.md`, `PRODUCT.md`, `SPEC.md`
45
+ 3. Any markdown file whose name contains "goals" or "requirements"
46
+
47
+ **If goals are NOT found**, gather them interactively — ask ONE question at a time and wait
48
+ for the user's answer before asking the next:
49
+
50
+ 1. "What problem does this project solve?"
51
+ 2. "Who is the primary user or audience?"
52
+ 3. "What are the 3 most important features?"
53
+ 4. "What is explicitly out of scope?"
54
+ 5. "What does success look like for this project?"
55
+
56
+ **Do NOT present all five questions at once. Ask one. Wait for the answer. Ask the next.**
57
+
58
+ ---
59
+
60
+ ## Phase 3 — Boundaries
61
+
62
+ From README and code structure, identify:
63
+ - Key entry points (main files, API routes, CLI commands)
64
+ - External services consumed (databases, third-party APIs, cloud services)
65
+ - Exposed interfaces (HTTP endpoints, CLI flags, exported packages)
66
+ - Technical constraints (runtime version, OS requirements, required env vars)
67
+
68
+ ---
69
+
70
+ ## Phase 4 — Project Status
71
+
72
+ 1. Run: `git log --oneline -20` — record the output
73
+ 2. Check for `CHANGELOG.md`, `TODO.md`, `ISSUES.md`, `ROADMAP.md`
74
+ 3. Scan for technical debt markers:
75
+ ```
76
+ grep -r "TODO:\|FIXME:\|HACK:\|BUG:" --include="*.ts" --include="*.js" --include="*.py" --include="*.go" . 2>/dev/null | head -20
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Phase 5 — Technical Issues
82
+
83
+ Detect and report:
84
+ - No test directory or test config found (`test/`, `tests/`, `__tests__/`, `vitest.config.*`, `jest.config.*`)
85
+ - `.env.example` exists but `.env` is missing
86
+ - `tsconfig.json` is not valid JSON
87
+ - Count of `// @ts-nocheck` or `// @ts-ignore` occurrences
88
+
89
+ Then ask the user:
90
+ > "I found [N] potential issues above. Are there additional technical issues you want me to be aware of or address?"
91
+
92
+ Record their response.
93
+
94
+ ---
95
+
96
+ ## Phase 6 — Documentation Generation
97
+
98
+ Produce two complementary documents from everything gathered so far, and split the content
99
+ by audience. **Never put the same content in both.**
100
+
101
+ | Document | Audience | Holds the *what & why* / *how* |
102
+ |---|---|---|
103
+ | `docs/PRD.md` | Humans (product) | overview, problem, goals, non-goals, target users, key features, success metrics, product-scope boundaries, open questions |
104
+ | `AGENTS.md` (repo root) | Coding agents (engineering) | tech stack, project structure, build/test/run commands, conventions, **technical** boundaries, known issues, companion-extension usage, current focus |
105
+ | `CLAUDE.md` (repo root) | Claude Code | thin pointer that imports `AGENTS.md` |
106
+
107
+ ### 6a — PRD (human, product)
108
+
109
+ **Search for existing PRD** in: `docs/PRD.md`, `docs/prd.md`, `PRD.md`, `.pi/prd.md`,
110
+ `PRODUCT.md`, `SPEC.md`, or `README.md` with a Goals/Requirements heading.
111
+
112
+ **If it exists**: read and summarize key sections for the Phase 8 summary.
113
+
114
+ **If it does NOT exist**:
115
+ - Ask: "No PRD found. Should I create `docs/PRD.md` with the product information we gathered?"
116
+ - If yes, write `docs/PRD.md` using this template (product content only — no commands, no file paths, no conventions):
117
+
118
+ ```
119
+ # Product Requirements Document: <project-name>
120
+
121
+ **Version:** 1.0
122
+ **Date:** <today>
123
+ **Status:** Draft
124
+
125
+ ## Overview
126
+ <1-2 sentence vision summary>
127
+
128
+ ## Problem Statement
129
+ <what problem this solves and who has it>
130
+
131
+ ## Goals
132
+ - <goal from Phase 2>
133
+
134
+ ## Non-Goals
135
+ - <non-goal from Phase 2>
136
+
137
+ ## Target Users
138
+ <from Phase 2>
139
+
140
+ ## Key Features
141
+ ### <Feature>
142
+ <product-level description>
143
+
144
+ ## Success Metrics
145
+ - <metric from Phase 2>
146
+
147
+ ## Scope & Boundaries
148
+ <product-scope boundaries from Phase 3 — what the product will and will not do>
149
+
150
+ ## Open Questions
151
+ - <any unresolved questions>
152
+ ```
153
+
154
+ ### 6b — AGENTS.md (coding agent, engineering)
155
+
156
+ **Search for an existing agent guide** at: `AGENTS.md`, `.agents/AGENTS.md`, `docs/AGENTS.md`.
157
+
158
+ **If it exists**: read it; offer to update stale sections rather than overwrite.
159
+
160
+ **If it does NOT exist**:
161
+ - Ask: "No AGENTS.md found. Should I create one at the repo root for coding agents?"
162
+ - If yes, write `AGENTS.md` using this template (engineering content only — NO product goals/users/metrics; link to the PRD for those):
163
+
164
+ ```
165
+ # AGENTS.md — <project-name>
166
+
167
+ Guide for coding agents working in this repository. Product context (goals, users,
168
+ features, success metrics): see [docs/PRD.md](docs/PRD.md).
169
+
170
+ ## Summary
171
+ <one-line: what this codebase is, technically>
172
+
173
+ ## Tech Stack
174
+ <languages, frameworks, infrastructure, package manager — from Phase 1>
175
+
176
+ ## Project Structure
177
+ <key entry points and directories — from Phase 3>
178
+
179
+ ## Commands
180
+ - **Setup:** <install command, if any>
181
+ - **Build:** <build command, if any>
182
+ - **Test:** <test command, if any>
183
+ - **Run:** <run/dev command, if any>
184
+ - **Lint:** <lint/format command, if any>
185
+
186
+ ## Conventions
187
+ <code style, naming, patterns observed in the codebase — match what exists>
188
+
189
+ ## Boundaries (technical)
190
+ <do-not-touch areas, invariants, generated files, things that must not change — from Phase 3>
191
+
192
+ ## Known Issues & Gotchas
193
+ - <technical issue from Phase 5>
194
+
195
+ ## Companion Extensions
196
+ <if minion/memory are active (Phase 7): how the agent should use them — e.g. check the
197
+ kanban board before starting, record durable facts to memory. If not active, say so.>
198
+
199
+ ## Current Focus
200
+ <what is being worked on now — from Phase 4 recent commits / status>
201
+ ```
202
+
203
+ ### 6c — CLAUDE.md (Claude Code pointer)
204
+
205
+ **If `CLAUDE.md` does not already exist** at the repo root, create it as a thin pointer so
206
+ Claude Code loads the same guide (do not duplicate AGENTS.md content):
207
+
208
+ ```
209
+ # CLAUDE.md — <project-name>
210
+
211
+ Guidance for Claude Code in this repository.
212
+
213
+ All project conventions, architecture, build/test commands, and boundaries live in
214
+ **[AGENTS.md](./AGENTS.md)** — the shared guide for every coding agent. Keep that file
215
+ as the single source of truth; do not duplicate its content here.
216
+
217
+ @AGENTS.md
218
+ ```
219
+
220
+ If `CLAUDE.md` already exists with its own content, do NOT overwrite it — instead offer to
221
+ add the `@AGENTS.md` import line if it is missing.
222
+
223
+ ---
224
+
225
+ ## Phase 7 — Integration Detection
226
+
227
+ **Detect `@aprimediet/minion`:**
228
+
229
+ Step-by-step marker detection:
230
+ 1. List all `*.md` files inside the `.pi/` directory at the project root
231
+ 2. For each file, read its contents
232
+ 3. Check if the file contains both `pi-project: true` and an `id:` field (in YAML frontmatter)
233
+ 4. If found, extract the value after `id:` — this is the project id
234
+
235
+ Then check for minion:
236
+ - Check if `~/.pi/projects/<id>/tasks/` directory exists
237
+ - If yes: read each `*.md` file in the tasks dir; count those whose frontmatter has `status:` set to one of: `backlog`, `todo`, `in_progress`, `blocked`, `review`
238
+ - Report: count of open tasks + their titles + statuses
239
+
240
+ **Detect `@aprimediet/memory`:**
241
+
242
+ - Use the **same `.pi/<id>.md` marker** (one file serves both extensions — do not create a new one)
243
+ - Check if `~/.pi/projects/<id>/memory/` directory exists
244
+ - If yes: check for `~/.pi/projects/<id>/memory/MEMORY.md` — read it if present
245
+ - Count `*.md` files in `~/.pi/projects/<id>/memory/entries/`
246
+ - Report: active/not-detected, entry count, MEMORY.md contents
247
+
248
+ ---
249
+
250
+ ## Phase 8 — Compile Summary
251
+
252
+ Assemble the full project intelligence document using these exact section headers:
253
+
254
+ ```
255
+ # Project Intelligence: <project-name>
256
+ > Generated by /learn-this on <date>
257
+
258
+ ## Tech Stack
259
+ **Language(s):** ...
260
+ **Frameworks:** ...
261
+ **Infrastructure:** ...
262
+ **Package Manager:** ...
263
+
264
+ ## Goals
265
+ ...
266
+
267
+ ## Non-Goals
268
+ ...
269
+
270
+ ## Boundaries
271
+ ...
272
+
273
+ ## Current Status
274
+ **Recent commits:**
275
+ <git log output>
276
+
277
+ **Open TODOs/FIXMEs:** N found
278
+
279
+ ## Technical Issues
280
+ - ...
281
+
282
+ ## Documentation
283
+ **PRD (`docs/PRD.md`):** exists | created | not created
284
+ **AGENTS.md:** exists | created | not created
285
+ **CLAUDE.md:** exists | created | not created
286
+ **Key points:** ...
287
+
288
+ ## Minion Integration
289
+ **Status:** active | not detected
290
+ **Project ID:** ...
291
+ **Open tasks (N):**
292
+ - ...
293
+
294
+ ## Memory Integration
295
+ **Status:** active (N entries) | not detected
296
+ **Index:**
297
+ <MEMORY.md contents, or "(empty)">
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Phase 9 — Store to Memory
303
+
304
+ **If `@aprimediet/memory` is active** (detected in Phase 7):
305
+ - Call `memory_write` with `scope: "project"`, `type: "fact"`, and `text:` set to the full Phase 8 summary
306
+ - Report: "Summary stored to project memory."
307
+
308
+ **If memory is not active**:
309
+ - Display the summary in chat
310
+ - Ask: "Would you like me to save this to `docs/project-intelligence.md`?"
311
+ - If yes, write the file.
312
+
313
+ ---
314
+
315
+ ## Checklist
316
+
317
+ - [ ] Phase 1: Tech stack identified
318
+ - [ ] Phase 2: Goals/non-goals found or gathered interactively (one question at a time)
319
+ - [ ] Phase 3: Boundaries documented
320
+ - [ ] Phase 4: Project status from git log + TODO scan
321
+ - [ ] Phase 5: Technical issues detected + user asked about additional issues
322
+ - [ ] Phase 6: Docs generated — PRD (product), AGENTS.md (engineering), CLAUDE.md (pointer), with user confirmation and audience-correct content split
323
+ - [ ] Phase 7: minion compatibility detected; memory compatibility detected
324
+ - [ ] Phase 8: Full summary compiled
325
+ - [ ] Phase 9: Summary stored to memory or saved to file