forgetrail 0.5.5 → 0.5.6
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/CONTINUATION_PROMPT.md +1 -1
- package/README.md +3 -3
- package/TRY_FORGETRAIL.md +2 -2
- package/WORKFLOW.md +6 -6
- package/content/AGENT_INTEGRATION_cursor.md +0 -1
- package/content/AGENT_INTEGRATION_generic.md +1 -1
- package/content/COMPANION_TOOLS.md +2 -2
- package/content/FORGETRAIL_LITE.md +5 -5
- package/content/NEW_PROJECT_BOOTSTRAP.md +4 -4
- package/content/ONE_CLICK_DEV_SETUP.md +1 -1
- package/content/SESSION_RESUME_MCP.md +0 -1
- package/content/SYSTEM_HEALTH_CHECKS.md +1 -1
- package/content/companion-tools.json +5 -0
- package/content/examples/two-session-continuity.md +1 -3
- package/content/hooks/README.md +4 -3
- package/content/hooks/appledger-bin.mjs +33 -0
- package/content/hooks/session-start.mjs +6 -0
- package/content/hooks/validate-tracking.mjs +26 -0
- package/content/skills/forgetrail/SKILL.md +1 -2
- package/docs/NPM.md +3 -3
- package/package.json +1 -1
- package/prompts/propagate-to-forgetrail.md +7 -7
- package/prompts/second-family-critique.md +1 -1
- package/scripts/forgetrail-cli.mjs +1 -1
- package/scripts/install.mjs +4 -3
- package/scripts/tracking-cutover.test.mjs +66 -1
package/CONTINUATION_PROMPT.md
CHANGED
|
@@ -11,7 +11,7 @@ I'm continuing work on [APP NAME]. You are following ForgeTrail, a structured ph
|
|
|
11
11
|
|
|
12
12
|
1. Call ForgeTrail MCP **`getResumeSessionInstructions`** and follow it.
|
|
13
13
|
2. Read **`appledger/profiles/forgetrail.yaml`** and the latest session record. If the phase is **plan**, read **`docs/PHASE_1_BRIEF.md`**. Otherwise read **`CONTEXT_PROMPT.md`** (if a later phase is current but CONTEXT is missing and the brief exists, **merge the brief into CONTEXT** first per the CONTEXT_PROMPT template).
|
|
14
|
-
3. Use **`getPhaseGuidance`** for the current phase.
|
|
14
|
+
3. Use **`getPhaseGuidance`** for the current phase.
|
|
15
15
|
|
|
16
16
|
### Local `_forgetrail/` folder
|
|
17
17
|
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ The shortest supported first task is: create `appledger/`, draft `docs/PHASE_1_B
|
|
|
33
33
|
| Path | Who uses it | What it is |
|
|
34
34
|
| --- | --- | --- |
|
|
35
35
|
| **Lite** | First path | One protocol file. The agent writes `appledger/`. |
|
|
36
|
-
| **CLI** (`forgetrail`) | Node.js 20+ | Installer. Writes Lite and Cursor hooks, or the full template tree.
|
|
36
|
+
| **CLI** (`forgetrail`) | Node.js 20+ | Installer. Writes Lite and Cursor hooks, or the full template tree. Skips files that already exist. Does not run the agent. |
|
|
37
37
|
| **MCP** (`forgetrail-mcp`) | Cursor or Claude | Phase guidance, templates, and lessons search. The ledger still lives in the app repo. |
|
|
38
38
|
|
|
39
39
|
```bash
|
|
@@ -45,9 +45,9 @@ MCP: `npx -y forgetrail-mcp` (0.4.2 or later finds the methodology without `FORG
|
|
|
45
45
|
|
|
46
46
|
## What you get
|
|
47
47
|
|
|
48
|
-
A 7-phase playbook, a ledger in `appledger/`, and templates pre-loaded with first-party production lessons. Each project leaves decisions, lessons, and a session handoff that future work follows. Those lesson notes are not independent adoption evidence.
|
|
48
|
+
A 7-phase playbook, a ledger in `appledger/`, and templates pre-loaded with first-party production lessons. Each project leaves decisions, lessons, and a session handoff that future work follows. Those lesson notes are not independent adoption evidence.
|
|
49
49
|
|
|
50
|
-
Optional hooks in [`content/hooks/`](content/hooks/README.md) load the current phase at session start in Cursor or Claude Code,
|
|
50
|
+
Optional hooks in [`content/hooks/`](content/hooks/README.md) load the current phase at session start in Cursor or Claude Code, check ledger edits, and check for a session note at session stop. The agent still does the writing. Flags, MCP, and the phase table live in the [docs](https://forgetrail.dev/docs).
|
|
51
51
|
|
|
52
52
|
<!-- xfacts-label -->
|
|
53
53
|
|
package/TRY_FORGETRAIL.md
CHANGED
|
@@ -29,14 +29,14 @@ Prove ForgeTrail in one sitting: write a **what, not how** spec in any AI chat,
|
|
|
29
29
|
`pnpm dlx forgetrail install --lite`
|
|
30
30
|
Stub for Genesis too:
|
|
31
31
|
`pnpm dlx forgetrail install --lite --with-genesis-stub`
|
|
32
|
-
The CLI writes the Lite protocol and Cursor hooks.
|
|
32
|
+
The CLI writes the Lite protocol and Cursor hooks. Project state belongs in `appledger/`. It skips files that already exist.
|
|
33
33
|
|
|
34
34
|
5. **Save your spec as `docs/GENESIS.md`**
|
|
35
35
|
Create `docs/` if needed. That path is the canonical handoff for ForgeTrail (not the repo root).
|
|
36
36
|
|
|
37
37
|
6. **Open the folder in your coding agent** and paste this kickoff line:
|
|
38
38
|
|
|
39
|
-
> Follow `.forgetrail/FORGETRAIL_LITE.md` as the project protocol. Treat `docs/GENESIS.md` as the product spec (what, not how). Create `appledger/` (manifest, profile, application record, session record) and draft `docs/PHASE_1_BRIEF.md` from the Genesis file, asking me only about gaps. Do not
|
|
39
|
+
> Follow `.forgetrail/FORGETRAIL_LITE.md` as the project protocol. Treat `docs/GENESIS.md` as the product spec (what, not how). Create `appledger/` (manifest, profile, application record, session record) and draft `docs/PHASE_1_BRIEF.md` from the Genesis file, asking me only about gaps. Do not scaffold application code until I explicitly approve the Phase 1 brief.
|
|
40
40
|
|
|
41
41
|
7. **Approve the Phase 1 brief** before any app scaffold. If the agent starts writing application code early, stop it and paste the kickoff line again.
|
|
42
42
|
|
package/WORKFLOW.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A persistent development system for building software with AI agents. A structured 7-phase workflow for solo developers building non-trivial full-stack apps with coding agents. Derived from 7 sessions and ~78,000 lines of real-world app development.
|
|
6
6
|
|
|
7
|
-
**System of record:** Phase, decisions, lessons, and sessions live in `appledger/` (`profiles/forgetrail.yaml` and records).
|
|
7
|
+
**System of record:** Phase, decisions, lessons, and sessions live in `appledger/` (`profiles/forgetrail.yaml` and records). `.forgetrail/` is hooks and host integration.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -272,7 +272,7 @@ Catalyst Forge siblings (and Cloudflare as a default DNS/hosting suggestion) are
|
|
|
272
272
|
|
|
273
273
|
They are **never required**. Decline is success. Do not dump the shelf at kickoff. Suggest when a trigger is true; persist the outcome on the appledger session as `data.companion_outcomes`.
|
|
274
274
|
|
|
275
|
-
**Subjects:** When an applicable subject exists — an application, a tool server, a skill package, an agent configuration, or a model variant — record a disposition with `appledger subjects`. A family with no subject is `not_applicable`, not a missing label. Do not generate or rewrite a label. A published xFacts label remains an offer when the product goes public or changes hands, and only if the user asks.
|
|
275
|
+
**Subjects:** When an applicable subject exists — an application, a tool server, a skill package, an agent configuration, or a model variant — record a disposition with `appledger subjects`. A family with no subject is `not_applicable`, not a missing label. Do not generate or rewrite a label. A published xFacts label remains an offer when the product goes public or changes hands, and only if the user asks. An [Efficacy](https://efficacy.dev) chain in `.efficacy/` is the same kind of offer when a later agent should record a measured use of that version.
|
|
276
276
|
|
|
277
277
|
**Agents:** `getCompanionSuggestions` (`phase` or `situation`) plus the optional footer on `getPhaseGuidance`. Mapping: `content/COMPANION_TOOLS.md`. Shelf: [catalystforge.com/tools](https://catalystforge.com/tools/).
|
|
278
278
|
|
|
@@ -289,7 +289,7 @@ They are **never required**. Decline is success. Do not dump the shelf at kickof
|
|
|
289
289
|
- Pre-launch newcomer check → Cold-eye
|
|
290
290
|
- Quality / presentation of a tool, site, or page → CraftAssay
|
|
291
291
|
- An applicable subject exists → record a disposition (`appledger subjects`). A missing family stays `not_applicable`. Do not generate a label.
|
|
292
|
-
- Product going public or handed off, and the user asks → offer an xFacts label
|
|
292
|
+
- Product going public or handed off, and the user asks → offer an xFacts label, and an [Efficacy](https://efficacy.dev) chain if a later agent should inspect a measured use
|
|
293
293
|
- Unpushed work you cannot lose → IngotVault
|
|
294
294
|
- Spoken idea capture → DictaWhisper
|
|
295
295
|
|
|
@@ -303,8 +303,8 @@ ForgeTrail includes deterministic host hooks (`.forgetrail/hooks/` with `.cursor
|
|
|
303
303
|
|
|
304
304
|
- **Shell guards:** Runs pre-commit verification (`pnpm run verify`), prevents package manager divergence (e.g. `npm`/`yarn` when `pnpm-lock.yaml` is present), gates `git push` on explicit user approval, and flags destructive operations (`git reset --hard`, `rm -rf`).
|
|
305
305
|
- **Edit guards:** Requires user confirmation before mutating environment secrets (`.env*`) or canonical/completed specs (`specs/completed/**`).
|
|
306
|
-
- **Session start injection:** Points the session at `appledger/` (profile phase and the latest session).
|
|
307
|
-
- **
|
|
306
|
+
- **Session start injection:** Points the session at `appledger/` (profile phase and the latest session).
|
|
307
|
+
- **Ledger check:** After an edit under `appledger/`, runs `appledger check` when the command is on PATH.
|
|
308
308
|
|
|
309
309
|
Where the host supports hooks, tool-level denial and injection take the load off agent context budgets.
|
|
310
310
|
|
|
@@ -567,7 +567,7 @@ Where the host supports hooks, tool-level denial and injection take the load off
|
|
|
567
567
|
- No silent failures in core workflows
|
|
568
568
|
- Docs alignment audit passed (MCP `runAudit({ type: "docs-alignment" })` or `_forgetrail/prompts/docs-alignment-audit.md`)
|
|
569
569
|
|
|
570
|
-
**Optional companions:** Cold-eye for newcomer readiness; CraftAssay for a quality score of the presented work; FilePress + Cloudflare Pages for a Markdown or docs site; IngotVault before a rewrite. If an applicable subject exists, record a disposition; a missing family is `not_applicable`. Offer an xFacts label only when the product goes public or changes hands and the user asks. Do not generate a label. See §1f.
|
|
570
|
+
**Optional companions:** Cold-eye for newcomer readiness; CraftAssay for a quality score of the presented work; FilePress + Cloudflare Pages for a Markdown or docs site; IngotVault before a rewrite. If an applicable subject exists, record a disposition; a missing family is `not_applicable`. Offer an xFacts label only when the product goes public or changes hands and the user asks. Do not generate a label. An Efficacy chain in `.efficacy/` is optional in that same moment. See §1f.
|
|
571
571
|
|
|
572
572
|
---
|
|
573
573
|
|
|
@@ -42,7 +42,6 @@ Use `run_in_background` for long subagents when appropriate.
|
|
|
42
42
|
|
|
43
43
|
After subagent or feature work:
|
|
44
44
|
- Update `appledger/` (criteria, decision records, lessons, the session).
|
|
45
|
-
- Run **`validateTracking`** only when a legacy tracking file is present. A missing file is expected.
|
|
46
45
|
- Update `CONTEXT_PROMPT.md` when architecture or patterns change.
|
|
47
46
|
|
|
48
47
|
## Skills alternative
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ForgeTrail Integration Guide (generic agents)
|
|
2
2
|
|
|
3
|
-
Use this when no agent-specific guide is available. ForgeTrail is **agent-agnostic** — the lifecycle,
|
|
3
|
+
Use this when no agent-specific guide is available. ForgeTrail is **agent-agnostic** — the lifecycle, the ledger, and MCP tools work with any capable coding agent.
|
|
4
4
|
|
|
5
5
|
## Core integration model
|
|
6
6
|
|
|
@@ -17,7 +17,7 @@ Public shelf (current versions and install): [catalystforge.com/tools](https://c
|
|
|
17
17
|
3. FilePress publishes **Markdown**. It does not replace an interactive SvelteKit app.
|
|
18
18
|
4. LocalSlip and LocalHelm are for **two or more** local apps, not a first single project. If they accept LocalSlip, use the recipes below. Do not write `ensure-lease.mjs`.
|
|
19
19
|
5. Practice skills: install the one that matches the current job, not the set.
|
|
20
|
-
6. Offer an xFacts label when a product ships (public URL or handoff). Generate one only if the user accepts. Record the subject disposition in `appledger/` either way.
|
|
20
|
+
6. Offer an xFacts label when a product ships (public URL or handoff). Generate one only if the user accepts. Record the subject disposition in `appledger/` either way. Offer an [Efficacy](https://efficacy.dev) chain in `.efficacy/` when a later agent should record a measured use of that version. The chain is optional, and a passing verify does not make the claim true.
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -77,7 +77,7 @@ Do not migrate a working host the user already chose.
|
|
|
77
77
|
| `hard-to-undo` | Delete data, lock persistence, rewrite git, lock a stack | [TemperPass](https://temperpass.dev) |
|
|
78
78
|
| `never-do` | Destructive action, force-push, or history rewrite | [TemperPass](https://temperpass.dev), [IngotVault](https://ingotvault.dev) |
|
|
79
79
|
| `unclear-cause` | Failure is real; cause is not earned | [Gap Last](https://gaplast.dev) |
|
|
80
|
-
| `ship-label` | Product is going public or being handed off | [xFacts](https://xfacts.dev) (AppFacts and neighbors) |
|
|
80
|
+
| `ship-label` | Product is going public or being handed off | [xFacts](https://xfacts.dev) (AppFacts and neighbors), [Efficacy](https://efficacy.dev) |
|
|
81
81
|
| `git-backup` | New project, or unpushed work you cannot lose; before rebase/rewrite | [IngotVault](https://ingotvault.dev) |
|
|
82
82
|
| `voice-journal` | Builder captures ideas by voice, or wants a local journal | [DictaWhisper](https://dictawhisper.com) |
|
|
83
83
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
A single self-contained file for starting a new project in **any** agent: Cursor, Claude Code, Claude Cowork, OpenAI Codex, Cline, Aider, Continue, Windsurf, etc. **No MCP server, no vendored methodology tree, no external fetches.** Drop this file into the repo (or paste it into chat), and the agent has enough structure to run a real project end to end.
|
|
10
10
|
|
|
11
|
-
**System of record:** Phase, decisions, lessons, and sessions live in `appledger/` (`profiles/forgetrail.yaml` and records).
|
|
11
|
+
**System of record:** Phase, decisions, lessons, and sessions live in `appledger/` (`profiles/forgetrail.yaml` and records). `.forgetrail/` is the protocol, rules, and hooks.
|
|
12
12
|
|
|
13
13
|
> **Maintainers:** Optional onboarding blocks in **§4.3**, **§4.4**, and **§7.1** are intentionally duplicated in root **`README.md`** and **`WORKFLOW.md`**. When you edit one, sync the others (see **`update-log.md`** — FORGETRAIL_LITE release checklist, item 3).
|
|
14
14
|
|
|
@@ -49,7 +49,7 @@ Any of the three works. A + C together is best. For a written pre-Phase-1 spec,
|
|
|
49
49
|
|
|
50
50
|
ForgeTrail agent artifacts (protocol, tracking, platform rules) live in **`.forgetrail/`** at the repo root — **whether you bootstrap via ForgeTrail Lite file copy or MCP greenfield.**
|
|
51
51
|
|
|
52
|
-
**Upstream ForgeTrail is open source** (Apache 2.0). In your app repo, **`.forgetrail/`** holds the protocol, rules, and hooks. Project state lives in **`appledger/`**. **
|
|
52
|
+
**Upstream ForgeTrail is open source** (Apache 2.0). In your app repo, **`.forgetrail/`** holds the protocol, rules, and hooks. Project state lives in **`appledger/`**. **Lite file bootstrap** may copy `FORGETRAIL_LITE.md` here; you may **commit** `.forgetrail/` under the same license or **gitignore** it to keep the public repo focused on app code and to avoid duplicating a large protocol when MCP already serves updates. Never commit **secrets** (`.env`, API keys) inside the ledger or rules.
|
|
53
53
|
|
|
54
54
|
```
|
|
55
55
|
.forgetrail/
|
|
@@ -101,7 +101,7 @@ When a boot surfaces a gap in **ForgeTrail Lite itself** (not a one-off app bug)
|
|
|
101
101
|
|
|
102
102
|
**Optional companions:** when a job matches (Markdown site, two or more local apps, local Ollama, copy review), you may offer a sibling from the Catalyst Forge shelf. Never required. Do not list them in the first message to the human. MCP: `getCompanionSuggestions`. Full mapping lives with ForgeTrail, not in this file.
|
|
103
103
|
|
|
104
|
-
**Subjects:** When the project has an application, a tool server, a skill package, an agent configuration, or a model variant, record a disposition with `appledger subjects`. A family with no subject is `not_applicable`, not a missing label. Do not generate or publish a label unless the user asks. Offering an xFacts label when the product goes public or changes hands stays optional.
|
|
104
|
+
**Subjects:** When the project has an application, a tool server, a skill package, an agent configuration, or a model variant, record a disposition with `appledger subjects`. A family with no subject is `not_applicable`, not a missing label. Do not generate or publish a label unless the user asks. Offering an xFacts label when the product goes public or changes hands stays optional. An [Efficacy](https://efficacy.dev) chain in `.efficacy/` is the same kind of offer when a later agent should record a measured use of that version. The chain is not the project record.
|
|
105
105
|
|
|
106
106
|
**Named ports (if they accept):** [LocalSlip](https://localslip.dev). FilePress: lease name = site `package.json` `name`. `localslip claim NAME --port N && filepress dev`. Do not pass `--port`. Vite: `localslip get` in `vite.config`, `strictPort`. Claim once. Do not write `ensure-lease.mjs`. Do not add the `localslip` package just to read a port.
|
|
107
107
|
|
|
@@ -161,7 +161,7 @@ Every project flows through these phases. The agent **pauses at every phase tran
|
|
|
161
161
|
|
|
162
162
|
When archetype ≠ `product`, **prune** the non-applicable criteria in the profile once (and record that pruning as a decision) instead of annotating them "N/A" forever. If the project outgrows its archetype (a one-shot grows accounts), flag it and propose re-promoting to `product`.
|
|
163
163
|
|
|
164
|
-
**Wrap (when the project ends):** Finishing a project includes **harvesting** it. When the app ships, is delivered, or is intentionally shelved: sweep lesson and decision records for lessons that generalize beyond this app (framework traps, CLI changes, integration surprises), record them in `FORGETRAIL_LITE_UPDATES.md` (§1.6) or propagate to the upstream ForgeTrail repo if you have one, set `project_status` to `wrapped`, and add a final session record with the end state (deploy URL, handoff notes). Small projects often surface the freshest tooling lessons — do not let them die in the repo. Optional: Cold-eye for a newcomer-readiness pass. A public xFacts label is still optional and only when the user asks. The subject disposition from the **Subjects** note above is already recorded.
|
|
164
|
+
**Wrap (when the project ends):** Finishing a project includes **harvesting** it. When the app ships, is delivered, or is intentionally shelved: sweep lesson and decision records for lessons that generalize beyond this app (framework traps, CLI changes, integration surprises), record them in `FORGETRAIL_LITE_UPDATES.md` (§1.6) or propagate to the upstream ForgeTrail repo if you have one, set `project_status` to `wrapped`, and add a final session record with the end state (deploy URL, handoff notes). Small projects often surface the freshest tooling lessons — do not let them die in the repo. Optional: Cold-eye for a newcomer-readiness pass. A public xFacts label is still optional and only when the user asks. An Efficacy chain is the same kind of offer. The subject disposition from the **Subjects** note above is already recorded.
|
|
165
165
|
|
|
166
166
|
### 3.1 Feature specs (Phase 4+)
|
|
167
167
|
|
|
@@ -469,7 +469,7 @@ Output requirements
|
|
|
469
469
|
|-----------|----------------|
|
|
470
470
|
| **`status.bat`** / **`status.sh`** / **`pnpm run forgetrail:status`** | Anyone — prints phase name, open exit criteria, last session; refreshes **`docs/FORGETRAIL_PROGRESS.md`** |
|
|
471
471
|
| **`docs/FORGETRAIL_PROGRESS.md`** | Plain-language snapshot (template: upstream **`FORGETRAIL_PROGRESS.md`**) |
|
|
472
|
-
| **`.cursor/rules/forgetrail-phase-status.mdc`** | Cursor agent footers from
|
|
472
|
+
| **`.cursor/rules/forgetrail-phase-status.mdc`** | Cursor agent footers from `appledger/profiles/forgetrail.yaml` |
|
|
473
473
|
| **Ask the agent** | *"What's our ForgeTrail phase and what's next?"* — it should read tracking first |
|
|
474
474
|
|
|
475
475
|
**Agent:** After locking a phase or completing exit criteria, update tracking **and** either refresh **`docs/FORGETRAIL_PROGRESS.md`** or remind the user to run **status.bat**. On phase transitions, pause for explicit approval (§8 rule 1) — **status** output should not replace that conversation.
|
|
@@ -62,7 +62,7 @@ Call **`getProgressiveDocSchedule`** for the canonical phase → doc matrix (WOR
|
|
|
62
62
|
3. Call **`getProgressiveDocSchedule`** and keep it in mind for every phase transition.
|
|
63
63
|
4. Call **`getChecklist`** with section `before-session-1` — complete those items with the user (problem statement, stack, assets, hero flow).
|
|
64
64
|
5. Call **`getGreenfieldIntakePrompt`** — product/delivery questions: exports (PDF / DOCX / PPTX, etc.), tenancy (e.g. consultants × clients), hybrid vs full spec, compliance tier (even if “none yet”), hero flow, and registrar/DNS/git/hosting if still open. Capture answers in **`PHASE_1_BRIEF.md`** and as decision records. If using native plan mode, include these questions in the plan context (`getPlanModePatterns`). When a companion trigger is true later, call **`getCompanionSuggestions`**. Do not name companions in the first user-facing message.
|
|
65
|
-
6. Call **`getTrackingSchema`** — you will maintain **`appledger/`**.
|
|
65
|
+
6. Call **`getTrackingSchema`** — you will maintain **`appledger/`**. Optionally call **`getAgentIntegrationGuide`** for your host (`grok`, `cursor`, `claude`, `generic`) and **`getForgeTrailSkill`** if the agent supports persistent skills.
|
|
66
66
|
7. Call **`getPhaseGuidance`** with phase `1` (architecture). Summarize understanding and propose structure, data model, integrations, and v1 scope **before** writing app code.
|
|
67
67
|
8. During Phase 1, create **`docs/PHASE_1_BRIEF.md`** from **`getTemplate({ name: "PHASE_1_BRIEF" })`**, fill every section, and **lock** it; mirror major decisions as **appledger decision records**.
|
|
68
68
|
9. After architecture is confirmed and the brief is locked, call **`getPhaseGuidance`** with phase `2` (scaffolding). Read the brief and **`appledger/profiles/forgetrail.yaml`**, **merge the brief into `CONTEXT_PROMPT.md`**, then execute a **single-pass app skeleton** and the rest of the Phase 2 doc set (`README`, `TODO`, `.forgetrail/IDEAS.md`).
|
|
@@ -76,7 +76,7 @@ Call **`getProgressiveDocSchedule`** for the canonical phase → doc matrix (WOR
|
|
|
76
76
|
| **Pre-Phase-1 build spec (external LLM chat)** | **`getGenesisSpecPrompt`** → user saves **`docs/GENESIS.md`**; or human recipe **`TRY_FORGETRAIL.md`** (no MCP) |
|
|
77
77
|
| **Feature delivery SPEC template (Phase 4+)** | **`getTemplate({ name: "SPEC_FEATURE_TEMPLATE" })`** → write `specs/[feature].md`; lifecycle in WORKFLOW Phase 4 |
|
|
78
78
|
| **Approved Genesis / plan → brief + decisions** | **`ingestPlanArtifact`** — after plan approval or when `docs/GENESIS.md` exists |
|
|
79
|
-
| **One-call greenfield setup** (bootstrap +
|
|
79
|
+
| **One-call greenfield setup** (bootstrap + ledger + post-bootstrap guidance + optional Cursor rules) | **`getNewProjectKickoff`** — prefer over calling the granular tools separately |
|
|
80
80
|
| **Which docs in which phase** | **`getProgressiveDocSchedule`** (WORKFLOW §1a) |
|
|
81
81
|
| Phase playbooks, entry/exit criteria, patterns | `getPhaseGuidance` (phases 1–7 or keywords like `scaffolding`, `hardening`) |
|
|
82
82
|
| Milestone checklists | `getChecklist` (`before-session-1`, `session-1`, `session-2`, `full`, …) |
|
|
@@ -89,7 +89,7 @@ Call **`getProgressiveDocSchedule`** for the canonical phase → doc matrix (WOR
|
|
|
89
89
|
| **Native plan mode as Phase 1** | **`getPlanModePatterns`** — use before scaffolding when the host supports plan-before-code |
|
|
90
90
|
| **Agent-specific integration** (Grok, Cursor, Claude) | **`getAgentIntegrationGuide`** — primitive mappings and session openers |
|
|
91
91
|
| **Installable forgetrail skill** (Grok etc.) | **`getForgeTrailSkill`** — copy to host skill directory |
|
|
92
|
-
| **
|
|
92
|
+
| **Ledger check** | **`validateTracking`** — a missing file is expected |
|
|
93
93
|
| **Optional companion tools** (FilePress, LocalSlip, skills, xFacts, …) | **`getCompanionSuggestions`** — `phase` or `situation`; never required; not in the first user-facing message (WORKFLOW §1f) |
|
|
94
94
|
| **Parallel subagent recommendations** | **`suggestSubagentDecomposition`** — before spawning audits/research (WORKFLOW §1c) |
|
|
95
95
|
| **Ledger initialization** for a greenfield repo | `getInitialWorkflowTracking` — does **not** return JSON. Create **`appledger/`** |
|
|
@@ -140,7 +140,7 @@ Call **`getProgressiveDocSchedule`** for the canonical phase → doc matrix (WOR
|
|
|
140
140
|
|
|
141
141
|
- At **each session start**, read **`appledger/profiles/forgetrail.yaml`**, the latest session record, and `CONTEXT_PROMPT.md` (if present). Use **`getPhaseGuidance`** for the current phase.
|
|
142
142
|
- When exit criteria for a phase appear satisfied, **state that explicitly** and **wait for user confirmation** before treating the next phase as active; change `current_phase_instance` only after approval.
|
|
143
|
-
- After substantive work, update **`appledger/`** (criteria, decision records, lessons, the session).
|
|
143
|
+
- After substantive work, update **`appledger/`** (criteria, decision records, lessons, the session).
|
|
144
144
|
- If a problem does not converge after **~5 turns**, propose a **different approach**, not more patches.
|
|
145
145
|
- **When the project ends** (shipped, delivered, shelved), run the **wrap protocol** (WORKFLOW §1e): sweep lesson and decision records for generalizable lessons, run the propagation prompt in **Harvest mode**, set **`project_status`** to **`wrapped`** on the profile, and add a final session record with end state and handoff pointers.
|
|
146
146
|
- **Git commits:** `git commit -F <file>` or plain `-m` at natural stopping points with concise summaries. Run verification checks prior to commit.
|
|
@@ -137,6 +137,6 @@ if errorlevel 1 pause
|
|
|
137
137
|
See **FORGETRAIL_LITE.md** §4.2.2 and **`SCAFFOLD_INSTALL.json`** (`versionPolicy`). Install scripts read `POCKETBASE_VERSION` from `.env`:
|
|
138
138
|
|
|
139
139
|
- unset or `latest` → resolve from GitHub **releases/latest** at setup time
|
|
140
|
-
- `0.26.2` (example) → pin that release; record
|
|
140
|
+
- `0.26.2` (example) → pin that release; record it as an appledger decision record when the user confirms a good boot
|
|
141
141
|
|
|
142
142
|
Never ship a stale semver only in methodology docs without an env override path.
|
|
@@ -10,7 +10,6 @@ The user is **continuing** a project that uses ForgeTrail via the **MCP server**
|
|
|
10
10
|
2. If the current phase is **`plan`**, read **`docs/PHASE_1_BRIEF.md`** and continue planning toward a locked brief. Otherwise read **`CONTEXT_PROMPT.md`**. If a later phase is current but CONTEXT is missing and **`PHASE_1_BRIEF.md`** exists, **merge the brief into CONTEXT** first (see CONTEXT_PROMPT template).
|
|
11
11
|
3. Call **`getPhaseGuidance`** for that phase (`plan` through `harden`, or `1`–`7`). When a companion trigger is true, call **`getCompanionSuggestions`** for that phase or situation. Do not install unless the user asked.
|
|
12
12
|
4. If you need checklist context, call **`getChecklist`** (e.g. `every-session` or `full`).
|
|
13
|
-
5. If a **`workflow_tracking.json`** file exists and is not a pointer, do not update it. Run **`appledger migrate preview`**, then apply. Call **`validateTracking`** only to classify that file.
|
|
14
13
|
|
|
15
14
|
Do **not** require `_forgetrail/WORKFLOW.md` or `_forgetrail/TRACKING_SCHEMA.md` on disk — use the MCP tools above.
|
|
16
15
|
|
|
@@ -69,7 +69,7 @@ OLLAMA_MODEL=ibm/granite4.1:8b
|
|
|
69
69
|
# SKIP_OLLAMA_INSTALL=1 # skip entire setup
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
Pin **`OLLAMA_MODEL`** after a successful **test-ollama** run
|
|
72
|
+
Pin **`OLLAMA_MODEL`** after a successful **test-ollama** run, and record that pin as an appledger decision record.
|
|
73
73
|
|
|
74
74
|
---
|
|
75
75
|
|
|
@@ -204,6 +204,11 @@
|
|
|
204
204
|
"name": "xFacts",
|
|
205
205
|
"homepage": "https://xfacts.dev",
|
|
206
206
|
"offer": "When the product is public or handed off, offer an xFacts label (AppFacts and neighbors). Record the subject disposition either way, and bind an existing label with appledger bind. A validator checks shape, not truth."
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"name": "Efficacy",
|
|
210
|
+
"homepage": "https://efficacy.dev",
|
|
211
|
+
"offer": "When a later agent should inspect a measured use of this exact version, offer an Efficacy chain in .efficacy/. The chain is optional. Verify shows the record is intact and bound to its evidence. It does not show the claim is true."
|
|
207
212
|
}
|
|
208
213
|
]
|
|
209
214
|
},
|
|
@@ -19,7 +19,7 @@ The human pasted the kickoff line from [TRY_FORGETRAIL.md](../../TRY_FORGETRAIL.
|
|
|
19
19
|
3. Recorded one decision and one lesson.
|
|
20
20
|
4. Stopped after the human approved the brief. No application scaffold yet.
|
|
21
21
|
|
|
22
|
-
The CLI, if used instead of a hand copy, writes the Lite file, hook scripts, and an optional Genesis stub. It does not
|
|
22
|
+
The CLI, if used instead of a hand copy, writes the Lite file, hook scripts, and an optional Genesis stub. It does not fill in the phase, decisions, or session. Those writes depend on the agent following the protocol.
|
|
23
23
|
|
|
24
24
|
### What was left unfinished
|
|
25
25
|
|
|
@@ -67,8 +67,6 @@ That is the trail: a phase, a decision, a lesson, and a next step. The next chat
|
|
|
67
67
|
|
|
68
68
|
MCP tools can hand the agent the same protocol and a lessons search. They do not replace the files in the app repo.
|
|
69
69
|
|
|
70
|
-
An existing writable `.forgetrail/workflow_tracking.json` is legacy. `appledger migrate preview` writes nothing. `apply` imports decisions, sessions, resolved gotchas as lessons, unresolved gotchas as open questions, and `IDEAS.md` / `BUGS.md` from the repository root and from `.forgetrail/`, then replaces the file with a pointer. The `appledger` package is not a published npm release. Use the [repository](https://github.com/Catalyst-Forge-LLC/appledger).
|
|
71
|
-
|
|
72
70
|
## Catalog excerpt
|
|
73
71
|
|
|
74
72
|
Keep project decisions, development state, and lessons in the repository so the next session can continue. After one sitting you should see `appledger/` with a phase, a decision, and a session next step. Full walk-through: this file, and the [continuity](https://forgetrail.dev/docs/continuity) page. The live site still shows the previous pages until it is redeployed.
|
package/content/hooks/README.md
CHANGED
|
@@ -6,10 +6,11 @@ Enforces ForgeTrail rules and guards at the host tool level, rather than relying
|
|
|
6
6
|
|
|
7
7
|
- `guard-shell.mjs`: runs pre-commit verification (`pnpm run verify`), prevents npm/yarn when `pnpm-lock.yaml` is present, allows `ingotvault` (asks before `--force-with-lease`), asks before any `git push`, and prompts on destructive git or filesystem operations.
|
|
8
8
|
- `guard-edit.mjs`: guards `.env*` secrets files and `specs/completed/**` or `specs/canonical/**` records against accidental mutation.
|
|
9
|
-
- `session-start.mjs`: on session start, points the session at `appledger/`.
|
|
10
|
-
- `
|
|
9
|
+
- `session-start.mjs`: on session start, points the session at `appledger/`. When `appledger` is on PATH it appends `appledger orient --budget 300`.
|
|
10
|
+
- `appledger-bin.mjs`: finds the `appledger` command. A missing command is not a failure.
|
|
11
|
+
- `validate-tracking.mjs`: after an edit under `appledger/`, runs `appledger check` when the command is on PATH and reports warnings.
|
|
11
12
|
- `validate-tracking-core.mjs`: standalone zero-dependency tracking validator.
|
|
12
|
-
- `session-stop.mjs`: when a turn ends, reminds the agent to update the appledger session record if project files changed after that record was last written. It stays quiet on follow-up turns, on read-only turns, and when only `appledger/`, `.forgetrail/`, `.cursor/`, or `.claude/` changed.
|
|
13
|
+
- `session-stop.mjs`: when a turn ends, reminds the agent to update the appledger session record if project files changed after that record was last written. It stays quiet on follow-up turns, on read-only turns, and when only `appledger/`, `.forgetrail/`, `.cursor/`, or `.claude/` changed.
|
|
13
14
|
- `cursor-hooks.json`: standard Cursor hooks configuration.
|
|
14
15
|
- `claude-settings-hooks.json`: standard Claude Code configuration fragment.
|
|
15
16
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find and run the appledger CLI from PATH.
|
|
3
|
+
* A missing command is absent, not a failure. Hooks keep their previous text in that case.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
export function findAppledger() {
|
|
9
|
+
const finder = process.platform === "win32" ? "where.exe" : "which";
|
|
10
|
+
const found = spawnSync(finder, ["appledger"], { encoding: "utf8", windowsHide: true });
|
|
11
|
+
if (found.status !== 0) return null;
|
|
12
|
+
const line = found.stdout
|
|
13
|
+
.split(/\r?\n/)
|
|
14
|
+
.map((item) => item.trim())
|
|
15
|
+
.find(Boolean);
|
|
16
|
+
return line || null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function runAppledger(args, cwd) {
|
|
20
|
+
const bin = findAppledger();
|
|
21
|
+
if (!bin) return { absent: true, status: null, text: "" };
|
|
22
|
+
const script = /\.(cmd|bat)$/i.test(bin);
|
|
23
|
+
const result = spawnSync(bin, args, {
|
|
24
|
+
cwd,
|
|
25
|
+
encoding: "utf8",
|
|
26
|
+
timeout: 20_000,
|
|
27
|
+
windowsHide: true,
|
|
28
|
+
shell: script,
|
|
29
|
+
});
|
|
30
|
+
if (result.error?.code === "ENOENT") return { absent: true, status: null, text: "" };
|
|
31
|
+
const text = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
32
|
+
return { absent: false, status: result.status, text };
|
|
33
|
+
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
10
|
import { join, resolve } from "node:path";
|
|
11
|
+
import { runAppledger } from "./appledger-bin.mjs";
|
|
11
12
|
|
|
12
13
|
function walkUp(startDir, found) {
|
|
13
14
|
let curr = resolve(startDir || process.cwd());
|
|
@@ -54,6 +55,11 @@ function main() {
|
|
|
54
55
|
lines.push("Project record: appledger/");
|
|
55
56
|
lines.push("Read appledger/profiles/forgetrail.yaml for the current phase.");
|
|
56
57
|
lines.push("Read the latest session record for left_off and next_steps.");
|
|
58
|
+
const orient = runAppledger(["orient", "--budget", "300"], ledgerRoot);
|
|
59
|
+
if (!orient.absent && orient.text) {
|
|
60
|
+
lines.push("");
|
|
61
|
+
lines.push(orient.text);
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
if (trackingPath) {
|
|
@@ -7,7 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { readFileSync, existsSync } from "node:fs";
|
|
10
|
+
import { resolve } from "node:path";
|
|
10
11
|
import { validateTrackingData, formatValidationResult } from "./validate-tracking-core.mjs";
|
|
12
|
+
import { runAppledger } from "./appledger-bin.mjs";
|
|
13
|
+
|
|
14
|
+
function ledgerRoot(filePath) {
|
|
15
|
+
if (!filePath) return null;
|
|
16
|
+
const abs = resolve(filePath).replaceAll("\\", "/");
|
|
17
|
+
const at = abs.toLowerCase().lastIndexOf("/appledger/");
|
|
18
|
+
if (at === -1) return null;
|
|
19
|
+
return abs.slice(0, at);
|
|
20
|
+
}
|
|
11
21
|
|
|
12
22
|
function readStdin() {
|
|
13
23
|
try {
|
|
@@ -27,6 +37,22 @@ function main() {
|
|
|
27
37
|
payload.tool_input?.path ||
|
|
28
38
|
"";
|
|
29
39
|
|
|
40
|
+
const ledger = ledgerRoot(filePath);
|
|
41
|
+
if (ledger) {
|
|
42
|
+
const check = runAppledger(["check", "--root", ledger], ledger);
|
|
43
|
+
const noisy = !check.absent && (check.status !== 0 || /warning|error/i.test(check.text));
|
|
44
|
+
if (noisy && check.text) {
|
|
45
|
+
console.log(
|
|
46
|
+
JSON.stringify({
|
|
47
|
+
additional_context: `=== ForgeTrail ledger check ===\n${check.text}\n================================`,
|
|
48
|
+
})
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
console.log(JSON.stringify({}));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
30
56
|
if (!filePath.endsWith("workflow_tracking.json")) {
|
|
31
57
|
console.log(JSON.stringify({}));
|
|
32
58
|
return;
|
|
@@ -28,7 +28,6 @@ You are operating under the ForgeTrail methodology. Your primary job is to give
|
|
|
28
28
|
- Read `CONTEXT_PROMPT.md` and `TODO.md` if they exist.
|
|
29
29
|
- Call `getPhaseGuidance` for the current phase if needed.
|
|
30
30
|
- Summarize current phase, pending criteria, and recent decisions to the user briefly.
|
|
31
|
-
- If `workflow_tracking.json` exists and is not a pointer, do not edit it. Run `appledger migrate preview`, then apply.
|
|
32
31
|
|
|
33
32
|
3. **Pause at phase transitions**:
|
|
34
33
|
- When you believe exit criteria for the current phase are met, explicitly tell the user: "I think we have completed Phase X because [reasons]. The remaining exit criteria are [list]. Ready to move to Phase Y?"
|
|
@@ -87,7 +86,7 @@ Call `getResumeSessionInstructions` (or read `appledger/profiles/forgetrail.yaml
|
|
|
87
86
|
- `getTemplate({name: "..."})` — for PHASE_1_BRIEF, CONTEXT_PROMPT, audits, etc. Use mode "shell" for clean structure.
|
|
88
87
|
- `runAudit`, `searchLessons`, `getAntiPatterns`
|
|
89
88
|
- `suggestSubagentDecomposition` (when subagents available)
|
|
90
|
-
- `validateTracking` (
|
|
89
|
+
- `validateTracking` (a missing file is expected)
|
|
91
90
|
- `ingestPlanArtifact` (after native plan mode approval — map plan → PHASE_1_BRIEF + decision records)
|
|
92
91
|
- `todo_write` — mirror open exit criteria and next actions.
|
|
93
92
|
|
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.
|
|
14
|
-
| [`forgetrail-mcp`](https://www.npmjs.com/package/forgetrail-mcp) | 0.4.3 | 0.4.
|
|
13
|
+
| [`forgetrail`](https://www.npmjs.com/package/forgetrail) | 0.5.5 | 0.5.5 | repo root | CLI + Lite + templates. `pnpm dlx forgetrail install --lite` |
|
|
14
|
+
| [`forgetrail-mcp`](https://www.npmjs.com/package/forgetrail-mcp) | 0.4.3 | 0.4.3 | `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
|
-
`forgetrail@0.5.
|
|
18
|
+
`forgetrail@0.5.5` and `forgetrail-mcp@0.4.3` are on npm and match these `package.json` versions as of 2026-09-29. A later content change needs a version bump before it publishes. `getCompanionSuggestions` reads its text from the installed `forgetrail`. `pnpm run pack:check` is the gate. It does not publish.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
package/package.json
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Run this prompt after implementing a new feature, pattern, plan, or significant enhancement in your app. It generalizes **both** durable **feature shapes** (what to document in **`TECHNICAL_REFERENCE.md`**, **`TEST_PLAN.md`**, brand/design templates) **and** reusable **lessons** (callouts in templates), then updates ForgeTrail so future projects start with that guidance.
|
|
4
4
|
|
|
5
|
-
**Any ForgeTrail project is a valid source** — not just the flagship app that seeded these templates. A weekend one-shot with two
|
|
5
|
+
**Any ForgeTrail project is a valid source** — not just the flagship app that seeded these templates. A weekend one-shot with two lessons in its ledger propagates the same way a mature SaaS does; small projects often exercise the newest tool versions and surface the freshest scaffolding lessons. If your project has only a handful of docs (Lite bootstrap, `one-shot` archetype), skip the doc-inventory ceremony and use **Harvest mode** below.
|
|
6
6
|
|
|
7
7
|
### Harvest mode (small projects and project wrap)
|
|
8
8
|
|
|
9
|
-
Use this when the source project is **small** (no product journal, minimal doc set) or you are running the **wrap protocol** (WORKFLOW.md §1e) at project end. The primary discovery source is the **
|
|
9
|
+
Use this when the source project is **small** (no product journal, minimal doc set) or you are running the **wrap protocol** (WORKFLOW.md §1e) at project end. The primary discovery source is the **ledger**, not the doc tree:
|
|
10
10
|
|
|
11
|
-
1. **Read
|
|
11
|
+
1. **Read appledger decision records and lesson records**, plus `CONTEXT_PROMPT.md`'s gotcha/pattern sections and any `FORGETRAIL_LITE_UPDATES.md`.
|
|
12
12
|
2. **Classify each entry:** *generalizable* (framework traps, CLI behavior changes, scaffolding surprises, integration lessons — anything a different project on the same stack could hit) vs *app-specific* (content decisions, domain rules). Only the first group propagates.
|
|
13
|
-
3. **For each generalizable entry**, run the normal Step 2 dedupe (grep ForgeTrail for existing coverage) and Step 3 mapping (which template gets it).
|
|
13
|
+
3. **For each generalizable entry**, run the normal Step 2 dedupe (grep ForgeTrail for existing coverage) and Step 3 mapping (which template gets it). Ledger lessons usually land as **pattern memory** (`CONTEXT_PROMPT.md` callouts, `FORGETRAIL_LITE.md` scaffolding notes); occasionally a decision reveals a **feature shape** worth a stub.
|
|
14
14
|
4. **Zero-yield is fine.** If nothing generalizes, say so and skip the update-log entry — do not pad.
|
|
15
15
|
|
|
16
16
|
Harvest mode replaces the Discovery scan and Journal-driven sections for these projects; everything from Step 2 onward applies unchanged.
|
|
@@ -44,7 +44,7 @@ When you run a **periodic** propagation (catch-up after a sprint, or anytime **A
|
|
|
44
44
|
|
|
45
45
|
## Context
|
|
46
46
|
|
|
47
|
-
**Your app** is the live project. Its docs are the source of truth — **whichever of these exist**. A full Phase-7 product will have most of them; a Lite or `one-shot` project may have only `CONTEXT_PROMPT.md`, `README.md`, `TODO.md`, and
|
|
47
|
+
**Your app** is the live project. Its docs are the source of truth — **whichever of these exist**. A full Phase-7 product will have most of them; a Lite or `one-shot` project may have only `CONTEXT_PROMPT.md`, `README.md`, `TODO.md`, and `appledger/` (use **Harvest mode** above in that case). Treat this list as a menu, not a requirement:
|
|
48
48
|
|
|
49
49
|
- `CONTEXT_PROMPT.md`
|
|
50
50
|
- `docs/PHASE_1_BRIEF.md` (if you improved the Phase 1 handoff template)
|
|
@@ -91,7 +91,7 @@ Run after meaningful implementation work **and** after substantive **documentati
|
|
|
91
91
|
| **Isolated service health checks / local Ollama** (test PB without app; install Ollama + VRAM model + completion test; avoid thinking models by default) | **`SYSTEM_HEALTH_CHECKS.md`**, **`FORGETRAIL_LITE.md`** §4.7–§4.8; **`scripts/test-pocketbase.mjs`**, **`scripts/setup-ollama.mjs`**, **`scripts/test-ollama.mjs`**, **`SCAFFOLD_INSTALL.json`** `systemHealthChecks` |
|
|
92
92
|
| **URL / listing import pipeline** (fetch + HTML parse, refresh-from-source, optional LLM-assisted recover when selectors drift) | `docs/TECHNICAL_REFERENCE.md` (*URL import* — paywalls, **markup drift / optional recover**); `docs/CONTEXT_PROMPT.md`; `docs/TEST_PLAN.md` §2a; **`content/FORGETRAIL_LITE.md` §7.2**; partial spec stub under **`specs/partial/`** when shipped behavior needs follow-up. |
|
|
93
93
|
| **A week+ of shipping without running this prompt** | Use **Journal-driven propagation**: sweep **`docs/PRODUCT_JOURNAL.md`** (e.g. last 10–14 days) so **Added** / **Improved** items get **`TECHNICAL_REFERENCE` / `TEST_PLAN`** stubs, not only **CONTEXT_PROMPT** lessons. |
|
|
94
|
-
| **Project wrap — the source project is finished, delivered, or shelved** | Run **Harvest mode** (top of this prompt) as part of the wrap protocol (**WORKFLOW.md §1e**): sweep
|
|
94
|
+
| **Project wrap — the source project is finished, delivered, or shelved** | Run **Harvest mode** (top of this prompt) as part of the wrap protocol (**WORKFLOW.md §1e**): sweep appledger lesson records and decision records before the project goes quiet. Small projects count. |
|
|
95
95
|
| **CI/CD, Node/`engines`, or package-manager pins changed** | Keep workflow, container, and `package.json` in sync — lessons for **DEPLOYMENT.md**, **TECHNICAL_REFERENCE.md**, **CONTEXT_PROMPT.md**. |
|
|
96
96
|
| **Deploy scripts, systemd units, or process stop/restart behavior** | `TimeoutStopSec`, blue-green `systemctl stop`, and graceful-shutdown tradeoffs affect **wall-clock deploy time** as well as request safety — **DEPLOYMENT.md** (and **CONTEXT_PROMPT** if it changes operator expectations). |
|
|
97
97
|
| **New scripts, hooks, or dev-tooling** | Journal/lint/build wrappers → **CONTEXT_PROMPT** (tooling) or **TECHNICAL_REFERENCE** (pipelines). |
|
|
@@ -109,7 +109,7 @@ Do **not** rely only on the immediate trigger. Skim **multiple signal sources**
|
|
|
109
109
|
|
|
110
110
|
| Source | What to extract |
|
|
111
111
|
|--------|-----------------|
|
|
112
|
-
|
|
|
112
|
+
| **`appledger/` decision and lesson records** | Framework traps, CLI/scaffolding surprises, and integration lessons logged during the build — the primary source for small projects (see **Harvest mode**), and an easy-to-miss one for large projects where docs lag the ledger. |
|
|
113
113
|
| **`git log` / recent commits** | Subjects and paths; cluster related work; compare to the last `update-log.md` propagation date. |
|
|
114
114
|
| **`docs/PRODUCT_JOURNAL.md`** (or git-derived changelog) | Day-level themes across UX, infra, and docs. Map **`Added`** / major **`Improved`** items to Step 3: new **feature-area** stubs in **`TECHNICAL_REFERENCE.md`**, **`TEST_PLAN.md`** checks, **`BRAND_AND_PRODUCT.md`** / **`DESIGN_SYSTEM.md`** when IA or positioning changes—not only **`CONTEXT_PROMPT.md`** bullets. |
|
|
115
115
|
| **Recently touched `specs/`** | Durable architecture and copy decisions, including WIP specs. |
|
|
@@ -40,4 +40,4 @@ When the second model returns its review:
|
|
|
40
40
|
|
|
41
41
|
1. **Verify observations against codebase reality:** Not all critiques apply if the opposing model lacked local file context.
|
|
42
42
|
2. **Update the spec:** Add newly discovered edge cases to the Edge Cases section; tighten acceptance criteria.
|
|
43
|
-
3. **Log architectural pivots:** If a critique exposes an unviable path,
|
|
43
|
+
3. **Log architectural pivots:** If a critique exposes an unviable path, record the alternative as an appledger decision record.
|
|
@@ -37,7 +37,7 @@ Install options:
|
|
|
37
37
|
--with-genesis-stub With --lite: also create docs/GENESIS.md stub
|
|
38
38
|
--force, -f Overwrite existing files
|
|
39
39
|
--dry-run Preview without writing
|
|
40
|
-
--skip-tracking Accepted and ignored.
|
|
40
|
+
--skip-tracking Accepted and ignored.
|
|
41
41
|
--path, -p <dir> Install elsewhere (default: current directory)
|
|
42
42
|
--help, -h Show help
|
|
43
43
|
--version, -v Print the forgetrail version
|
package/scripts/install.mjs
CHANGED
|
@@ -38,6 +38,7 @@ const HOOK_FILES = [
|
|
|
38
38
|
"guard-shell.mjs",
|
|
39
39
|
"guard-edit.mjs",
|
|
40
40
|
"session-start.mjs",
|
|
41
|
+
"appledger-bin.mjs",
|
|
41
42
|
"validate-tracking.mjs",
|
|
42
43
|
"validate-tracking-core.mjs",
|
|
43
44
|
"session-stop.mjs",
|
|
@@ -142,7 +143,7 @@ export function runInstallLite(rawArgv, { defaultToCwd = false } = {}) {
|
|
|
142
143
|
|
|
143
144
|
console.log("\nDone.");
|
|
144
145
|
console.log(" Protocol: .forgetrail/FORGETRAIL_LITE.md");
|
|
145
|
-
console.log(" Project record: appledger/
|
|
146
|
+
console.log(" Project record: appledger/");
|
|
146
147
|
console.log(" Hooks: .forgetrail/hooks/ (enforced via .cursor/hooks.json)");
|
|
147
148
|
if (args.withGenesisStub) {
|
|
148
149
|
console.log(" Genesis: docs/GENESIS.md (stub — replace with your spec)");
|
|
@@ -168,7 +169,7 @@ Usage:
|
|
|
168
169
|
Options:
|
|
169
170
|
--path, -p <dir> Target project root (default: current directory for \`forgetrail\` CLI)
|
|
170
171
|
--force, -f Overwrite existing files
|
|
171
|
-
--skip-tracking Accepted and ignored.
|
|
172
|
+
--skip-tracking Accepted and ignored.
|
|
172
173
|
--dry-run Print actions only
|
|
173
174
|
|
|
174
175
|
Installs:
|
|
@@ -186,7 +187,7 @@ Usage:
|
|
|
186
187
|
Options:
|
|
187
188
|
--path, -p <dir> Target project root (default: current directory for \`forgetrail\` CLI)
|
|
188
189
|
--force, -f Overwrite existing files
|
|
189
|
-
--skip-tracking Accepted and ignored.
|
|
190
|
+
--skip-tracking Accepted and ignored.
|
|
190
191
|
--with-genesis-stub Also create docs/GENESIS.md stub (for the Try path)
|
|
191
192
|
--dry-run Print actions only
|
|
192
193
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import { mkdtempSync, readFileSync, writeFileSync, mkdirSync, utimesSync } from "node:fs";
|
|
2
|
+
import { mkdtempSync, readFileSync, writeFileSync, mkdirSync, utimesSync, chmodSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -94,6 +94,70 @@ test("session start warns on a legacy file and does not quote it as the live pha
|
|
|
94
94
|
assert.doesNotMatch(payload.additional_context, /Current Phase: 4-feature-iteration/);
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
function stubAppledger(dir, line) {
|
|
98
|
+
const stub = join(dir, "bin");
|
|
99
|
+
mkdirSync(stub, { recursive: true });
|
|
100
|
+
if (process.platform === "win32") {
|
|
101
|
+
writeFileSync(join(stub, "appledger.cmd"), `@echo off\r\necho ${line}\r\n`);
|
|
102
|
+
} else {
|
|
103
|
+
const file = join(stub, "appledger");
|
|
104
|
+
writeFileSync(file, `#!/bin/sh\necho ${line}\n`);
|
|
105
|
+
chmodSync(file, 0o755);
|
|
106
|
+
}
|
|
107
|
+
const system = process.env.SystemRoot ? `${process.env.SystemRoot}\\System32` : "/usr/bin";
|
|
108
|
+
const sep = process.platform === "win32" ? ";" : ":";
|
|
109
|
+
return { PATH: [stub, system, process.env.PATH].filter(Boolean).join(sep) };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function runHook(script, dir, { input, env } = {}) {
|
|
113
|
+
return spawnSync(process.execPath, [join(root, "content", "hooks", script)], {
|
|
114
|
+
cwd: dir,
|
|
115
|
+
input,
|
|
116
|
+
encoding: "utf8",
|
|
117
|
+
env: env ? { ...process.env, ...env } : process.env,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
test("session start includes orient when appledger is on PATH", () => {
|
|
122
|
+
const dir = mkdtempSync(join(tmpdir(), "ft-orient-"));
|
|
123
|
+
mkdirSync(join(dir, "appledger"), { recursive: true });
|
|
124
|
+
writeFileSync(join(dir, "appledger", "manifest.yaml"), "format: appledger\n");
|
|
125
|
+
const result = runHook("session-start.mjs", dir, { env: stubAppledger(dir, "STUB-ORIENT") });
|
|
126
|
+
assert.equal(result.status, 0, result.stderr);
|
|
127
|
+
assert.match(JSON.parse(result.stdout).additional_context, /STUB-ORIENT/);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("session start keeps the ledger text when appledger is absent", () => {
|
|
131
|
+
const dir = mkdtempSync(join(tmpdir(), "ft-noap-"));
|
|
132
|
+
mkdirSync(join(dir, "appledger"), { recursive: true });
|
|
133
|
+
writeFileSync(join(dir, "appledger", "manifest.yaml"), "format: appledger\n");
|
|
134
|
+
const system = process.env.SystemRoot ? `${process.env.SystemRoot}\\System32` : "/usr/bin";
|
|
135
|
+
const result = runHook("session-start.mjs", dir, { env: { PATH: system } });
|
|
136
|
+
assert.equal(result.status, 0, result.stderr);
|
|
137
|
+
const text = JSON.parse(result.stdout).additional_context;
|
|
138
|
+
assert.match(text, /Project record: appledger/);
|
|
139
|
+
assert.doesNotMatch(text, /STUB-ORIENT/);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("an edit under appledger/ runs check and reports a warning", () => {
|
|
143
|
+
const dir = mkdtempSync(join(tmpdir(), "ft-check-"));
|
|
144
|
+
mkdirSync(join(dir, "appledger"), { recursive: true });
|
|
145
|
+
const manifest = join(dir, "appledger", "manifest.yaml");
|
|
146
|
+
writeFileSync(manifest, "format: appledger\n");
|
|
147
|
+
const warned = runHook("validate-tracking.mjs", dir, {
|
|
148
|
+
input: JSON.stringify({ path: manifest }),
|
|
149
|
+
env: stubAppledger(dir, "warning missing_source example"),
|
|
150
|
+
});
|
|
151
|
+
assert.equal(warned.status, 0, warned.stderr);
|
|
152
|
+
assert.match(JSON.parse(warned.stdout).additional_context, /warning missing_source example/);
|
|
153
|
+
const clean = runHook("validate-tracking.mjs", dir, {
|
|
154
|
+
input: JSON.stringify({ path: manifest }),
|
|
155
|
+
env: stubAppledger(join(dir, "clean"), "ok ledger"),
|
|
156
|
+
});
|
|
157
|
+
assert.equal(clean.status, 0, clean.stderr);
|
|
158
|
+
assert.deepEqual(JSON.parse(clean.stdout), {});
|
|
159
|
+
});
|
|
160
|
+
|
|
97
161
|
test("Lite and workflow instructions name the ledger", () => {
|
|
98
162
|
const lite = readFileSync(join(root, "content", "FORGETRAIL_LITE.md"), "utf8");
|
|
99
163
|
const legacyAt = lite.indexOf("## 11. Legacy");
|
|
@@ -180,6 +244,7 @@ test("session stop reminds only after work newer than the session record", () =>
|
|
|
180
244
|
|
|
181
245
|
test("kickoff names appledger init and does not require the tracking file", () => {
|
|
182
246
|
const kickoff = readFileSync(join(root, "mcp-server", "src", "index.ts"), "utf8");
|
|
247
|
+
assert.match(kickoff, /z\.union\(\[z\.string\(\), z\.number\(\)\]\)/);
|
|
183
248
|
assert.match(kickoff, /appledger init/);
|
|
184
249
|
assert.doesNotMatch(kickoff, /no separate init command/);
|
|
185
250
|
const plan = readFileSync(join(root, "content", "PLAN_MODE_PATTERNS.md"), "utf8");
|