forgetrail 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,9 +12,9 @@
12
12
 
13
13
  ForgeTrail gives your next coding session a place to start. It keeps the phase, decisions, and handoff in your repository so an agent can read them when you resume. Start with Lite for a small project. You do not have to run all seven phases to try the method.
14
14
 
15
- ForgeTrail instructs the agent to read tracking, preserve approved decisions, and pause at approval gates. The agent must write the handoff. Those updates are not automatic. Optional hooks enforce the checks documented for their supported host.
15
+ ForgeTrail instructs the agent to read the ledger, preserve approved decisions, and pause at approval gates. The agent must write the handoff. Those updates are not automatic. Optional hooks enforce the checks documented for their supported host.
16
16
 
17
- In session one, the agent drafts a Phase 1 brief, you approve it, and the agent logs the stack decision and a note for next time. In session two, a fresh chat reads that record, skips the settled questions, finishes the open Phase 1 item, and asks to move into Phase 2 with that phase's guidance. The record is `.forgetrail/workflow_tracking.json`. Labeled walk-through: [`content/examples/two-session-continuity.md`](content/examples/two-session-continuity.md).
17
+ In session one, the agent drafts a Phase 1 brief, you approve it, and the agent logs the stack decision and a note for next time. In session two, a fresh chat reads that record, skips the settled questions, finishes the open Phase 1 item, and asks to move into Phase 2 with that phase's guidance. The record is the [AppLedger](https://appledger.dev) ledger in `appledger/`: the phase in `profiles/forgetrail.yaml`, plus decision, lesson, and session records. `pnpm dlx appledger init` creates it. Labeled walk-through: [`content/examples/two-session-continuity.md`](content/examples/two-session-continuity.md).
18
18
 
19
19
  **Docs:** [forgetrail.dev/docs](https://forgetrail.dev/docs) · **Site:** [forgetrail.dev](https://forgetrail.dev)
20
20
 
@@ -38,9 +38,10 @@ The shortest supported first task is: create `appledger/`, draft `docs/PHASE_1_B
38
38
 
39
39
  ```bash
40
40
  pnpm dlx forgetrail install --lite --with-genesis-stub
41
+ pnpm dlx appledger init --name "Your app name"
41
42
  ```
42
43
 
43
- MCP: `npx -y forgetrail-mcp` with `FORGETRAIL_ROOT` set. Prefer `pnpm dlx` on Windows. Do not add `forgetrail` to an app's `dependencies`. Do not merge the two packages.
44
+ MCP: `npx -y forgetrail-mcp` (0.4.2 or later finds the methodology without `FORGETRAIL_ROOT`). Prefer `pnpm dlx` on Windows. Do not add `forgetrail` to an app's `dependencies`. Do not merge the two packages.
44
45
 
45
46
  ## What you get
46
47
 
@@ -1,6 +1,6 @@
1
1
  # ForgeTrail Lite — portable kickoff for any agentic chat
2
2
 
3
- > **ForgeTrail Lite v2.2.0**
3
+ > **ForgeTrail Lite v2.2.1**
4
4
  > © Catalyst Forge, LLC — [www.catalystforge.com](https://www.catalystforge.com)
5
5
  > Part of the **ForgeTrail** open-source methodology ([Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0) in the upstream ForgeTrail repo).
6
6
  >
@@ -320,7 +320,7 @@ Record anything non-obvious as a lesson in **`appledger/`** (for example, Playwr
320
320
  2. **`.forgetrail/cursor/rules/forgetrail-updates-log.mdc`** — use the §12.5 snippet verbatim. **Symlink or copy** into `.cursor/rules/` so Cursor reminds agents when to update `FORGETRAIL_LITE_UPDATES.md` (§1.6). Optional: copy the upstream **`FORGETRAIL_LITE_UPDATES.md`** starter into `.forgetrail/` when you expect protocol feedback during the project.
321
321
  3. **`.forgetrail/hooks/` and `.cursor/hooks.json`** — install host safety hooks (`content/hooks/`) into `.forgetrail/hooks/` and copy `cursor-hooks.json` to `.cursor/hooks.json`. On Cursor, this runs pre-commit verification, enforces pnpm lock consistency, gates git push at the tool level, and injects live phase context at session start. For Claude Code, add `claude-settings-hooks.json` into `.claude/settings.json`.
322
322
  If any of these already exists and its content conflicts with the Lite defaults, **do not overwrite** — flag the conflict to the user and ask how to reconcile. Record the reconciliation as a decision in `appledger/`.
323
- 4. **Create `appledger/`** if it does not exist: `manifest.yaml`, `profiles/forgetrail.yaml` with the `plan` phase `in_progress`, an application record, and a session record. Do **not** create `.forgetrail/workflow_tracking.json`. Fill the application name and a one-line description from whatever the user has already said. Criteria stay `pending` until evidence exists.
323
+ 4. **Create `appledger/`** if it does not exist. Run `pnpm dlx appledger init --name "<application name>"` (or `appledger init` when it is installed globally), then `pnpm dlx appledger check`. Init writes `manifest.yaml`, `profiles/forgetrail.yaml` with the `plan` phase `in_progress`, an application record, and a session record. It does not overwrite existing files. Init leaves the purpose as "Not supplied." Write the one-line purpose into the application record from what the user has already said, then run `check` again. Do **not** create `.forgetrail/workflow_tracking.json`. Criteria stay `pending` until evidence exists. **Without Node:** write the same four files by hand in the shape of the [minimal example ledger](https://github.com/Catalyst-Forge-LLC/appledger/tree/main/examples/minimal/appledger), and run `appledger check` once Node is available. A hand-written ledger is not checked until then.
324
324
  5. **If git was initialized in step 2**, make the first commit now so the user has a clean baseline. **What lands in the commit depends on §1.5:** if **committing `.forgetrail/`**, steps 3–4 artifacts are included; if **gitignoring `.forgetrail/`**, only `.gitignore` (and any `.cursor/rules/` copies) — the workspace stays local-only and that is expected, not a mistake. Example: `git add -A && git commit -m "chore: ForgeTrail Lite bootstrap"`. Skip this step if the repo already had history — do not squash or amend what's there. Skip entirely if the user is in no-git mode (§4.1).
325
325
  6. **Ask the §5 intake questions.** Do not write any project code yet. For the first user-facing reply, follow §9 (plain product language, one clear "reply with," no methodology jargon).
326
326
  7. **Create `docs/`** (if missing) and **draft `docs/PHASE_1_BRIEF.md`** from the §6 template using the user's answers. Show it to the user, iterate, then **lock it**: mark the brief criteria met in `appledger/profiles/forgetrail.yaml` only when the user has approved them, and record major commitments as decision records.
@@ -1003,7 +1003,7 @@ Save this as `.forgetrail/AGENTS.md` so agents that auto-load it (Codex, Cursor,
1003
1003
 
1004
1004
  ```markdown
1005
1005
  <!--
1006
- Agent protocol based on ForgeTrail Lite v2.2.0.
1006
+ Agent protocol based on ForgeTrail Lite v2.2.1.
1007
1007
  © Catalyst Forge, LLC — www.catalystforge.com
1008
1008
  Licensed under Apache License 2.0 (upstream ForgeTrail repo).
1009
1009
  -->
@@ -1179,4 +1179,4 @@ ForgeTrail Lite covers the shape of a project. The full **ForgeTrail MCP server*
1179
1179
 
1180
1180
  ---
1181
1181
 
1182
- **ForgeTrail Lite v2.2.0** · © Catalyst Forge, LLC · [www.catalystforge.com](https://www.catalystforge.com) · [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)
1182
+ **ForgeTrail Lite v2.2.1** · © Catalyst Forge, LLC · [www.catalystforge.com](https://www.catalystforge.com) · [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)
package/docs/NPM.md CHANGED
@@ -10,12 +10,12 @@ Two public unscoped packages:
10
10
 
11
11
  | Package | This tree | On npm until you publish | From | What it is |
12
12
  | --- | --- | --- | --- | --- |
13
- | [`forgetrail`](https://www.npmjs.com/package/forgetrail) | 0.5.0 | 0.4.20 | repo root | CLI + Lite + templates. `pnpm dlx forgetrail install --lite` |
14
- | [`forgetrail-mcp`](https://www.npmjs.com/package/forgetrail-mcp) | 0.4.0 | 0.3.10 | `mcp-server/` | MCP bin. `pnpm dlx forgetrail-mcp` |
13
+ | [`forgetrail`](https://www.npmjs.com/package/forgetrail) | 0.5.2 | 0.5.2 | repo root | CLI + Lite + templates. `pnpm dlx forgetrail install --lite` |
14
+ | [`forgetrail-mcp`](https://www.npmjs.com/package/forgetrail-mcp) | 0.4.2 | 0.4.1 | `mcp-server/` | MCP bin. Depends on `forgetrail` for content. `pnpm dlx forgetrail-mcp` |
15
15
 
16
16
  These are **installer and MCP channels**, not a library. App repos should not add `forgetrail` to `dependencies`.
17
17
 
18
- `0.5.0` stops installing `workflow_tracking.json`. `0.4.0` tells kickoff to run `appledger init`. The registry copies above do not include that cutover. `pnpm run pack:check` is the gate. It does not publish.
18
+ `forgetrail@0.5.2` is on npm. This tree has Lite v2.2.1 and a new installer `Next:` step that are not in `0.5.2`, so `forgetrail` needs a version bump before its next publish. `forgetrail-mcp@0.4.2` is this tree and is not published yet. It adds `forgetrail` as a dependency and returns an explicit error when content is missing. `0.4.1` remains the registry copy until you publish from `mcp-server/`. `pnpm run pack:check` is the gate. It does not publish.
19
19
 
20
20
  ---
21
21
 
@@ -59,11 +59,11 @@ The `Debugger listening` line on MCP `prepack` is Cursor attaching to a one-line
59
59
 
60
60
  ```bash
61
61
  # Prefer pnpm dlx. npm 12 `npx forgetrail --help` on Windows failed to spawn the bin.
62
- pnpm dlx forgetrail@0.5.0 --help
63
- pnpm dlx forgetrail@0.5.0 install --lite --dry-run
62
+ pnpm dlx forgetrail@<version> --help
63
+ pnpm dlx forgetrail@<version> install --lite --dry-run
64
64
 
65
- # MCP starts; needs content via FORGETRAIL_ROOT or a sibling forgetrail install
66
- pnpm dlx forgetrail-mcp@0.4.0
65
+ # MCP starts and reads content from its forgetrail dependency. ping should not say "content missing".
66
+ pnpm dlx forgetrail-mcp@0.4.2
67
67
  ```
68
68
 
69
69
  Optional Cursor MCP (content from a `forgetrail` install, or set the path):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgetrail",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "private": false,
5
5
  "description": "ForgeTrail: a persistent development system for building software with AI agents. CLI, Lite protocol, and methodology templates.",
6
6
  "license": "Apache-2.0",
@@ -88,6 +88,7 @@ export function runInstallForgetrail(rawArgv, { defaultToCwd = false } = {}) {
88
88
  console.log(" First chat: _forgetrail/INITIAL_PROMPT.md");
89
89
  console.log(" Project record: appledger/ (not workflow_tracking.json)");
90
90
  console.log(" Hooks: .forgetrail/hooks/ (enforced via .cursor/hooks.json)");
91
+ printLedgerNext();
91
92
  return { target, mode: "full" };
92
93
  }
93
94
 
@@ -145,11 +146,18 @@ export function runInstallLite(rawArgv, { defaultToCwd = false } = {}) {
145
146
  console.log(" Hooks: .forgetrail/hooks/ (enforced via .cursor/hooks.json)");
146
147
  if (args.withGenesisStub) {
147
148
  console.log(" Genesis: docs/GENESIS.md (stub — replace with your spec)");
148
- console.log(" Next: see TRY_FORGETRAIL.md in the ForgeTrail repo");
149
149
  }
150
+ printLedgerNext();
150
151
  return { target, mode: "lite", withGenesisStub: !!args.withGenesisStub };
151
152
  }
152
153
 
154
+ function printLedgerNext() {
155
+ console.log("\nNext, create the ledger in the app folder (the agent can run these):");
156
+ console.log(' pnpm dlx appledger init --name "Your app name"');
157
+ console.log(" pnpm dlx appledger check");
158
+ console.log("Then paste the kickoff line from https://forgetrail.dev/docs/try");
159
+ }
160
+
153
161
  export const INSTALL_FULL_HELP = `
154
162
  ForgeTrail template-in-repo install (offline / no MCP server required)
155
163
 
@@ -125,21 +125,36 @@ export function posixPath(p) {
125
125
  return p.replace(/\\/g, "/");
126
126
  }
127
127
 
128
+ /** True when this CLI runs from a clone that has mcp-server/ (the npm package does not ship it). */
129
+ export function isClone() {
130
+ return existsSync(join(MCP_SERVER_DIR, "package.json"));
131
+ }
132
+
133
+ /** pnpm dlx and npx unpack into a cache that can be removed, so its path is not a stable FORGETRAIL_ROOT. */
134
+ export function isTemporaryInstall(p = FORGETRAIL_ROOT) {
135
+ return /[\\/](dlx|_npx)[\\/]/i.test(p);
136
+ }
137
+
128
138
  export function mcpClientConfigObject() {
129
- return {
130
- mcpServers: {
131
- forgetrail: {
132
- command: "node",
133
- args: [posixPath(MCP_ENTRY)],
134
- env: { FORGETRAIL_ROOT: posixPath(FORGETRAIL_ROOT) },
139
+ if (existsSync(MCP_ENTRY)) {
140
+ return {
141
+ mcpServers: {
142
+ forgetrail: {
143
+ command: "node",
144
+ args: [posixPath(MCP_ENTRY)],
145
+ env: { FORGETRAIL_ROOT: posixPath(FORGETRAIL_ROOT) },
146
+ },
135
147
  },
136
- },
137
- };
148
+ };
149
+ }
150
+ const server = { command: "npx", args: ["-y", "forgetrail-mcp"] };
151
+ if (!isTemporaryInstall()) server.env = { FORGETRAIL_ROOT: posixPath(FORGETRAIL_ROOT) };
152
+ return { mcpServers: { forgetrail: server } };
138
153
  }
139
154
 
140
155
  /** Copy-paste MCP client setup — shown after `forgetrail mcp build`. */
141
156
  export function printMcpClientSetupBanner({ showBuildComplete = true } = {}) {
142
- const entry = posixPath(MCP_ENTRY);
157
+ const fromClone = existsSync(MCP_ENTRY);
143
158
 
144
159
  if (showBuildComplete) {
145
160
  console.log("\n✓ Build complete.\n");
@@ -149,8 +164,21 @@ export function printMcpClientSetupBanner({ showBuildComplete = true } = {}) {
149
164
  console.log(" Cursor — project .cursor/mcp.json or Settings → MCP → add server:");
150
165
  console.log(JSON.stringify(mcpClientConfigObject(), null, 2));
151
166
  console.log("");
167
+ if (!fromClone) {
168
+ if (isTemporaryInstall()) {
169
+ console.log(" This forgetrail copy is in a temporary pnpm dlx or npx cache, so FORGETRAIL_ROOT is not set.");
170
+ console.log(" forgetrail-mcp finds the forgetrail package it depends on. For a fixed path: pnpm add -g forgetrail, then rerun this command.");
171
+ } else {
172
+ console.log(` FORGETRAIL_ROOT is this installed forgetrail package: ${posixPath(FORGETRAIL_ROOT)}`);
173
+ }
174
+ console.log("");
175
+ }
152
176
  console.log(" Claude Desktop — %APPDATA%\\Claude\\claude_desktop_config.json (same mcpServers block)");
153
- console.log(` Claude Code — claude mcp add forgetrail node ${entry}`);
177
+ console.log(
178
+ fromClone
179
+ ? ` Claude Code — claude mcp add forgetrail node ${posixPath(MCP_ENTRY)}`
180
+ : " Claude Code — claude mcp add forgetrail -- npx -y forgetrail-mcp"
181
+ );
154
182
  console.log("");
155
183
  console.log(" Then reload MCP in Cursor (Settings → MCP) or restart Cursor.");
156
184
  console.log(" Verify: forgetrail mcp ping | Reprint: forgetrail mcp cursor-config");
@@ -8,6 +8,7 @@ import {
8
8
  MCP_SERVER_DIR,
9
9
  analyzeCursorMcpConfig,
10
10
  findCursorMcpJson,
11
+ isClone,
11
12
  staticMcpChecks,
12
13
  printCursorConfigTemplate,
13
14
  runMcpBuild,
@@ -121,6 +122,12 @@ export function runMcpCommand(argv) {
121
122
  return;
122
123
  }
123
124
 
125
+ if (cmd !== "cursor-config" && !isClone()) {
126
+ console.error(`forgetrail mcp ${cmd} runs from a ForgeTrail clone. This npm install does not include mcp-server/.`);
127
+ console.error("Use the published server instead: forgetrail mcp cursor-config prints a config that starts forgetrail-mcp.");
128
+ process.exit(1);
129
+ }
130
+
124
131
  switch (cmd) {
125
132
  case "build":
126
133
  runMcpBuild();
@@ -44,9 +44,34 @@ test("install does not create workflow_tracking.json", () => {
44
44
  assert.equal(result.status, 0, result.stderr || result.stdout);
45
45
  assert.doesNotMatch(result.stdout, /\\workflow_tracking\.json/);
46
46
  assert.match(result.stdout, /Project record: appledger/);
47
+ assert.match(result.stdout, /pnpm dlx appledger init --name/);
48
+ assert.match(result.stdout, /pnpm dlx appledger check/);
47
49
  }
48
50
  });
49
51
 
52
+ test("Lite step 4 runs appledger init and check", () => {
53
+ const lite = readFileSync(join(root, "content", "FORGETRAIL_LITE.md"), "utf8");
54
+ const step = lite.split("\n").find((line) => line.startsWith("4. **Create `appledger/`**"));
55
+ assert.ok(step);
56
+ assert.match(step, /pnpm dlx appledger init --name/);
57
+ assert.match(step, /appledger check/);
58
+ assert.match(step, /examples\/minimal\/appledger/);
59
+ });
60
+
61
+ test("cursor-config from an npm install starts forgetrail-mcp, not a missing dist file", async () => {
62
+ const { mcpClientConfigObject, isTemporaryInstall } = await import("./mcp-lib.mjs");
63
+ const server = mcpClientConfigObject().mcpServers.forgetrail;
64
+ const hasDist = spawnSync(process.execPath, ["-e", "process.exit(require('node:fs').existsSync(process.argv[1]) ? 0 : 1)", join(root, "mcp-server", "dist", "index.js")]).status === 0;
65
+ if (hasDist) {
66
+ assert.equal(server.command, "node");
67
+ } else {
68
+ assert.deepEqual([server.command, ...server.args], ["npx", "-y", "forgetrail-mcp"]);
69
+ }
70
+ assert.equal(isTemporaryInstall("C:/Users/u/AppData/Local/pnpm-cache/dlx/abc/node_modules/forgetrail"), true);
71
+ assert.equal(isTemporaryInstall("/home/u/.npm/_npx/abc/node_modules/forgetrail"), true);
72
+ assert.equal(isTemporaryInstall("C:/Users/u/AppData/Local/pnpm/global/5/node_modules/forgetrail"), false);
73
+ });
74
+
50
75
  test("session start warns on a legacy file and does not quote it as the live phase", () => {
51
76
  const dir = mkdtempSync(join(tmpdir(), "ft-session-"));
52
77
  mkdirSync(join(dir, ".forgetrail"), { recursive: true });
@@ -76,7 +101,7 @@ test("Lite and workflow instructions name the ledger", () => {
76
101
  assert.ok(legacyAt > 0 && resumeAt > legacyAt);
77
102
  const instructional = `${lite.slice(0, legacyAt)}\n${lite.slice(resumeAt)}`;
78
103
  assert.match(lite.slice(legacyAt, resumeAt), /"schemaVersion": "lite-1"/);
79
- assert.match(instructional, /ForgeTrail Lite v2\.2\.0/);
104
+ assert.match(instructional, /ForgeTrail Lite v2\.2\.1/);
80
105
  for (const line of instructional.split("\n")) {
81
106
  if (!line.includes("workflow_tracking.json")) continue;
82
107
  assert.match(line, /[Dd]o not|does not|not the live phase|not recreate/, line);