@a-company/paradigm 3.18.0 → 3.19.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.
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ normalizeLoreEntry,
4
+ recordLore
5
+ } from "./chunk-BRILIG7Z.js";
6
+ import "./chunk-ZXMDA7VB.js";
7
+
8
+ // src/commands/lore/migrate-assessments.ts
9
+ import chalk from "chalk";
10
+ import * as fs from "fs";
11
+ import * as path from "path";
12
+ import * as yaml from "js-yaml";
13
+ var ASSESSMENTS_DIR = ".paradigm/assessments";
14
+ async function loreMigrateAssessmentsCommand(options) {
15
+ const rootDir = process.cwd();
16
+ const arcsDir = path.join(rootDir, ASSESSMENTS_DIR, "arcs");
17
+ const dryRun = !!options.dryRun;
18
+ if (!fs.existsSync(arcsDir)) {
19
+ console.log(chalk.yellow("\n No assessments found at .paradigm/assessments/arcs/\n"));
20
+ return;
21
+ }
22
+ const arcDirs = fs.readdirSync(arcsDir).filter((d) => {
23
+ const stat = fs.statSync(path.join(arcsDir, d));
24
+ return stat.isDirectory();
25
+ });
26
+ let migrated = 0;
27
+ let skipped = 0;
28
+ const arcsProcessed = [];
29
+ for (const arcDir of arcDirs) {
30
+ const entriesDir = path.join(arcsDir, arcDir, "entries");
31
+ if (!fs.existsSync(entriesDir)) continue;
32
+ const entryFiles = fs.readdirSync(entriesDir).filter((f) => f.endsWith(".yaml") && !f.endsWith(".migrated"));
33
+ for (const file of entryFiles) {
34
+ const filePath = path.join(entriesDir, file);
35
+ try {
36
+ const content = fs.readFileSync(filePath, "utf8");
37
+ const assessment = yaml.load(content);
38
+ const tags = [
39
+ `arc:${assessment.arc_id}`,
40
+ `assessment:${assessment.type}`,
41
+ ...assessment.tags || [],
42
+ "migrated-from-assessment"
43
+ ];
44
+ const rawEntry = {
45
+ id: "",
46
+ // Will be generated
47
+ type: assessment.type,
48
+ timestamp: assessment.date,
49
+ author: assessment.author,
50
+ // Will be normalized
51
+ title: assessment.title,
52
+ summary: assessment.summary,
53
+ body: assessment.body,
54
+ symbols_touched: assessment.symbols || [],
55
+ tags,
56
+ linked_lore: assessment.linked_lore,
57
+ linked_tasks: assessment.linked_tasks,
58
+ linked_commits: assessment.linked_commits
59
+ };
60
+ const normalized = normalizeLoreEntry(rawEntry);
61
+ const entry = {
62
+ ...normalized,
63
+ id: ""
64
+ // Let recordLore generate a new ID
65
+ };
66
+ if (dryRun) {
67
+ console.log(chalk.gray(` [dry-run] Would migrate: ${assessment.id} \u2192 lore (arc:${assessment.arc_id})`));
68
+ } else {
69
+ await recordLore(rootDir, entry);
70
+ fs.renameSync(filePath, filePath.replace(".yaml", ".migrated"));
71
+ console.log(chalk.green(` Migrated: ${assessment.id} \u2192 ${entry.id} (arc:${assessment.arc_id})`));
72
+ }
73
+ migrated++;
74
+ if (!arcsProcessed.includes(assessment.arc_id)) {
75
+ arcsProcessed.push(assessment.arc_id);
76
+ }
77
+ } catch (err) {
78
+ console.error(chalk.red(` Failed to migrate ${file}: ${err}`));
79
+ skipped++;
80
+ }
81
+ }
82
+ }
83
+ console.log();
84
+ if (dryRun) {
85
+ console.log(chalk.yellow(` Dry run complete: ${migrated} entries would be migrated from ${arcsProcessed.length} arcs`));
86
+ } else {
87
+ console.log(chalk.green(` Migration complete: ${migrated} entries migrated from ${arcsProcessed.length} arcs`));
88
+ }
89
+ if (skipped > 0) {
90
+ console.log(chalk.yellow(` ${skipped} entries skipped due to errors`));
91
+ }
92
+ console.log(chalk.gray(` Arcs preserved as tags: ${arcsProcessed.map((a) => `arc:${a}`).join(", ")}`));
93
+ console.log();
94
+ }
95
+ export {
96
+ loreMigrateAssessmentsCommand
97
+ };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  recordLore,
4
4
  resolveAuthor
5
- } from "./chunk-YHRRJM6J.js";
5
+ } from "./chunk-BRILIG7Z.js";
6
6
  import "./chunk-ZXMDA7VB.js";
7
7
 
8
8
  // src/commands/lore/record.ts
@@ -24,7 +24,10 @@ async function loreRecordCommand(options) {
24
24
  commit: options.commit || void 0,
25
25
  learnings: options.learnings ? options.learnings.split(",").map((l) => l.trim()) : void 0,
26
26
  tags: options.tags ? options.tags.split(",").map((t) => t.trim()) : void 0,
27
- meta: options.meta ? JSON.parse(options.meta) : void 0
27
+ meta: options.meta ? JSON.parse(options.meta) : void 0,
28
+ body: options.body || void 0,
29
+ linked_lore: options.linkLore ? options.linkLore.split(",").map((l) => l.trim()) : void 0,
30
+ linked_commits: options.linkCommits ? options.linkCommits.split(",").map((c) => c.trim()) : void 0
28
31
  // git_context is auto-captured by recordLore
29
32
  };
30
33
  await recordLore(rootDir, entry);
@@ -3,7 +3,8 @@ import {
3
3
  getReindexToolsList,
4
4
  handleReindexTool,
5
5
  rebuildStaticFiles
6
- } from "./chunk-TUW27EIC.js";
6
+ } from "./chunk-EZ6XW6FB.js";
7
+ import "./chunk-3DYYXGDC.js";
7
8
  export {
8
9
  getReindexToolsList,
9
10
  handleReindexTool,
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ loadLoreEntries,
4
+ updateLoreEntry
5
+ } from "./chunk-BRILIG7Z.js";
6
+ import "./chunk-ZXMDA7VB.js";
7
+
8
+ // src/commands/lore/retag.ts
9
+ import chalk from "chalk";
10
+ async function loreRetagCommand(options) {
11
+ const rootDir = process.cwd();
12
+ const addTag = options.add;
13
+ const removeTag = options.remove;
14
+ if (!addTag && !removeTag) {
15
+ console.error(chalk.red("\n Must specify --add <tag> or --remove <tag>\n"));
16
+ process.exit(1);
17
+ }
18
+ const filter = {};
19
+ if (options.type) filter.type = options.type;
20
+ if (options.symbol) filter.symbol = options.symbol;
21
+ if (options.author) filter.author = options.author;
22
+ if (options.from) filter.dateFrom = options.from;
23
+ if (options.to) filter.dateTo = options.to;
24
+ if (options.tags) filter.tags = options.tags.split(",").map((t) => t.trim());
25
+ const entries = await loadLoreEntries(rootDir, filter);
26
+ if (entries.length === 0) {
27
+ console.log(chalk.yellow("\n No matching entries found\n"));
28
+ return;
29
+ }
30
+ const dryRun = !!options.dryRun;
31
+ let updated = 0;
32
+ for (const entry of entries) {
33
+ const currentTags = entry.tags || [];
34
+ let newTags;
35
+ if (addTag) {
36
+ if (currentTags.includes(addTag)) continue;
37
+ newTags = [...currentTags, addTag];
38
+ } else {
39
+ if (!currentTags.includes(removeTag)) continue;
40
+ newTags = currentTags.filter((t) => t !== removeTag);
41
+ }
42
+ if (dryRun) {
43
+ const action = addTag ? chalk.green(`+${addTag}`) : chalk.red(`-${removeTag}`);
44
+ console.log(chalk.gray(` [dry-run] ${entry.id}: ${action}`));
45
+ } else {
46
+ await updateLoreEntry(rootDir, entry.id, { tags: newTags });
47
+ const action = addTag ? chalk.green(`+${addTag}`) : chalk.red(`-${removeTag}`);
48
+ console.log(` ${entry.id}: ${action}`);
49
+ }
50
+ updated++;
51
+ }
52
+ console.log();
53
+ if (dryRun) {
54
+ console.log(chalk.yellow(` Dry run: ${updated} entries would be updated`));
55
+ } else {
56
+ console.log(chalk.green(` Updated ${updated} entries`));
57
+ }
58
+ console.log();
59
+ }
60
+ export {
61
+ loreRetagCommand
62
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  addReview
4
- } from "./chunk-YHRRJM6J.js";
4
+ } from "./chunk-BRILIG7Z.js";
5
5
  import "./chunk-ZXMDA7VB.js";
6
6
 
7
7
  // src/commands/lore/review.ts
@@ -9,7 +9,7 @@ async function loreServeCommand(path, options) {
9
9
  const shouldOpen = options.open !== false;
10
10
  console.log(chalk.cyan("\nStarting Lore Timeline...\n"));
11
11
  try {
12
- const { startLoreServer } = await import("./lore-server-XEW7EG62.js");
12
+ const { startLoreServer } = await import("./lore-server-2NYDLGCJ.js");
13
13
  console.log(chalk.gray(`Project: ${projectDir}`));
14
14
  console.log(chalk.gray(`Port: ${port}`));
15
15
  console.log();
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadLoreEntry
4
- } from "./chunk-YHRRJM6J.js";
4
+ } from "./chunk-BRILIG7Z.js";
5
5
  import "./chunk-ZXMDA7VB.js";
6
6
 
7
7
  // src/commands/lore/show.ts
@@ -27,10 +27,16 @@ Entry not found: ${id}
27
27
  "incident": chalk.hex("#f87171"),
28
28
  "milestone": chalk.hex("#60a5fa")
29
29
  };
30
- const colorFn = typeColor[entry.type] || chalk.white;
30
+ const typeColors = {
31
+ ...typeColor,
32
+ "retro": chalk.hex("#fb923c"),
33
+ "insight": chalk.hex("#a78bfa")
34
+ };
35
+ const entryType = entry.type || "agent-session";
36
+ const colorFn = typeColors[entryType] || chalk.white;
31
37
  console.log();
32
38
  console.log(chalk.white.bold(` ${entry.title}`));
33
- console.log(chalk.gray(` ${entry.id} \xB7 ${colorFn(entry.type)} \xB7 ${entry.timestamp}`));
39
+ console.log(chalk.gray(` ${entry.id} \xB7 ${colorFn(entryType)} \xB7 ${entry.timestamp}`));
34
40
  console.log();
35
41
  console.log(` \u{1F464} ${chalk.white(entry.author)}`);
36
42
  if (entry.agent) {
@@ -43,6 +49,34 @@ Entry not found: ${id}
43
49
  console.log(chalk.gray(" Summary:"));
44
50
  console.log(` ${entry.summary}`);
45
51
  console.log();
52
+ if (entry.body) {
53
+ console.log(chalk.gray(" Body:"));
54
+ for (const line of entry.body.split("\n")) {
55
+ console.log(` ${line}`);
56
+ }
57
+ console.log();
58
+ }
59
+ if (entry.linked_lore && entry.linked_lore.length > 0) {
60
+ console.log(chalk.gray(" Linked lore:"));
61
+ for (const id2 of entry.linked_lore) {
62
+ console.log(` ${chalk.cyan(id2)}`);
63
+ }
64
+ console.log();
65
+ }
66
+ if (entry.linked_tasks && entry.linked_tasks.length > 0) {
67
+ console.log(chalk.gray(" Linked tasks:"));
68
+ for (const id2 of entry.linked_tasks) {
69
+ console.log(` ${chalk.yellow(id2)}`);
70
+ }
71
+ console.log();
72
+ }
73
+ if (entry.linked_commits && entry.linked_commits.length > 0) {
74
+ console.log(chalk.gray(" Linked commits:"));
75
+ for (const sha of entry.linked_commits) {
76
+ console.log(` ${chalk.gray(sha)}`);
77
+ }
78
+ console.log();
79
+ }
46
80
  if (entry.symbols_touched?.length > 0) {
47
81
  console.log(chalk.gray(" Symbols touched:"));
48
82
  console.log(` ${entry.symbols_touched.map((s) => chalk.cyan(s)).join(" ")}`);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadLoreEntries
4
- } from "./chunk-YHRRJM6J.js";
4
+ } from "./chunk-BRILIG7Z.js";
5
5
  import "./chunk-ZXMDA7VB.js";
6
6
 
7
7
  // src/commands/lore/timeline.ts
@@ -737,56 +737,56 @@
737
737
  },
738
738
  {
739
739
  "id": "assessment-loops",
740
- "title": "Assessment Loops",
741
- "content": "## The Three Layers of Project Memory\n\nParadigm captures project knowledge at three distinct layers, each with a different nature, author, and granularity:\n\n| Layer | Nature | Created by | Granularity |\n|---|---|---|---|\n| Commits | Raw facts | Git | Per-change |\n| Lore | Session events | Agent + user | Per-session |\n| Assessments | Synthesized insight | Agent (mostly) + user | Per-arc milestone |\n\nCommits record what changed in the code. Lore records what happened in a session the context, decisions, and learnings. Assessments synthesize patterns across multiple sessions and commits into higher-order insights: retrospectives, strategic decisions, and milestone reflections.\n\nAssessments reference downward. An assessment entry can link to specific lore entries and commits, creating a hierarchy: assessments summarize lore, lore summarizes commits. This layering means you can zoom in from a high-level insight to the specific session that produced it, and from there to the exact code change.\n\n## Arcs: Grouping Related Assessments\n\nAssessments are organized into arcs. An arc is a named grouping that represents a theme, project phase, or ongoing concern think of it as a folder for related reflections.\n\n```yaml\nid: arc-auth-hardening\nname: Authentication Hardening\ndescription: Assessments related to the Q1 auth security initiative\nstatus: active\ncreated: \"2026-02-01T09:00:00Z\"\n```\n\nArc IDs use kebab-case with an `arc-` prefix: `arc-auth-hardening`, `arc-performance-tuning`, `arc-v2-migration`. The status is either `active` (ongoing), `complete` (finished successfully), or `archived` (closed without completion).\n\nArcs are stored at `.paradigm/assessments/arcs/{arc-id}/arc.yaml`, with their entries in a sibling `entries/` directory:\n\n```\n.paradigm/assessments/\n arcs/\n arc-auth-hardening/\n arc.yaml\n entries/\n A-2026-02-10-001.yaml\n A-2026-02-15-002.yaml\n arc-performance-tuning/\n arc.yaml\n entries/\n A-2026-02-12-001.yaml\n```\n\n## Anatomy of an Assessment Entry\n\nEach assessment entry captures a synthesized reflection:\n\n```yaml\nid: A-2026-02-15-002\narc: arc-auth-hardening\ntype: retro\ntimestamp: \"2026-02-15T16:00:00Z\"\ntitle: \"JWT refresh token rotation — what we learned\"\ncontent: |\n After three sessions implementing refresh token rotation,\n the key insight is that storing refresh tokens in httpOnly\n cookies eliminates an entire class of XSS vulnerabilities.\n The initial approach of localStorage was abandoned after\n session L-2026-02-12-001 surfaced the risk.\nsymbols: [\"#refresh-token-handler\", \"^authenticated\"]\nrelated_lore: [L-2026-02-10-003, L-2026-02-12-001, L-2026-02-14-002]\nrelated_commits: [a1b2c3d, e4f5g6h]\ntags: [security, auth, jwt]\n```\n\nEntry IDs follow the pattern `A-{YYYY-MM-DD}-{NNN}` and are globally unique across all arcs. The sequence number increments globally, not per-arc, so you will never have two entries with the same ID in different arcs.\n\nFour entry types capture different kinds of synthesized insight:\n\n| Type | When to Use |\n|---|---|\n| `retro` | Looking back at a completed piece of work what went well, what did not, what to change |\n| `insight` | A realization or pattern discovered across multiple sessions |\n| `decision` | A strategic or architectural decision with rationale and alternatives considered |\n| `milestone` | A significant achievement or phase completion worth marking |\n\n## The Six MCP Tools\n\n**`paradigm_assessment_record`** Add a reflection to an arc. If the arc does not exist, it is auto-created from the arc ID. Pass `arc` (the arc ID), `type` (retro/insight/decision/milestone), `title`, `content`, and optionally `symbols`, `related_lore`, `related_commits`, and `tags`. The entry is written with an auto-generated globally unique ID.\n\n**`paradigm_assessment_list`** — List arcs or entries within an arc. Without an arc ID, it returns all arcs with their status and entry count. With an arc ID, it returns entries within that arc sorted by date.\n\n**`paradigm_assessment_get`** Fetch full detail for a single entry (pass an `A-*` ID) or a full arc with all its entries (pass an `arc-*` ID). This is the deep-dive tool use it when you need the complete content and all linked references.\n\n**`paradigm_assessment_search`** — Cross-arc search with filters: by symbol, tag, entry type, and date range. This searches across all arcs simultaneously, making it easy to find every retrospective that mentions `#payment-service` regardless of which arc it lives in.\n\n**`paradigm_assessment_arc_create`** — Explicitly create an arc with a name, description, and initial status. While `paradigm_assessment_record` auto-creates arcs, this tool lets you set up an arc with a proper description before adding entries to it.\n\n**`paradigm_assessment_arc_close`** — Mark an arc as `complete` or `archived`. Complete arcs represent finished initiatives. Archived arcs represent work that was abandoned or superseded. Closed arcs remain searchable closing is a status change, not a deletion.\n\n## The Assessment Feedback Loop\n\nAssessments do not exist in isolation. They connect to the rest of Paradigm through two feedback mechanisms:\n\n**Downward references.** Every assessment entry can link to specific lore entries (`related_lore`) and commits (`related_commits`). This creates traceability: an insight about authentication can point to the three sessions that produced it and the five commits that implemented it. When someone reads the assessment, they can drill down to the raw evidence.\n\n**Task-to-assessment nudge.** When a task is marked as complete via `paradigm_task_done`, the system nudges the agent to consider recording an assessment. Completing a task is a natural reflection point — was this harder than expected? Did we learn something? Should we change our approach? The nudge is advisory, not mandatory, but it creates a habit of reflection tied to completion.\n\n## When to Record Assessments\n\nAssessments are higher-order than lore. While lore should be recorded for any session that modifies 3+ files, assessments should be recorded at natural reflection points:\n\n- **After completing a multi-session feature** — What did we learn across the sessions? (retro)\n- **When a pattern emerges across unrelated work** — \"Every time we touch the auth system, we find expired token edge cases\" (insight)\n- **When making a decision that affects future work** — \"We are switching from REST to GraphQL for the admin API\" (decision)\n- **When reaching a project milestone** — \"v2.0 shipped to production\" (milestone)\n\nThe general rule: if the knowledge would be valuable in 3 months, it belongs in an assessment. If it is only relevant for the next session, a task or lore entry is sufficient.\n\n## Arc Lifecycle\n\nArcs follow a natural lifecycle:\n\n1. **Creation** An arc is created (explicitly or auto-created) when a theme emerges. The name should be descriptive: `arc-auth-hardening`, not `arc-misc`.\n2. **Active collection** — Entries accumulate as work progresses. Retros after implementations, insights as patterns emerge, decisions when direction changes.\n3. **Closure** — When the initiative is complete or the theme is no longer active, close the arc with `paradigm_assessment_arc_close`. Use `complete` for successful initiatives, `archived` for abandoned ones.\n4. **Reference** — Closed arcs remain fully searchable. Future sessions can reference them when similar themes arise. The arc becomes part of institutional memory.\n\nWell-managed arcs have 5-15 entries over weeks or months. An arc with 1 entry should probably be merged into a broader arc. An arc with 50+ entries should probably be split into sub-themes.",
740
+ "title": "Lore as Unified Project Memory",
741
+ "content": "## Lore: The Single Source of Project Memory\n\nParadigm uses lore as its unified project memory system. Every piece of project knowledge session records, retrospectives, insights, decisions, milestones lives in lore entries, differentiated by `type` and classified by tags.\n\nThe model is simple: **one system, tags drive classification.**\n\n| Entry Type | When to Use |\n|---|---|\n| `agent-session` | Automated record of an AI-assisted work session |\n| `human-note` | Manual note from a human developer |\n| `decision` | Strategic or architectural decision with rationale |\n| `review` | Quality review of a previous entry |\n| `incident` | Production issue or bug report |\n| `milestone` | Significant project achievement |\n| `retro` | Retrospective looking back at completed work |\n| `insight` | A realization or pattern discovered across sessions |\n\nLore entries are stored as YAML files in `.paradigm/lore/entries/{date}/` with the `.lore` extension. Each entry has a unique ID: `L-{date}-{author}-{HHMMSS}-{NNN}`.\n\n## Tags Drive Classification\n\nTags are the primary classification mechanism in lore. Any string can be a tag, but certain prefixes carry special meaning:\n\n| Tag Prefix | Meaning | Example |\n|---|---|---|\n| `arc:` | Groups entries into a thematic arc | `arc:auth-hardening`, `arc:v2-migration` |\n| `assessment:` | Marks the reflection type | `assessment:retro`, `assessment:insight` |\n| `arc-closed` | Arc is no longer active | Added when an arc is complete |\n| `arc-status:` | Arc status metadata | `arc-status:complete`, `arc-status:archived` |\n\nArcs are simply tag prefixes no separate storage or management needed. To create an arc, just start tagging lore entries with `arc:my-arc-name`. To close an arc, add `arc-closed` and `arc-status:complete` tags to its entries.\n\n## The Body Field\n\nFor entries that need more than a 2-3 sentence summary, lore entries support a `body` field for long-form content. This is where retrospective narratives, detailed decision rationale, and multi-paragraph reflections live:\n\n```yaml\nid: L-2026-03-02-ascend-164500-001\ntype: retro\ntitle: \"JWT refresh token rotation — what we learned\"\nsummary: Completed refresh token rotation with httpOnly cookie storage.\nbody: |\n After three sessions implementing refresh token rotation,\n the key insight is that storing refresh tokens in httpOnly\n cookies eliminates an entire class of XSS vulnerabilities.\nsymbols_touched: [\"#refresh-token-handler\", \"^authenticated\"]\nlinked_lore: [L-2026-02-10-003, L-2026-02-12-001]\nlinked_commits: [a1b2c3d, e4f5g6h]\ntags: [arc:auth-hardening, assessment:retro, security, auth, jwt]\n```\n\n## Cross-Referencing\n\nLore entries can link to other project artifacts:\n\n- **`linked_lore`** References to other lore entry IDs, creating a web of related records\n- **`linked_tasks`** References to paradigm task IDs\n- **`linked_commits`** Git commit SHAs related to this entry\n\nThese links create traceability. A retrospective entry can point to the three session records that produced it and the five commits that implemented it.\n\n## Working with Lore\n\n**Recording:** Use `paradigm_lore_record` with `type`, `title`, `summary`, and `symbols_touched`. Add `body` for long-form content, `tags` with `arc:*` prefixes for arc grouping, and `linked_lore`/`linked_commits` for cross-references.\n\n**Searching:** Use `paradigm_lore_search` with filters:\n- `tag: \"arc:auth-hardening\"` Find all entries in an arc\n- `type: \"retro\"`Find all retrospectives\n- `hasBody: true` Find entries with detailed content\n- `symbol: \"#payment-service\"` — Find entries touching a symbol\n\n## The Reflection Loop\n\nLore supports a natural reflection cycle:\n\n1. **Session records** Automatically captured during work sessions (type: `agent-session`)\n2. **Reflection entries** Manually recorded at natural pause points (type: `retro`, `insight`, `decision`, `milestone`)\n3. **Arc grouping** Related reflections tagged with `arc:*` for thematic organization\n4. **Cross-referencing** Reflection entries link back to the sessions that produced them\n\nWhen a task is marked complete via `paradigm_task_done`, the system suggests recording a lore entry as a natural reflection point.\n\n## When to Record Reflective Entries\n\n- **After completing a multi-session feature** — What did we learn? (`retro` with `arc:feature-name`)\n- **When a pattern emerges** — \"Every time we touch auth, we find token edge cases\" (`insight`)\n- **When making a strategic choice** — \"Switching from REST to GraphQL\" (`decision`)\n- **When reaching a milestone** — \"v2.0 shipped to production\" (`milestone`)\n\nThe general rule: if the knowledge would be valuable in 3 months, record it as a reflective lore entry with appropriate tags.\n\n## Migration from Assessments\n\nProjects that used the older separate assessment system can migrate with `paradigm lore migrate-assessments`. This converts assessment entries to lore entries with `arc:{arc_id}` and `assessment:{type}` tags, preserving all data.",
742
742
  "keyConcepts": [
743
- "Three-layer model: commits (raw facts) -> lore (session events) -> assessments (synthesized insight)",
744
- "Arcs group related assessments by theme or initiative with arc-{kebab-case} IDs",
745
- "Entry IDs are globally unique: A-{YYYY-MM-DD}-{NNN}, not scoped per arc",
746
- "Four entry types: retro, insight, decision, milestone",
747
- "Six MCP tools: paradigm_assessment_record, paradigm_assessment_list, paradigm_assessment_get, paradigm_assessment_search, paradigm_assessment_arc_create, paradigm_assessment_arc_close",
748
- "Assessments reference downward linking to lore entries and commits for traceability",
749
- "Task completion nudges assessment recording as a natural reflection point"
743
+ "Lore is the unified project memory one system, tags drive classification",
744
+ "Eight entry types: agent-session, human-note, decision, review, incident, milestone, retro, insight",
745
+ "Arc tags (arc:*) group related entries by theme no separate arc management needed",
746
+ "The body field supports long-form content for detailed reflections",
747
+ "Cross-referencing via linked_lore, linked_tasks, and linked_commits creates traceability",
748
+ "paradigm_lore_search with tag filter finds entries across arcs",
749
+ "Task completion nudges lore recording as a natural reflection point"
750
750
  ],
751
751
  "quiz": [
752
752
  {
753
753
  "id": "q1",
754
- "question": "You have completed a three-session effort to add rate limiting. Across those sessions, you recorded three lore entries and completed two tasks. What is the most appropriate assessment entry type and why?",
754
+ "question": "You have completed a three-session effort to add rate limiting. You want to record a retrospective grouped with other rate-limiting work. What is the correct approach?",
755
755
  "choices": {
756
- "A": "`milestone` completing a multi-session feature is always a milestone",
757
- "B": "`retro` this is a natural reflection point after completing a body of work, capturing what went well and what to change",
758
- "C": "`decision` you decided to use rate limiting, so record the decision",
759
- "D": "`insight` you gained insight into rate limiting through three sessions",
760
- "E": "`retro` and `milestone` — record both entries in the same arc"
756
+ "A": "Call `paradigm_lore_record` with `type: \"retro\"`, a body with your reflection, and `tags: [\"arc:rate-limiting\"]`",
757
+ "B": "Call `paradigm_assessment_record` with `arc_id: \"arc-rate-limiting\"` and `type: \"retro\"`",
758
+ "C": "Call `paradigm_lore_record` with `type: \"milestone\"` completing features is always a milestone",
759
+ "D": "Create a separate `.paradigm/assessments/` directory and write the entry manually",
760
+ "E": "Call `paradigm_lore_record` with `type: \"agent-session\"` — all lore is session-level"
761
761
  },
762
- "correct": "B",
763
- "explanation": "A retro is the right type for reflecting on completed work it captures what happened across sessions, what went well, what did not, and what to change next time. A milestone (A) marks a significant project event like a release, not a feature completion. A decision (C) would be appropriate if the assessment focused on choosing the rate limiting strategy, but the question asks about the post-implementation reflection. Recording both (E) could be valid but the retro is the primary and most appropriate single entry."
762
+ "correct": "A",
763
+ "explanation": "Reflective entries are recorded via `paradigm_lore_record` with the appropriate type and arc tag. A retro with `tags: [\"arc:rate-limiting\"]` groups it with other entries in that arc. The body field holds the detailed reflection. The assessment tools (B) are deprecated wrappers. Milestones (C) mark significant project events, not feature completions. Agent-session (E) is for automated session records, not deliberate reflections."
764
764
  },
765
765
  {
766
766
  "id": "q2",
767
- "question": "An assessment entry has `related_lore: [L-2026-02-10-003, L-2026-02-12-001]` and `related_commits: [a1b2c3d]`. What does this downward referencing enable?",
767
+ "question": "A lore entry has `linked_lore: [L-2026-02-10-003, L-2026-02-12-001]` and `linked_commits: [a1b2c3d]`. What does this cross-referencing enable?",
768
768
  "choices": {
769
- "A": "It automatically updates the lore entries and commits with a backlink to the assessment",
770
- "B": "It creates traceability — readers can drill from the synthesized insight down to the specific sessions that produced it and the exact code changes",
769
+ "A": "It automatically updates the linked entries with backlinks",
770
+ "B": "It creates traceability — readers can drill from the synthesized insight down to the specific sessions and code changes",
771
771
  "C": "It prevents the referenced lore entries from being deleted",
772
772
  "D": "It triggers Sentinel to check those commits for incidents",
773
- "E": "It merges the lore entries into the assessment content automatically"
773
+ "E": "It merges the linked entries into a single combined entry"
774
774
  },
775
775
  "correct": "B",
776
- "explanation": "Downward references create a traceability chain: assessment -> lore -> commits. A reader encountering the insight can follow the `related_lore` links to see the full session context, and the `related_commits` links to see the exact code changes. This layered referencing is the core design of the three-layer model — each layer summarizes the one below it, with links to drill down for detail."
776
+ "explanation": "Cross-references create a traceability chain. A reader encountering an insight entry can follow `linked_lore` to see the full session context, and `linked_commits` to see the exact code changes. This is the core value of linking — each entry adds interpretation to what it references, with links to drill down for evidence."
777
777
  },
778
778
  {
779
779
  "id": "q3",
780
- "question": "You want to find every retrospective that mentions `#payment-service` across all arcs in your project. Which tool and approach is correct?",
780
+ "question": "You want to find every retrospective in the `arc:auth-hardening` arc that mentions `#payment-service`. Which approach is correct?",
781
781
  "choices": {
782
- "A": "`paradigm_assessment_list` for each arc, then manually filter entries mentioning the symbol",
783
- "B": "`paradigm_assessment_search` with `symbol: '#payment-service'` and `type: 'retro'` — it searches across all arcs simultaneously",
784
- "C": "`paradigm_assessment_get` with the arc ID containing payment-related work",
785
- "D": "`paradigm_lore_search` with `symbol: '#payment-service'` — lore and assessments share the same search",
786
- "E": "`paradigm_search` with `query: 'payment retro'` the general search covers assessments"
782
+ "A": "Call `paradigm_lore_search` with `tag: \"arc:auth-hardening\"`, `type: \"retro\"`, and `symbol: \"#payment-service\"`",
783
+ "B": "Call `paradigm_assessment_search` with `symbol: \"#payment-service\"` — it searches the old assessment system",
784
+ "C": "Call `paradigm_lore_search` with `tags: [\"arc:auth-hardening\", \"retro\"]`",
785
+ "D": "Call `paradigm_search` with `query: \"payment retro auth\"` — general search covers lore",
786
+ "E": "Read every file in `.paradigm/lore/entries/` and filter manually"
787
787
  },
788
- "correct": "B",
789
- "explanation": "`paradigm_assessment_search` is designed for cross-arc queries with filters. Passing `symbol: '#payment-service'` and `type: 'retro'` returns all retrospective entries that reference the payment service, regardless of which arc they belong to. Listing per-arc (A) works but is tedious. `paradigm_lore_search` (D) only searches lore entries, not assessments they are separate systems. `paradigm_search` (E) searches the symbol index, not assessment content."
788
+ "correct": "A",
789
+ "explanation": "`paradigm_lore_search` supports combining filters: `tag` for arc prefix matching, `type` for entry type, and `symbol` for symbol references. These filters combine (AND logic), so you get only retro entries in the auth-hardening arc that touch the payment service. The assessment tools (B) are deprecated. Using `tags` array (C) uses OR logic, not AND. General search (D) searches the symbol index, not lore content."
790
790
  }
791
791
  ]
792
792
  }
@@ -2224,17 +2224,17 @@
2224
2224
  "variants": [
2225
2225
  {
2226
2226
  "id": "plsat-091",
2227
- "scenario": "An agent finishes a debugging session and wants to record the root cause and resolution as a lasting insight. The team already has an assessment arc called `arc-auth-hardening` tracking authentication improvements. The agent calls `paradigm_assessment_record` with `type: \"insight\"`, `arc_id: \"arc-auth-hardening\"`, and a summary of the fix. Three entries already exist across all arcs today (2026-04-02).",
2228
- "question": "What entry ID is assigned, and where is the file stored?",
2227
+ "scenario": "An agent finishes a debugging session and wants to record the root cause and resolution as a lasting insight, grouped under the `arc:auth-hardening` arc. The agent calls `paradigm_lore_record` with `type: \"insight\"`, `tags: [\"arc:auth-hardening\", \"assessment:insight\"]`, a summary, and a body with the detailed analysis. The author is `ascend` and the timestamp is `2026-04-02T16:30:00Z`.",
2228
+ "question": "Where is the entry stored, and how does the arc grouping work?",
2229
2229
  "choices": {
2230
- "A": "A-2026-04-02-001 stored in `.paradigm/assessments/arcs/arc-auth-hardening/entries/A-2026-04-02-001.yaml` \u2014 entry IDs are sequential per arc.",
2231
- "B": "A-2026-04-02-004 stored in `.paradigm/assessments/arcs/arc-auth-hardening/entries/A-2026-04-02-004.yaml` \u2014 entry IDs are globally unique across all arcs.",
2232
- "C": "I-2026-04-02-004 stored in `.paradigm/assessments/insights/I-2026-04-02-004.yaml` \u2014 insights have their own prefix and directory.",
2233
- "D": "A-auth-hardening-004 stored in `.paradigm/assessments/entries/A-auth-hardening-004.yaml` \u2014 entry IDs embed the arc name.",
2234
- "E": "A-2026-04-02-004 stored in `.paradigm/assessments/entries/2026-04-02/A-2026-04-02-004.yaml` \u2014 entries are grouped by date, not arc."
2230
+ "A": "Stored in `.paradigm/assessments/arcs/arc-auth-hardening/entries/` \u2014 arcs have their own storage directories.",
2231
+ "B": "Stored in `.paradigm/lore/entries/2026-04-02/` as a `.lore` file \u2014 arcs are just tag prefixes, not separate storage.",
2232
+ "C": "Stored in `.paradigm/lore/arcs/auth-hardening/` \u2014 arc entries get their own subdirectory.",
2233
+ "D": "Stored in `.paradigm/lore/entries/` root directory \u2014 no date partitioning for arc entries.",
2234
+ "E": "Stored in both `.paradigm/lore/` and `.paradigm/assessments/` \u2014 the system maintains backward compatibility."
2235
2235
  },
2236
2236
  "correct": "B",
2237
- "explanation": "Assessment entry IDs follow the format A-YYYY-MM-DD-NNN where NNN is globally unique across ALL arcs \u2014 the ID generator scans every arc's entries directory to determine the next sequence number. Since three entries already exist today, this one gets A-2026-04-02-004. The file is stored under the arc's own entries directory at `.paradigm/assessments/arcs/arc-auth-hardening/entries/A-2026-04-02-004.yaml`. This global uniqueness guarantees that an entry ID alone is sufficient to locate any assessment entry without knowing which arc it belongs to."
2237
+ "explanation": "All lore entries are stored in `.paradigm/lore/entries/{date}/` as `.lore` files, regardless of their tags. Arcs are simply tag prefixes (e.g., `arc:auth-hardening`) \u2014 they require no separate directory structure or management. To find all entries in an arc, use `paradigm_lore_search` with `tag: \"arc:auth-hardening\"`. This unified storage eliminates the complexity of a separate assessment system while preserving full arc-based organization through tags."
2238
2238
  }
2239
2239
  ]
2240
2240
  },
@@ -2245,17 +2245,17 @@
2245
2245
  "variants": [
2246
2246
  {
2247
2247
  "id": "plsat-092",
2248
- "scenario": "A developer asks their agent to record a retrospective about a failed deployment. The agent calls `paradigm_assessment_record` with `type: \"retro\"`, `arc_name: \"Q1 Platform Stability\"`, but does NOT provide an `arc_id`. No arc for platform stability exists yet.",
2249
- "question": "What happens when `arc_name` is provided without an `arc_id` to `paradigm_assessment_record`?",
2248
+ "scenario": "A developer wants to record retrospectives about a failed deployment. They have no prior entries tagged with `arc:platform-stability`. The agent calls `paradigm_lore_record` with `type: \"retro\"`, `tags: [\"arc:platform-stability\", \"assessment:retro\"]`, a title, summary, and body describing the failure and lessons learned.",
2249
+ "question": "What happens when you use a new arc tag that no prior entries have?",
2250
2250
  "choices": {
2251
- "A": "The call fails with an error \u2014 `arc_id` is always required when recording an entry.",
2252
- "B": "The entry is recorded as an orphan in `.paradigm/assessments/unassigned/`.",
2253
- "C": "The tool auto-creates a new arc (deriving an arc_id like `arc-q1-platform-stability` from the name) and records the entry inside it.",
2254
- "D": "The tool searches existing arcs by name and fails if no exact match is found.",
2255
- "E": "The entry is recorded with a temporary arc_id that must be manually linked later."
2251
+ "A": "The call fails \u2014 arcs must be explicitly created before tagging entries.",
2252
+ "B": "The entry is recorded normally \u2014 arcs are just tag prefixes, no creation step needed. The arc exists as soon as an entry has the tag.",
2253
+ "C": "The system auto-creates a `.paradigm/lore/arcs/platform-stability/` directory to track the arc.",
2254
+ "D": "The entry is recorded but flagged as orphaned until an arc is formally registered.",
2255
+ "E": "The tag is rejected because it does not match an existing arc in the arc registry."
2256
2256
  },
2257
- "correct": "C",
2258
- "explanation": "When `arc_name` is provided without an `arc_id`, `paradigm_assessment_record` auto-creates the arc. The arc_id is derived by converting the name to kebab-case and prefixing with `arc-` (validated against `/^arc-[a-z0-9-]+$/`). This creates the arc directory structure at `.paradigm/assessments/arcs/arc-q1-platform-stability/` with an `arc.yaml` and the entry in its `entries/` subdirectory. This convenience behavior reduces friction \u2014 agents can record assessments without a separate arc creation step."
2257
+ "correct": "B",
2258
+ "explanation": "Arcs in the unified lore system are simply tag prefixes \u2014 no explicit creation needed. The first entry tagged with `arc:platform-stability` effectively creates that arc. To find all entries in this arc later, use `paradigm_lore_search` with `tag: \"arc:platform-stability\"`. To close the arc, add `arc-closed` and `arc-status:complete` tags to its entries. This tag-based approach eliminates the overhead of managing separate arc directories and YAML files."
2259
2259
  }
2260
2260
  ]
2261
2261
  },
@@ -2266,17 +2266,17 @@
2266
2266
  "variants": [
2267
2267
  {
2268
2268
  "id": "plsat-093",
2269
- "scenario": "Your project has been running for six months. The codebase has 200+ commits (raw facts in git), 45 lore entries (session-level events captured by the post-commit hook), and 12 assessment entries across 3 arcs (synthesized insights from retrospectives and decisions). A new team member asks how these three layers relate to each other.",
2270
- "question": "Which statement BEST describes Paradigm's three-layer knowledge model?",
2269
+ "scenario": "Your project has been running for six months. The codebase has 200+ commits in git and 57 lore entries: 45 are `agent-session` type (automatic session records), 8 have `arc:*` tags (retrospectives and insights grouped into thematic arcs), and 4 are `decision` type (architectural decisions). A new team member asks how lore's different entry types and tags work together.",
2270
+ "question": "Which statement BEST describes Paradigm's unified lore model?",
2271
2271
  "choices": {
2272
- "A": "Commits, lore, and assessments are independent systems \u2014 they share no data and serve different audiences.",
2273
- "B": "Lore replaces commit messages with richer context, and assessments replace lore when insights are finalized.",
2274
- "C": "Commits capture raw facts (what changed), lore captures session-level events (what happened and why), and assessments synthesize cross-session insights (what we learned) \u2014 each layer builds on the one below it.",
2275
- "D": "Assessments are the authoritative layer \u2014 commits and lore are temporary and should be pruned once assessments exist.",
2276
- "E": "Lore and assessments are both subsets of the commit history, just filtered by different criteria."
2272
+ "A": "Lore entries are all the same \u2014 tags are purely cosmetic and do not affect searching or organization.",
2273
+ "B": "Lore is the single project memory system. Entry types classify the nature of knowledge (session, retro, insight, decision), while tags like `arc:*` group related entries into themes \u2014 both are filterable via `paradigm_lore_search`.",
2274
+ "C": "Session entries and reflection entries are stored in separate directories, with tags used only for cross-referencing between them.",
2275
+ "D": "The `arc:*` tags are managed by a separate arc subsystem that must be initialized before use.",
2276
+ "E": "Entry types are deprecated \u2014 tags alone drive all classification in the new model."
2277
2277
  },
2278
- "correct": "C",
2279
- "explanation": "Paradigm's three-layer knowledge model is: Commits (raw facts \u2014 what code changed, captured by git), Lore (session events \u2014 what happened during a work session and why, captured by the post-commit hook into `.paradigm/history/`), and Assessments (synthesized insight \u2014 what the team learned across multiple sessions, recorded into `.paradigm/assessments/`). Each layer adds interpretation: commits are mechanical diffs, lore adds narrative context, and assessments distill patterns and decisions. All three layers persist and remain valuable \u2014 none replaces or supersedes the others."
2278
+ "correct": "B",
2279
+ "explanation": "Paradigm's unified lore model uses one system with two classification axes: entry `type` classifies the nature of the knowledge (agent-session for automated records, retro for retrospectives, insight for patterns, decision for choices, etc.), while tags provide flexible grouping (arc:* for thematic arcs, assessment:* for reflection type, plus arbitrary project tags). Both are searchable via `paradigm_lore_search` \u2014 you can filter by type, tag prefix, symbol, author, and date range. All entries live in the same `.paradigm/lore/entries/` directory structure regardless of type or tags."
2280
2280
  }
2281
2281
  ]
2282
2282
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a-company/paradigm",
3
- "version": "3.18.0",
3
+ "version": "3.19.0",
4
4
  "description": "Unified CLI for Paradigm developer tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- closeArc,
4
- createArc,
5
- loadArc,
6
- loadArcs,
7
- loadEntries,
8
- loadEntry,
9
- rebuildAssessmentIndex,
10
- recordEntry,
11
- searchEntries
12
- } from "./chunk-DSXS42FY.js";
13
- export {
14
- closeArc,
15
- createArc,
16
- loadArc,
17
- loadArcs,
18
- loadEntries,
19
- loadEntry,
20
- rebuildAssessmentIndex,
21
- recordEntry,
22
- searchEntries
23
- };