codealmanac 0.2.6 → 0.2.7

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.
Files changed (86) hide show
  1. package/LICENSE +21 -133
  2. package/README.md +20 -15
  3. package/dist/{agents-HYRWRHRX.js → agents-V2ZOIACP.js} +6 -5
  4. package/dist/{chunk-PDFS5VFE.js → chunk-447U3GQJ.js} +5 -17
  5. package/dist/chunk-447U3GQJ.js.map +1 -0
  6. package/dist/{chunk-3E7JNMTZ.js → chunk-5BWUMAOX.js} +4 -29
  7. package/dist/chunk-5BWUMAOX.js.map +1 -0
  8. package/dist/{chunk-KQUVMF27.js → chunk-BFIG2CXM.js} +2 -516
  9. package/dist/chunk-BFIG2CXM.js.map +1 -0
  10. package/dist/{chunk-K2JBCB7R.js → chunk-BQY5L3DL.js} +7 -43
  11. package/dist/chunk-BQY5L3DL.js.map +1 -0
  12. package/dist/{chunk-F53U6JQG.js → chunk-CQJVM34R.js} +2 -2
  13. package/dist/chunk-FUBE6KCO.js +124 -0
  14. package/dist/chunk-FUBE6KCO.js.map +1 -0
  15. package/dist/chunk-IZBXXAVL.js +524 -0
  16. package/dist/chunk-IZBXXAVL.js.map +1 -0
  17. package/dist/{chunk-7JUX4ADQ.js → chunk-IZT6RBHS.js} +1 -1
  18. package/dist/{chunk-DW32TL5W.js → chunk-JLQZELHQ.js} +18 -58
  19. package/dist/chunk-JLQZELHQ.js.map +1 -0
  20. package/dist/{chunk-2BNDNGUR.js → chunk-KZXWPG4P.js} +4 -8
  21. package/dist/{chunk-2BNDNGUR.js.map → chunk-KZXWPG4P.js.map} +1 -1
  22. package/dist/{chunk-GPFVEF6V.js → chunk-QIA22IAM.js} +6 -24
  23. package/dist/chunk-QIA22IAM.js.map +1 -0
  24. package/dist/{chunk-J7DNV2DH.js → chunk-RALBM6HZ.js} +43 -355
  25. package/dist/chunk-RALBM6HZ.js.map +1 -0
  26. package/dist/{chunk-HJ3WREGP.js → chunk-U5DLLWIC.js} +3 -3
  27. package/dist/chunk-WL4UE7Q6.js +1386 -0
  28. package/dist/chunk-WL4UE7Q6.js.map +1 -0
  29. package/dist/{chunk-VXDPUOQ5.js → chunk-ZUQN5Y3K.js} +129 -382
  30. package/dist/chunk-ZUQN5Y3K.js.map +1 -0
  31. package/dist/{chunk-ODJAAJGZ.js → chunk-ZZLLOAI6.js} +3 -3
  32. package/dist/{cli-MKXCNEMW.js → cli-XWPNARA6.js} +37 -20
  33. package/dist/cli-XWPNARA6.js.map +1 -0
  34. package/dist/codealmanac.js +1 -1
  35. package/dist/{config-F7FKEQ7F.js → config-KH3JUMG6.js} +4 -4
  36. package/dist/doctor-ENJT665Z.js +18 -0
  37. package/dist/{hook-4SVX446M.js → hook-2NP3UE7U.js} +2 -4
  38. package/dist/paths-O5CZADP2.js +14 -0
  39. package/dist/process-KFSLENL3.js +61 -0
  40. package/dist/{register-commands-2F6SXLDI.js → register-commands-LULZUSPO.js} +999 -1030
  41. package/dist/register-commands-LULZUSPO.js.map +1 -0
  42. package/dist/uninstall-BD4MMQ7M.js +16 -0
  43. package/dist/uninstall-BD4MMQ7M.js.map +1 -0
  44. package/dist/update-XSKPDFMJ.js +11 -0
  45. package/dist/update-XSKPDFMJ.js.map +1 -0
  46. package/dist/{wiki-IGNRNLUZ.js → wiki-O4RWMAE6.js} +8 -6
  47. package/dist/wiki-O4RWMAE6.js.map +1 -0
  48. package/guides/mini.md +8 -6
  49. package/guides/reference.md +89 -32
  50. package/hooks/almanac-capture.sh +7 -8
  51. package/package.json +3 -4
  52. package/prompts/agents/.gitkeep +1 -0
  53. package/prompts/base/notability.md +139 -0
  54. package/prompts/base/purpose.md +85 -0
  55. package/prompts/base/syntax.md +114 -0
  56. package/prompts/operations/absorb.md +43 -0
  57. package/prompts/operations/build.md +49 -0
  58. package/prompts/operations/garden.md +51 -0
  59. package/COMMERCIAL.md +0 -9
  60. package/dist/chunk-3E7JNMTZ.js.map +0 -1
  61. package/dist/chunk-DW32TL5W.js.map +0 -1
  62. package/dist/chunk-GPFVEF6V.js.map +0 -1
  63. package/dist/chunk-J7DNV2DH.js.map +0 -1
  64. package/dist/chunk-K2JBCB7R.js.map +0 -1
  65. package/dist/chunk-KQUVMF27.js.map +0 -1
  66. package/dist/chunk-PDFS5VFE.js.map +0 -1
  67. package/dist/chunk-VXDPUOQ5.js.map +0 -1
  68. package/dist/cli-MKXCNEMW.js.map +0 -1
  69. package/dist/doctor-37UH3HT5.js +0 -17
  70. package/dist/register-commands-2F6SXLDI.js.map +0 -1
  71. package/dist/uninstall-C62ZOK32.js +0 -17
  72. package/dist/update-2UGOFN5C.js +0 -11
  73. package/dist/wiki-IGNRNLUZ.js.map +0 -1
  74. package/prompts/bootstrap.md +0 -176
  75. package/prompts/reviewer.md +0 -129
  76. package/prompts/writer.md +0 -134
  77. /package/dist/{agents-HYRWRHRX.js.map → agents-V2ZOIACP.js.map} +0 -0
  78. /package/dist/{chunk-F53U6JQG.js.map → chunk-CQJVM34R.js.map} +0 -0
  79. /package/dist/{chunk-7JUX4ADQ.js.map → chunk-IZT6RBHS.js.map} +0 -0
  80. /package/dist/{chunk-HJ3WREGP.js.map → chunk-U5DLLWIC.js.map} +0 -0
  81. /package/dist/{chunk-ODJAAJGZ.js.map → chunk-ZZLLOAI6.js.map} +0 -0
  82. /package/dist/{config-F7FKEQ7F.js.map → config-KH3JUMG6.js.map} +0 -0
  83. /package/dist/{doctor-37UH3HT5.js.map → doctor-ENJT665Z.js.map} +0 -0
  84. /package/dist/{hook-4SVX446M.js.map → hook-2NP3UE7U.js.map} +0 -0
  85. /package/dist/{uninstall-C62ZOK32.js.map → paths-O5CZADP2.js.map} +0 -0
  86. /package/dist/{update-2UGOFN5C.js.map → process-KFSLENL3.js.map} +0 -0
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ removeImportLine,
4
+ runUninstall
5
+ } from "./chunk-BQY5L3DL.js";
6
+ import "./chunk-ZUQN5Y3K.js";
7
+ import "./chunk-447U3GQJ.js";
8
+ import "./chunk-RALBM6HZ.js";
9
+ import "./chunk-FUBE6KCO.js";
10
+ import "./chunk-5BWUMAOX.js";
11
+ import "./chunk-IZT6RBHS.js";
12
+ export {
13
+ removeImportLine,
14
+ runUninstall
15
+ };
16
+ //# sourceMappingURL=uninstall-BD4MMQ7M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runUpdate
4
+ } from "./chunk-ZZLLOAI6.js";
5
+ import "./chunk-CQJVM34R.js";
6
+ import "./chunk-5BWUMAOX.js";
7
+ import "./chunk-IZT6RBHS.js";
8
+ export {
9
+ runUpdate
10
+ };
11
+ //# sourceMappingURL=update-XSKPDFMJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,17 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- ensureFreshIndex,
4
3
  findEntry,
5
- openIndex,
6
4
  runHealth
7
- } from "./chunk-KQUVMF27.js";
5
+ } from "./chunk-IZBXXAVL.js";
6
+ import {
7
+ ensureFreshIndex,
8
+ openIndex
9
+ } from "./chunk-BFIG2CXM.js";
8
10
  import {
9
11
  formatDuration
10
12
  } from "./chunk-4CODZRHH.js";
11
13
  import "./chunk-FM3VRDK7.js";
12
14
  import {
13
15
  findNearestAlmanacDir
14
- } from "./chunk-7JUX4ADQ.js";
16
+ } from "./chunk-IZT6RBHS.js";
15
17
 
16
18
  // src/commands/doctor-checks/wiki.ts
17
19
  import { existsSync, readdirSync, statSync } from "fs";
@@ -24,7 +26,7 @@ async function gatherWikiChecks(options) {
24
26
  status: "info",
25
27
  key: "wiki.none",
26
28
  message: "No wiki in current directory",
27
- fix: "run: almanac bootstrap (to create one in this repo)"
29
+ fix: "run: almanac init (to create one in this repo)"
28
30
  });
29
31
  return checks;
30
32
  }
@@ -234,4 +236,4 @@ function countHealthProblems(jsonStdout) {
234
236
  export {
235
237
  gatherWikiChecks
236
238
  };
237
- //# sourceMappingURL=wiki-IGNRNLUZ.js.map
239
+ //# sourceMappingURL=wiki-O4RWMAE6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/doctor-checks/wiki.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport type Database from \"better-sqlite3\";\n\nimport { ensureFreshIndex } from \"../../indexer/index.js\";\nimport { openIndex } from \"../../indexer/schema.js\";\nimport { findNearestAlmanacDir } from \"../../paths.js\";\nimport { findEntry } from \"../../registry/index.js\";\nimport { runHealth, type HealthReport } from \"../health.js\";\nimport { formatDuration } from \"./duration.js\";\nimport type { Check, DoctorOptions } from \"./types.js\";\n\nexport async function gatherWikiChecks(options: DoctorOptions): Promise<Check[]> {\n const checks: Check[] = [];\n const repoRoot = findNearestAlmanacDir(options.cwd);\n\n if (repoRoot === null) {\n checks.push({\n status: \"info\",\n key: \"wiki.none\",\n message: \"No wiki in current directory\",\n fix: \"run: almanac init (to create one in this repo)\",\n });\n return checks;\n }\n\n checks.push({\n status: \"info\",\n key: \"wiki.repo\",\n message: `repo: ${repoRoot}`,\n });\n\n try {\n await ensureFreshIndex({ repoRoot });\n } catch {\n // non-fatal: counts below and the health probe report any real issue.\n }\n\n checks.push(await describeRegistry(repoRoot));\n\n const almanacDir = path.join(repoRoot, \".almanac\");\n const dbPath = path.join(almanacDir, \"index.db\");\n checks.push(...describeCounts(dbPath));\n checks.push(describeIndexFreshness(dbPath));\n checks.push(describeLastCapture(almanacDir, options.now));\n checks.push(await describeHealth(repoRoot, options));\n\n return checks;\n}\n\nasync function describeRegistry(repoRoot: string): Promise<Check> {\n try {\n const entry = await findEntry({ path: repoRoot });\n if (entry !== null) {\n return {\n status: \"ok\",\n key: \"wiki.registered\",\n message: `registered as '${entry.name}'`,\n };\n }\n return {\n status: \"info\",\n key: \"wiki.registered\",\n message: \"not yet registered (will register on first command)\",\n };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n status: \"problem\",\n key: \"wiki.registered\",\n message: `could not read registry: ${msg}`,\n fix: \"inspect ~/.almanac/registry.json; remove or fix the malformed entry\",\n };\n }\n}\n\nfunction describeCounts(dbPath: string): Check[] {\n const checks: Check[] = [];\n let pageCount: number | null = null;\n let topicCount: number | null = null;\n\n if (existsSync(dbPath)) {\n try {\n const db = openIndex(dbPath);\n try {\n pageCount = countRows(db, \"pages\");\n topicCount = countRows(db, \"topics\");\n } finally {\n db.close();\n }\n } catch {\n pageCount = null;\n }\n }\n\n if (pageCount !== null) {\n checks.push({\n status: \"info\",\n key: \"wiki.pages\",\n message: `pages: ${pageCount}`,\n });\n }\n if (topicCount !== null) {\n checks.push({\n status: \"info\",\n key: \"wiki.topics\",\n message: `topics: ${topicCount}`,\n });\n }\n\n return checks;\n}\n\nfunction countRows(db: Database.Database, table: string): number {\n const row = db\n .prepare<[], { n: number }>(`SELECT COUNT(*) AS n FROM ${table}`)\n .get();\n return row?.n ?? 0;\n}\n\nfunction describeIndexFreshness(dbPath: string): Check {\n if (!existsSync(dbPath)) {\n return {\n status: \"info\",\n key: \"wiki.index\",\n message: \"index: not built yet (run any query command)\",\n };\n }\n try {\n const dbMtime = statSync(dbPath).mtimeMs;\n const age = Date.now() - dbMtime;\n return {\n status: \"info\",\n key: \"wiki.index\",\n message: `index: rebuilt ${formatDuration(age)} ago`,\n };\n } catch {\n return {\n status: \"info\",\n key: \"wiki.index\",\n message: \"index: present\",\n };\n }\n}\n\nfunction describeLastCapture(\n almanacDir: string,\n nowFn?: () => Date,\n): Check {\n if (!existsSync(almanacDir)) {\n return {\n status: \"info\",\n key: \"wiki.capture\",\n message: \"last capture: never\",\n };\n }\n const logDirs = [path.join(almanacDir, \"logs\"), almanacDir];\n const captures = logDirs\n .flatMap((dir) => {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return [];\n }\n return entries\n .filter(\n (e) =>\n e.startsWith(\".capture-\") &&\n (e.endsWith(\".log\") || e.endsWith(\".jsonl\")),\n )\n .map((e) => ({ dir, name: e }));\n })\n .map((e) => {\n try {\n return {\n name: e.name,\n mtime: statSync(path.join(e.dir, e.name)).mtimeMs,\n };\n } catch {\n return null;\n }\n })\n .filter((e): e is { name: string; mtime: number } => e !== null);\n if (captures.length === 0) {\n return {\n status: \"info\",\n key: \"wiki.capture\",\n message: \"last capture: never\",\n };\n }\n captures.sort((a, b) => b.mtime - a.mtime);\n const latest = captures[0]!;\n const now = (nowFn?.() ?? new Date()).getTime();\n const age = now - latest.mtime;\n return {\n status: \"info\",\n key: \"wiki.capture\",\n message: `last capture: ${formatDuration(age)} ago (${latest.name})`,\n };\n}\n\nasync function describeHealth(\n repoRoot: string,\n options: DoctorOptions,\n): Promise<Check> {\n const healthFn = options.runHealthFn ?? runHealth;\n try {\n const healthRes = await healthFn({\n cwd: repoRoot,\n json: true,\n });\n const problems = countHealthProblems(healthRes.stdout);\n if (problems === 0) {\n return {\n status: \"ok\",\n key: \"wiki.health\",\n message: \"almanac health reports 0 problems\",\n };\n }\n return {\n status: \"problem\",\n key: \"wiki.health\",\n message: `almanac health reports ${problems} problem${problems === 1 ? \"\" : \"s\"}`,\n fix: \"run: almanac health\",\n };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n status: \"info\",\n key: \"wiki.health\",\n message: `could not run almanac health: ${msg}`,\n };\n }\n}\n\nconst HEALTH_PROBLEM_KEYS: (keyof HealthReport)[] = [\n \"orphans\",\n \"stale\",\n \"dead_refs\",\n \"broken_links\",\n \"broken_xwiki\",\n \"empty_topics\",\n \"empty_pages\",\n \"slug_collisions\",\n];\n\nfunction countHealthProblems(jsonStdout: string): number {\n try {\n const report = JSON.parse(jsonStdout) as Partial<HealthReport>;\n let total = 0;\n for (const key of HEALTH_PROBLEM_KEYS) {\n const arr = report[key];\n if (Array.isArray(arr)) total += arr.length;\n }\n return total;\n } catch {\n return 0;\n }\n}\n"],"mappings":"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","names":[]}
package/guides/mini.md CHANGED
@@ -4,7 +4,7 @@ This repo has a `.almanac/` directory. It's a **living wiki** written for AI age
4
4
 
5
5
  You are the primary reader. When the user asks you to do something, **check the wiki before you touch related code** — it will often answer the question the user didn't think to ask ("we tried that in March, here's why it broke").
6
6
 
7
- You don't write the wiki during normal work. A separate agent ("capture") runs automatically at session end via a Claude Code hook, reads the session transcript, and writes or updates pages. Your job during the session is: **read, use, occasionally fix obvious errors.**
7
+ You usually don't write the wiki during normal work. `almanac capture` runs automatically at session end through the installed hook, reads the session transcript, and starts an Absorb job that writes or updates pages. Your job during the session is: **read, use, occasionally fix obvious errors.**
8
8
 
9
9
  ---
10
10
 
@@ -165,9 +165,10 @@ You don't write anything. At session end the capture agent reads the transcript,
165
165
 
166
166
  ## What runs automatically (don't invoke these)
167
167
 
168
- - **`almanac capture`** — runs in the background after every Claude Code session via the `SessionEnd` hook.
168
+ - **`almanac capture`** — starts a background Absorb job after supported agent sessions through the installed hook.
169
169
  - **`almanac reindex`** — runs implicitly before every query when pages changed.
170
- - **`almanac bootstrap`** — one-shot scaffolding. You almost certainly don't run this.
170
+
171
+ Run `almanac init` yourself when you are creating the first wiki for a repo.
171
172
 
172
173
  ---
173
174
 
@@ -186,7 +187,7 @@ If the user has multiple repos with `.almanac/`, they're globally registered. Pa
186
187
  - **Reference code with `[[...]]`.** Inline mentions are fine but only `[[...]]` gets indexed.
187
188
  - **List files in frontmatter.** Pages about specific code need `files: [...]` to surface in `--mentions` queries.
188
189
 
189
- The reviewer subagent (run by capture at session end) enforces these. Stricter with yourself = less rework.
190
+ The Absorb/Garden prompts enforce these during wiki-writing runs. Stricter with yourself = less rework.
190
191
 
191
192
  ---
192
193
 
@@ -210,9 +211,10 @@ Empty stdout plus `# 0 results` on stderr means the query ran and genuinely matc
210
211
  ```bash
211
212
  almanac doctor # install.hook: ok/problem, wiki.capture: last capture age
212
213
  almanac hook status # just the hook entry
213
- ls -lah .almanac/logs/.capture-*.log
214
+ almanac jobs
215
+ ls -lah .almanac/runs/
214
216
  ```
215
- No logs at all → the hook isn't installed, or bailed before backgrounding, or `cwd` was outside any wiki (silent correct no-op). Capture ran but wrote nothing → the reviewer rejected the draft for notability, or the session was pure-read. Check `.almanac/logs/.capture-<id>.log` for the writer/reviewer transcript.
217
+ No jobs at all → the hook isn't installed, bailed before starting capture, or `cwd` was outside any wiki (silent correct no-op). Capture ran but wrote nothing → the Absorb run decided there was no durable wiki change, or the session was pure-read. Use `almanac jobs show <run-id>` and `almanac jobs logs <run-id>` for details.
216
218
 
217
219
  ---
218
220
 
@@ -6,12 +6,12 @@ Groupings match `almanac --help`:
6
6
 
7
7
  1. **Query** — `search`, `show`, `health`, `list`
8
8
  2. **Edit** — `tag`, `untag`, `topics ...`
9
- 3. **Wiki lifecycle** — `bootstrap`, `capture`, `hook ...`, `reindex`
9
+ 3. **Wiki lifecycle** — `init`, `capture`, `ingest`, `garden`, `jobs`, `hook ...`, `reindex`
10
10
  4. **Setup** — `setup`, `uninstall`, `doctor`, `update`
11
11
 
12
12
  Every query/edit command auto-registers the current repo in `~/.almanac/registry.json` on first run. Exceptions: `list --drop` (skips auto-register so the removal intent isn't undone) and the setup group (installers, not wiki commands — they never touch the registry).
13
13
 
14
- There is no `almanac init` command. The two ways a wiki gets scaffolded are `almanac bootstrap` (agent reads the repo and seeds stub pages) and committing a `.almanac/` that someone else authored and cloning into it (auto-registered on first query command).
14
+ A wiki gets scaffolded two ways: run `almanac init` yourself, or clone a repo that already has `.almanac/` committed (auto-registered on first query/edit command).
15
15
 
16
16
  ---
17
17
 
@@ -116,26 +116,81 @@ All topic subcommands accept `--wiki <name>`. `list` / `show` accept `--json`.
116
116
 
117
117
  ### 1.3 Wiki lifecycle
118
118
 
119
- #### `almanac bootstrap`
119
+ #### `almanac init`
120
120
 
121
- Spawns an agent to create initial wiki stubs. Requires the selected provider to be installed and logged in. `--quiet` suppresses per-tool streaming. `--agent <provider>` overrides the provider for this run. `--model <model>` overrides the provider-local model. `--json` emits a structured `CommandOutcome` and suppresses streaming. `--force` overwrites an existing populated wiki. Writes `.almanac/logs/.bootstrap-<timestamp>.log`.
121
+ Build the first wiki for this repo. Requires the selected provider to be installed and ready.
122
122
 
123
- Bootstrap is the scaffolding path — it creates `.almanac/pages/`, `.almanac/topics.yaml`, `.almanac/README.md`, and stub entity pages based on what the agent reads in the repo.
123
+ | Flag | Semantics |
124
+ |---|---|
125
+ | `--using <provider[/model]>` | Override the configured provider/model for this run. |
126
+ | `--background` | Start as a detached CodeAlmanac job. |
127
+ | `--json` | Emit structured JSON for background job start. Cannot be combined with foreground mode. |
128
+ | `--force` | Allow rebuilding an existing populated wiki. |
129
+ | `-y, --yes` | Confirm non-interactively. |
130
+
131
+ `init` runs foreground by default because first setup is an onboarding action. The Build operation receives the shared prompt base (`purpose`, `notability`, `syntax`) plus the Build algorithm prompt and runtime context.
124
132
 
125
- #### `almanac capture [transcript]`
133
+ #### `almanac capture [sessionFiles...]`
126
134
 
127
- Run the writer/reviewer pipeline on a Claude Code session transcript. Usually automatic the `SessionEnd` hook invokes this. Refuses if no `.almanac/` exists in cwd or any parent (capture maintains wikis, doesn't create them; run `almanac bootstrap` first).
135
+ Absorb coding-session knowledge into the wiki. Usually automatic: the installed hook invokes this at session end. Refuses if no `.almanac/` exists in cwd or any parent.
128
136
 
129
137
  | Flag | Semantics |
130
138
  |---|---|
131
- | `[transcript]` | Explicit path. Falls back to `--session` match or most-recent-by-cwd. |
132
- | `--session <id>` | Target a specific session by ID. Matches filename under `~/.claude/projects/`. |
133
- | `--quiet` | Suppress per-tool streaming; print only the final summary. |
134
- | `--agent <provider>` | Override the configured provider for this run. |
135
- | `--model <model>` | Override the agent model. |
136
- | `--json` | Emit a structured `CommandOutcome`; suppresses streaming so stdout is parseable. |
139
+ | `[sessionFiles...]` | Explicit session transcript files. |
140
+ | `--app <app>` | Source app: `claude`, `codex`, `cursor`, or `generic`. |
141
+ | `--session <id>` | Target a specific session by ID. |
142
+ | `--since <duration-or-date>` | Capture sessions since a time. |
143
+ | `--limit <n>` | Maximum sessions to capture. |
144
+ | `--all` | Capture all matching sessions. |
145
+ | `--all-apps` | Capture from all supported apps. |
146
+ | `--using <provider[/model]>` | Override the configured provider/model for this run. |
147
+ | `--foreground` | Run attached instead of starting a background job. |
148
+ | `--json` | Emit structured JSON for background job start. Cannot be combined with `--foreground`. |
149
+ | `-y, --yes` | Confirm non-interactively. |
150
+
151
+ `capture` maps to the internal Absorb operation with `targetKind: "session"`. It starts background by default. Run records and JSONL event logs live under `.almanac/runs/`.
152
+
153
+ #### `almanac ingest <paths...>`
154
+
155
+ Absorb knowledge from one or more files or folders.
156
+
157
+ | Flag | Semantics |
158
+ |---|---|
159
+ | `<paths...>` | One or more files/folders to use as starting context. |
160
+ | `--using <provider[/model]>` | Override the configured provider/model for this run. |
161
+ | `--foreground` | Run attached instead of starting a background job. |
162
+ | `--json` | Emit structured JSON for background job start. Cannot be combined with `--foreground`. |
163
+ | `-y, --yes` | Confirm non-interactively. |
164
+
165
+ `ingest` maps to the internal Absorb operation with `targetKind: "path"`. The input is raw material, not the output; Absorb updates the wiki only when it finds durable project understanding.
166
+
167
+ #### `almanac garden`
168
+
169
+ Improve the wiki as a graph: page boundaries, links, topics, hubs, stale claims, archive/supersession chains, and synthesis quality.
170
+
171
+ | Flag | Semantics |
172
+ |---|---|
173
+ | `--using <provider[/model]>` | Override the configured provider/model for this run. |
174
+ | `--foreground` | Run attached instead of starting a background job. |
175
+ | `--json` | Emit structured JSON for background job start. Cannot be combined with `--foreground`. |
176
+ | `-y, --yes` | Confirm non-interactively. |
177
+
178
+ `garden` starts background by default.
179
+
180
+ #### `almanac jobs`
181
+
182
+ Inspect and manage CodeAlmanac runs stored under `.almanac/runs/`.
183
+
184
+ ```bash
185
+ almanac jobs
186
+ almanac jobs list
187
+ almanac jobs show <run-id>
188
+ almanac jobs logs <run-id>
189
+ almanac jobs attach <run-id>
190
+ almanac jobs cancel <run-id>
191
+ ```
137
192
 
138
- Writes SDK transcript to `.almanac/logs/.capture-<session-id>.jsonl` (one JSON message per line). When invoked manually without `--session`, falls back to `.capture-<timestamp>.jsonl` so repeated runs don't clobber each other. A writer subagent drafts pages; a reviewer subagent enforces notability + writing conventions (§9) before drafts land.
193
+ Each jobs subcommand accepts `--json`. `attach` streams the JSONL event log until the run reaches `done`, `failed`, `cancelled`, or `stale`.
139
194
 
140
195
  #### `almanac hook install | uninstall | status`
141
196
 
@@ -242,11 +297,10 @@ almanac agents model claude --default
242
297
 
243
298
  `agents use` writes the default provider. `agents model` writes the provider-local model override; `--default`, `default`, or `null` resets the provider to its own default. The older `almanac set default-agent ...` and `almanac set model ...` commands remain compatibility aliases and print deprecation warnings.
244
299
 
245
- `bootstrap` and `capture` resolve provider settings in this order:
300
+ `init`, `capture`, `ingest`, and `garden` resolve provider settings in this order:
246
301
 
247
302
  ```text
248
- --agent flag > ALMANAC_AGENT env > config.agent.default > built-in default
249
- --model flag > ALMANAC_MODEL env > config.agent.models[provider] > provider default
303
+ --using flag > project config > user config > provider default
250
304
  ```
251
305
 
252
306
  #### `almanac config`
@@ -514,8 +568,8 @@ Claude Code invokes `SessionEnd` hooks after each session. Payload on stdin:
514
568
 
515
569
  1. Parse payload with `jq`. Missing `jq` → exit 0 silently.
516
570
  2. Walk upward from `cwd` for a `.almanac/`. Bounded at filesystem root.
517
- 3. Background `almanac capture "$TRANSCRIPT" --session "$SESSION_ID" --quiet`, redirect to `.almanac/logs/.capture-$SESSION_ID.log`, `disown`.
518
- 4. Exit always `0`. Capture failures must never break Claude Code's session-end path.
571
+ 3. Background `almanac capture "$TRANSCRIPT" --session "$SESSION_ID"`, redirect the hook sidecar to `.almanac/runs/.capture-$SESSION_ID.hook.log`, `disown`.
572
+ 4. Exit always `0`. Capture failures must never break the host agent's session-end path.
519
573
 
520
574
  Falls back to `npx --no-install codealmanac` if `almanac` isn't on `PATH`.
521
575
 
@@ -541,21 +595,23 @@ Falls back to `npx --no-install codealmanac` if `almanac` isn't on `PATH`.
541
595
  ```bash
542
596
  almanac doctor # catch-all — reports hook state + last capture age
543
597
  almanac hook status # just the hook entry
544
- ls -lah .almanac/logs/.capture-*.log
598
+ almanac jobs
599
+ ls -lah .almanac/runs/
545
600
  ```
546
601
 
547
- Installed but no log: `SessionEnd` didn't fire (rare, hard crash), or script bailed before backgrounding (add `set -x` to trace), or no `.almanac/` upward from `cwd` (silent correct no-op).
602
+ Installed but no job: the session-end event didn't fire, the script bailed before starting capture (add `set -x` to trace), or no `.almanac/` existed upward from `cwd` (silent correct no-op).
548
603
 
549
604
  ### Diagnosing "capture ran but wrote nothing"
550
605
 
551
606
  ```bash
552
- tail -200 .almanac/logs/.capture-<id>.log
607
+ almanac jobs show <run-id>
608
+ almanac jobs logs <run-id>
553
609
  ```
554
610
 
555
611
  Common causes:
556
- - `ANTHROPIC_API_KEY` not in the hook's environment. Claude Code's hook env is minimal; `~/.zshrc` is NOT sourced. Export via `~/.claude/settings.json`'s `env` key, or rely on `claude auth` OAuth credentials.
612
+ - Provider auth is missing in the hook environment. Claude Code's hook env is minimal; `~/.zshrc` is NOT sourced. Export needed env vars via host-agent settings, or rely on provider OAuth credentials where available.
557
613
  - Transcript path didn't resolve. Capture prints resolution status early.
558
- - Reviewer rejected the draft for notability — rationale is in the log.
614
+ - Absorb found no durable wiki change.
559
615
  - Session was pure-read with no decisions or discoveries. Correct no-op.
560
616
 
561
617
  ---
@@ -576,12 +632,12 @@ Common causes:
576
632
  ### Registration paths
577
633
 
578
634
  - **Silent auto-register** — every query/edit command (except `list --drop`) calls `autoRegisterIfNeeded` on cwd. A repo with `.almanac/` but no registry entry → added with `name = basename(cwd)`, no description. Makes "cloned a repo with `.almanac/` committed" just work.
579
- - **`almanac bootstrap`** — auto-registers as a side effect of scaffolding. `name` defaults to the repo basename; edit `~/.almanac/registry.json` or re-bootstrap to rename.
635
+ - **`almanac init`** — creates and registers the wiki. `name` defaults to the repo basename; edit `~/.almanac/registry.json` if you need to rename it.
580
636
  - **`almanac list --drop <name>`** — the only removal path. Skips auto-register so the removal isn't immediately undone.
581
637
 
582
638
  ### `--wiki <name>`
583
639
 
584
- Route the command at a specific registered wiki. Used when you're in one repo but querying another. Without `--wiki`, commands resolve to the wiki whose `path` is an ancestor of cwd. If none, commands error: `almanac: no .almanac/ found in this directory or any parent; run 'almanac bootstrap' first`.
640
+ Route the command at a specific registered wiki. Used when you're in one repo but querying another. Without `--wiki`, commands resolve to the wiki whose `path` is an ancestor of cwd. If none, commands error with a fix such as `run: almanac init`.
585
641
 
586
642
  ### Cross-wiki link resolution
587
643
 
@@ -597,7 +653,7 @@ Route the command at a specific registered wiki. Used when you're in one repo bu
597
653
 
598
654
  ## 9. Notability and writing conventions
599
655
 
600
- The reviewer subagent enforces these during capture. Applying them yourself reduces rework.
656
+ The Build, Absorb, and Garden prompts enforce these during wiki-writing runs. Applying them yourself reduces rework.
601
657
 
602
658
  ### Patterns to avoid (bad → good)
603
659
 
@@ -737,10 +793,11 @@ Missing `files:` frontmatter, OR path referenced only in inline prose (not via `
737
793
  almanac doctor # reports hook state + last capture age + auth
738
794
  claude auth status # OAuth token present?
739
795
  echo "${ANTHROPIC_API_KEY:0:10}" # API key fallback?
740
- ls -lah .almanac/logs/.capture-*.log
796
+ almanac jobs
797
+ ls -lah .almanac/runs/
741
798
  ```
742
799
 
743
- No logs at all → script bailed pre-background. Add `set -x` to `hooks/almanac-capture.sh` to trace. If the hook itself isn't installed, `almanac doctor` reports `install.hook: problem` with `run: almanac setup --yes`.
800
+ No jobs at all → script bailed before starting capture. Add `set -x` to `hooks/almanac-capture.sh` to trace. If the hook itself isn't installed, `almanac doctor` reports `install.hook: problem` with `run: almanac setup --yes`.
744
801
 
745
802
  ### "slug collision warnings"
746
803
 
@@ -752,9 +809,9 @@ Case sensitivity on Linux. Schema v2 stores `original_path` for case-preserving
752
809
 
753
810
  ### Forensics files
754
811
 
755
- - `.almanac/logs/.capture-<session-id>.jsonl` — SDK message stream from `almanac capture` (one JSON object per line). Writer + reviewer interleaved.
756
- - `.almanac/logs/.capture-<session-id>.log` — companion sidecar written by the SessionEnd hook: stdout+stderr of `almanac capture`, human-readable. Present only for hook-invoked captures; manual invocations emit only the `.jsonl`.
757
- - `.almanac/logs/.bootstrap-<timestamp>.log` — one per bootstrap. Gitignored by default.
812
+ - `.almanac/runs/<run-id>.json` — CodeAlmanac run record with status, provider, model, timings, log path, and failure metadata.
813
+ - `.almanac/runs/<run-id>.jsonl` — provider event log for the run. Read with `almanac jobs logs <run-id>`.
814
+ - `.almanac/runs/.capture-<session-id>.hook.log` — hook sidecar containing stdout/stderr from the capture start command. Present only for hook-invoked captures.
758
815
 
759
816
  ---
760
817
 
@@ -15,7 +15,7 @@
15
15
 
16
16
  set -u
17
17
 
18
- # CodeAlmanac's own bootstrap/capture agents run Claude Code internally.
18
+ # CodeAlmanac's own build/capture agents may run provider CLIs internally.
19
19
  # Their SessionEnd events must not trigger another capture, or one capture
20
20
  # can become an unbounded capture chain.
21
21
  if [ "${CODEALMANAC_INTERNAL_SESSION:-}" = "1" ]; then
@@ -50,7 +50,7 @@ fi
50
50
  DIR="$CWD"
51
51
  while [ "$DIR" != "/" ] && [ -n "$DIR" ]; do
52
52
  if [ -d "$DIR/.almanac" ]; then
53
- LOG_DIR="$DIR/.almanac/logs"
53
+ LOG_DIR="$DIR/.almanac/runs"
54
54
  mkdir -p "$LOG_DIR" || exit 0
55
55
  # Prefer `almanac` on PATH; fall back to `npx codealmanac` if the
56
56
  # binary isn't linked (happens with non-global installs).
@@ -65,8 +65,8 @@ while [ "$DIR" != "/" ] && [ -n "$DIR" ]; do
65
65
 
66
66
  run_capture() {
67
67
  cd "$DIR" && \
68
- $CMD capture "$TRANSCRIPT" --session "$SESSION_ID" --quiet \
69
- > "$LOG_DIR/.capture-$SESSION_ID.log" 2>&1
68
+ $CMD capture "$TRANSCRIPT" --session "$SESSION_ID" \
69
+ > "$LOG_DIR/.capture-$SESSION_ID.hook.log" 2>&1
70
70
  }
71
71
 
72
72
  # Codex Stop is turn-scoped, not session-scoped. Debounce it so an
@@ -90,10 +90,9 @@ while [ "$DIR" != "/" ] && [ -n "$DIR" ]; do
90
90
  exit 0
91
91
  fi
92
92
 
93
- # Background the capture, redirect all output to a session-scoped log.
94
- # `--quiet` keeps streaming off (the log still captures the raw
95
- # SDK transcript); `--session` lets the capture command name its
96
- # own log file consistently if desired.
93
+ # Background the capture start, redirect all output to a session-scoped
94
+ # hook sidecar. The process manager writes canonical run records and JSONL
95
+ # event logs under the same `.almanac/runs/` directory.
97
96
  ( run_capture ) &
98
97
  # Detach so the shell doesn't wait on the subprocess.
99
98
  disown $! 2>/dev/null || true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codealmanac",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "A living wiki for codebases, maintained by AI agents. Documents what the code can't say: decisions, flows, invariants, incidents, gotchas.",
5
5
  "keywords": [
6
6
  "wiki",
@@ -10,7 +10,7 @@
10
10
  "codebase",
11
11
  "knowledge-base"
12
12
  ],
13
- "license": "PolyForm-Noncommercial-1.0.0",
13
+ "license": "MIT",
14
14
  "author": "Rohan Sheth",
15
15
  "repository": {
16
16
  "type": "git",
@@ -32,8 +32,7 @@
32
32
  "hooks",
33
33
  "guides",
34
34
  "README.md",
35
- "LICENSE",
36
- "COMMERCIAL.md"
35
+ "LICENSE"
37
36
  ],
38
37
  "engines": {
39
38
  "node": "20.x || 22.x || 23.x || 24.x || 25.x"
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,139 @@
1
+ # Page Notability And Graph Structure
2
+
3
+ Use these rules to decide what deserves a page, what deserves a topic, and how
4
+ clusters should form. These are judgment tools, not a closed schema.
5
+
6
+ ## Page Existence
7
+
8
+ A page deserves to exist when it captures durable, reusable project
9
+ understanding that would be costly, useful, or risky to reconstruct later.
10
+
11
+ Good page candidates include:
12
+
13
+ - **Entity**: a named thing the project reasons about, such as `run`,
14
+ `provider`, `topic`, `stripe`, `postgres`, or `claude-agent-sdk`.
15
+ - **Subsystem**: an area with responsibility and boundaries.
16
+ - **Flow**: behavior that crosses files, commands, systems, or agents.
17
+ - **Contract**: obligations between callers, providers, schemas, APIs,
18
+ commands, file formats, or external services.
19
+ - **Data model**: records, schemas, storage formats, indexes, serialized files,
20
+ or external payloads whose shape affects behavior.
21
+ - **Operation**: a recurring project or product action with inputs, outputs,
22
+ side effects, and verification.
23
+ - **Decision or rationale**: why the project chose one path over plausible
24
+ alternatives.
25
+ - **Risk or invariant**: a rule, coupling, assumption, or fragile behavior that
26
+ future work must preserve.
27
+ - **Dependency**: an external runtime, service, SDK, API, framework, law,
28
+ platform, or tool as used by this project.
29
+ - **Influence**: an external idea, paper, tradition, book, framework, or prior
30
+ art that shaped this project.
31
+ - **Research synthesis**: conclusions from docs, papers, experiments, external
32
+ references, or design exploration.
33
+ - **Market or product synthesis**: durable understanding about users,
34
+ positioning, pricing, competitors, sentiment, or product strategy.
35
+ - **Incident or postmortem**: what happened, what was learned, and what changed.
36
+ - **Hub**: a navigational page that explains a dense cluster.
37
+
38
+ Genres are vocabulary, not enforcement. Create a different shape when the
39
+ material genuinely needs it.
40
+
41
+ ## What Usually Does Not Deserve A Page
42
+
43
+ Avoid pages that are only:
44
+
45
+ - file-by-file summaries
46
+ - folder trees in prose
47
+ - raw transcripts
48
+ - generic API documentation copied from an external source
49
+ - task progress logs
50
+ - roadmaps that belong in an issue tracker
51
+ - guesses about intent that the repo or sources do not support
52
+ - one-off facts obvious from one nearby file
53
+ - date-stamped notes with no synthesis value
54
+ - pages whose only claim is that something exists
55
+
56
+ If the useful part of an input can be folded into an existing synthesis page,
57
+ do that instead of creating a new page.
58
+
59
+ ## Entities
60
+
61
+ Entity pages are first-class. Use the natural name as the slug when possible:
62
+ `stripe.md`, `postgres.md`, `run.md`, `topic.md`, `claude-agent-sdk.md`.
63
+
64
+ An entity page should explain:
65
+
66
+ - what the entity means in this project
67
+ - where it is represented in code, docs, config, or external systems
68
+ - who creates, reads, mutates, or depends on it
69
+ - what states, versions, or variants matter
70
+ - what assumptions and constraints surround it
71
+ - what related pages a future agent should read next
72
+
73
+ External entity pages are not encyclopedia entries. They describe the entity's
74
+ role in this project.
75
+
76
+ ## Topics And Clusters
77
+
78
+ Topics are reading neighborhoods. A topic should help answer: what should an
79
+ agent read together?
80
+
81
+ Good topics name stable areas of meaning:
82
+
83
+ - `provider-harness`
84
+ - `prompt-system`
85
+ - `wiki-indexing`
86
+ - `agent-tools-market`
87
+ - `product-positioning`
88
+ - `claude-agent-sdk`
89
+ - `pricing`
90
+
91
+ Bad topics are bookkeeping labels:
92
+
93
+ - `misc`
94
+ - `notes`
95
+ - `research`
96
+ - `external`
97
+ - exact filenames
98
+ - dates by default
99
+
100
+ Prefer existing topics. Create a topic when several pages now form a real
101
+ cluster or a new cluster is clearly expected to grow.
102
+
103
+ ## Hubs
104
+
105
+ A hub exists when search results are no longer enough to understand a cluster.
106
+
107
+ A hub should explain:
108
+
109
+ - what the cluster is
110
+ - which pages are core
111
+ - what a new agent should read first
112
+ - how the pages relate
113
+ - which pages are current synthesis and which are historical context
114
+ - what tensions, open questions, or major changes shape the area
115
+
116
+ Small clusters do not need separate hub pages. The main entity or subsystem
117
+ page can act as the local hub until navigation becomes unclear.
118
+
119
+ ## Splitting And Merging
120
+
121
+ Use summary style. A page may start broad. When a section grows into an
122
+ independently useful concept, split it into its own page and leave a short
123
+ summary plus link on the original page.
124
+
125
+ Split when:
126
+
127
+ - a section has its own internal structure
128
+ - other pages want to link to that section specifically
129
+ - incidents, decisions, or docs cluster around a subtopic
130
+ - a page is doing multiple unrelated jobs
131
+
132
+ Merge when:
133
+
134
+ - two pages answer the same future-agent question
135
+ - one page is only a stub pointing to another
136
+ - a set of date-stamped fragments should become an evolving synthesis page
137
+
138
+ Archive or supersede when knowledge is no longer current but remains useful as
139
+ history. Delete only when the page has no durable value.