diff --git a/.cursor-plugin/marketplace.json b/.cursor-plugin/marketplace.json index 66fb20a..918bb39 100644 --- a/.cursor-plugin/marketplace.json +++ b/.cursor-plugin/marketplace.json @@ -14,8 +14,8 @@ "description": "Skill mapping, practice plans, and learning retrospectives." }, { - "name": "continuous-learning", - "source": "continuous-learning", + "name": "continual-learning", + "source": "continual-learning", "description": "Incremental transcript-driven memory updates for AGENTS.md using high-signal bullet points only." }, { diff --git a/README.md b/README.md index 2b3c740..9aad033 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Official Cursor plugins for popular developer tools, frameworks, and SaaS produc | Plugin | Category | Description | |:-------|:---------|:------------| | [Teaching](teaching/) | Utilities | Skill maps, practice plans, and feedback loops | -| [Continuous Learning](continuous-learning/) | Developer Tools | Incremental transcript-driven AGENTS.md memory updates with high-signal bullet points | +| [Continual Learning](continual-learning/) | Developer Tools | Incremental transcript-driven AGENTS.md memory updates with high-signal bullet points | | [Cursor Team Kit](cursor-team-kit/) | Developer Tools | Internal-style workflows for CI, code review, shipping, and testing | | [Create Plugin](create-plugin/) | Developer Tools | Meta workflows for creating Cursor plugins with scaffolding and submission checks | | [Ralph Loop](ralph-loop/) | Developer Tools | Iterative self-referential AI loops using the Ralph Wiggum technique | diff --git a/continuous-learning/.cursor-plugin/plugin.json b/continual-learning/.cursor-plugin/plugin.json similarity index 87% rename from continuous-learning/.cursor-plugin/plugin.json rename to continual-learning/.cursor-plugin/plugin.json index 7274946..dddca77 100644 --- a/continuous-learning/.cursor-plugin/plugin.json +++ b/continual-learning/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { - "name": "continuous-learning", - "displayName": "Continuous Learning", + "name": "continual-learning", + "displayName": "Continual Learning", "version": "1.0.0", "description": "Incrementally learns durable user preferences and workspace facts from transcript changes and keeps AGENTS.md up to date with plain bullet points.", "author": { @@ -12,7 +12,7 @@ "license": "MIT", "logo": "assets/avatar.png", "keywords": [ - "continuous-learning", + "continual-learning", "agent-memory", "transcripts", "hooks", diff --git a/continuous-learning/LICENSE b/continual-learning/LICENSE similarity index 100% rename from continuous-learning/LICENSE rename to continual-learning/LICENSE diff --git a/continuous-learning/README.md b/continual-learning/README.md similarity index 58% rename from continuous-learning/README.md rename to continual-learning/README.md index b7190fa..94e4c67 100644 --- a/continuous-learning/README.md +++ b/continual-learning/README.md @@ -1,11 +1,11 @@ -# Continuous Learning +# Continual Learning Automatically and incrementally keeps `AGENTS.md` up to date from transcript changes. The plugin combines: - A `stop` hook that decides when to trigger learning. -- A `continuous-learning` skill that mines only high-signal transcript deltas. +- A `continual-learning` skill that mines only high-signal transcript deltas. It is designed to avoid noisy rewrites by: @@ -16,20 +16,20 @@ It is designed to avoid noisy rewrites by: ## Installation ```bash -/add-plugin continuous-learning +/add-plugin continual-learning ``` ## How it works -On eligible `stop` events, the hook may emit a `followup_message` that asks the agent to run the `continuous-learning` skill. +On eligible `stop` events, the hook may emit a `followup_message` that asks the agent to run the `continual-learning` skill. The hook keeps local runtime state in: -- `.cursor/hooks/state/continuous-learning.json` (cadence state) +- `.cursor/hooks/state/continual-learning.json` (cadence state) The skill uses an incremental transcript index at: -- `.cursor/hooks/state/continuous-learning-index.json` +- `.cursor/hooks/state/continual-learning-index.json` ## Trigger cadence @@ -47,12 +47,12 @@ Trial mode defaults (enabled in this plugin hook config): ## Optional env overrides -- `CONTINUOUS_LEARNING_MIN_TURNS` -- `CONTINUOUS_LEARNING_MIN_MINUTES` -- `CONTINUOUS_LEARNING_TRIAL_MODE` -- `CONTINUOUS_LEARNING_TRIAL_MIN_TURNS` -- `CONTINUOUS_LEARNING_TRIAL_MIN_MINUTES` -- `CONTINUOUS_LEARNING_TRIAL_DURATION_MINUTES` +- `CONTINUAL_LEARNING_MIN_TURNS` (or legacy `CONTINUOUS_LEARNING_MIN_TURNS`) +- `CONTINUAL_LEARNING_MIN_MINUTES` (or legacy `CONTINUOUS_LEARNING_MIN_MINUTES`) +- `CONTINUAL_LEARNING_TRIAL_MODE` (or legacy `CONTINUOUS_LEARNING_TRIAL_MODE`) +- `CONTINUAL_LEARNING_TRIAL_MIN_TURNS` (or legacy `CONTINUOUS_LEARNING_TRIAL_MIN_TURNS`) +- `CONTINUAL_LEARNING_TRIAL_MIN_MINUTES` (or legacy `CONTINUOUS_LEARNING_TRIAL_MIN_MINUTES`) +- `CONTINUAL_LEARNING_TRIAL_DURATION_MINUTES` (or legacy `CONTINUOUS_LEARNING_TRIAL_DURATION_MINUTES`) ## Output format in AGENTS.md diff --git a/continuous-learning/assets/avatar.png b/continual-learning/assets/avatar.png similarity index 100% rename from continuous-learning/assets/avatar.png rename to continual-learning/assets/avatar.png diff --git a/continuous-learning/hooks/continuous-learning-stop.ts b/continual-learning/hooks/continual-learning-stop.ts similarity index 77% rename from continuous-learning/hooks/continuous-learning-stop.ts rename to continual-learning/hooks/continual-learning-stop.ts index 0922e2a..0bfcc81 100644 --- a/continuous-learning/hooks/continuous-learning-stop.ts +++ b/continual-learning/hooks/continual-learning-stop.ts @@ -4,9 +4,9 @@ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "no import { dirname, resolve } from "node:path"; import { stdin } from "bun"; -const STATE_PATH = resolve(".cursor/hooks/state/continuous-learning.json"); +const STATE_PATH = resolve(".cursor/hooks/state/continual-learning.json"); const INCREMENTAL_INDEX_PATH = resolve( - ".cursor/hooks/state/continuous-learning-index.json" + ".cursor/hooks/state/continual-learning-index.json" ); const DEFAULT_MIN_TURNS = 10; const DEFAULT_MIN_MINUTES = 120; @@ -15,7 +15,7 @@ const TRIAL_DEFAULT_MIN_MINUTES = 15; const TRIAL_DEFAULT_DURATION_MINUTES = 24 * 60; const FOLLOWUP_MESSAGE = - `Run the \`continuous-learning\` skill now. First read existing \`AGENTS.md\` and update existing entries in place (do not only append). Use incremental transcript processing with index file \`${INCREMENTAL_INDEX_PATH}\`: only read transcripts not in the index or transcripts whose mtime is newer than indexed mtime (re-read changed transcripts). After processing, write back the updated index mtimes and remove entries for deleted transcripts. Update \`AGENTS.md\` only for high-signal, repeated user-correction patterns or durable workspace facts. Exclude one-off/transient details and secrets. Keep each learned section to at most 12 bullets. Write plain bullet points only, with no evidence/confidence tags or other metadata annotations. If no meaningful updates exist, respond exactly: No high-signal memory updates.`; + `Run the \`continual-learning\` skill now. First read existing \`AGENTS.md\` and update existing entries in place (do not only append). Use incremental transcript processing with index file \`${INCREMENTAL_INDEX_PATH}\`: only read transcripts not in the index or transcripts whose mtime is newer than indexed mtime (re-read changed transcripts). After processing, write back the updated index mtimes and remove entries for deleted transcripts. Update \`AGENTS.md\` only for high-signal, repeated user-correction patterns or durable workspace facts. Exclude one-off/transient details and secrets. Keep each learned section to at most 12 bullets. Write plain bullet points only, with no evidence/confidence tags or other metadata annotations. If no meaningful updates exist, respond exactly: No high-signal memory updates.`; interface StopHookInput { conversation_id: string; @@ -58,6 +58,10 @@ function parseBoolean(value: string | undefined): boolean { ); } +function readEnvValue(primary: string, legacy: string): string | undefined { + return process.env[primary] ?? process.env[legacy]; +} + function loadState(): ContinuousLearningState { const fallback: ContinuousLearningState = { version: 1, @@ -156,21 +160,31 @@ async function main(args: string[]): Promise { const now = Date.now(); const trialEnabled = - args.includes("--trial") || parseBoolean(process.env.CONTINUOUS_LEARNING_TRIAL_MODE); + args.includes("--trial") || + parseBoolean(readEnvValue("CONTINUAL_LEARNING_TRIAL_MODE", "CONTINUOUS_LEARNING_TRIAL_MODE")); if (trialEnabled && countedTurn && state.trialStartedAtMs === null) { state.trialStartedAtMs = now; } const trialDurationMinutes = parsePositiveInt( - process.env.CONTINUOUS_LEARNING_TRIAL_DURATION_MINUTES, + readEnvValue( + "CONTINUAL_LEARNING_TRIAL_DURATION_MINUTES", + "CONTINUOUS_LEARNING_TRIAL_DURATION_MINUTES" + ), TRIAL_DEFAULT_DURATION_MINUTES ); const trialMinTurns = parsePositiveInt( - process.env.CONTINUOUS_LEARNING_TRIAL_MIN_TURNS, + readEnvValue( + "CONTINUAL_LEARNING_TRIAL_MIN_TURNS", + "CONTINUOUS_LEARNING_TRIAL_MIN_TURNS" + ), TRIAL_DEFAULT_MIN_TURNS ); const trialMinMinutes = parsePositiveInt( - process.env.CONTINUOUS_LEARNING_TRIAL_MIN_MINUTES, + readEnvValue( + "CONTINUAL_LEARNING_TRIAL_MIN_MINUTES", + "CONTINUOUS_LEARNING_TRIAL_MIN_MINUTES" + ), TRIAL_DEFAULT_MIN_MINUTES ); const inTrialWindow = @@ -179,11 +193,11 @@ async function main(args: string[]): Promise { now - state.trialStartedAtMs < trialDurationMinutes * 60_000; const minTurns = parsePositiveInt( - process.env.CONTINUOUS_LEARNING_MIN_TURNS, + readEnvValue("CONTINUAL_LEARNING_MIN_TURNS", "CONTINUOUS_LEARNING_MIN_TURNS"), DEFAULT_MIN_TURNS ); const minMinutes = parsePositiveInt( - process.env.CONTINUOUS_LEARNING_MIN_MINUTES, + readEnvValue("CONTINUAL_LEARNING_MIN_MINUTES", "CONTINUOUS_LEARNING_MIN_MINUTES"), DEFAULT_MIN_MINUTES ); @@ -223,7 +237,7 @@ async function main(args: string[]): Promise { console.log(JSON.stringify({})); return 0; } catch (error) { - console.error("[continuous-learning-stop] failed", error); + console.error("[continual-learning-stop] failed", error); console.log(JSON.stringify({})); return 0; } diff --git a/continuous-learning/hooks/hooks.json b/continual-learning/hooks/hooks.json similarity index 50% rename from continuous-learning/hooks/hooks.json rename to continual-learning/hooks/hooks.json index 90c3d1c..690c86c 100644 --- a/continuous-learning/hooks/hooks.json +++ b/continual-learning/hooks/hooks.json @@ -3,7 +3,7 @@ "hooks": { "stop": [ { - "command": "bun run ./hooks/continuous-learning-stop.ts --trial" + "command": "bun run ./hooks/continual-learning-stop.ts --trial" } ] } diff --git a/continuous-learning/skills/continuous-learning/SKILL.md b/continual-learning/skills/continual-learning/SKILL.md similarity index 94% rename from continuous-learning/skills/continuous-learning/SKILL.md rename to continual-learning/skills/continual-learning/SKILL.md index 2bb9d8e..cf42fc6 100644 --- a/continuous-learning/skills/continuous-learning/SKILL.md +++ b/continual-learning/skills/continual-learning/SKILL.md @@ -1,9 +1,9 @@ --- -name: continuous-learning +name: continual-learning description: Incrementally extract recurring user corrections and durable workspace facts from transcript changes, then update AGENTS.md with plain bullet points only. Use when the user asks to mine previous chats, maintain AGENTS.md memory, or build a self-learning preference loop. --- -# Continuous Learning +# Continual Learning Keep `AGENTS.md` current using transcript deltas instead of full rescans. @@ -11,7 +11,7 @@ Keep `AGENTS.md` current using transcript deltas instead of full rescans. - Transcript root: `~/.cursor/projects//agent-transcripts/` - Existing memory file: `AGENTS.md` -- Incremental index: `.cursor/hooks/state/continuous-learning-index.json` +- Incremental index: `.cursor/hooks/state/continual-learning-index.json` ## Workflow