liteagents 2.24.1 → 3.5.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.
- package/CHANGELOG.md +206 -0
- package/README.md +120 -160
- package/installer/cli.js +40 -5
- package/installer/installation-engine.js +8 -0
- package/package.json +4 -3
- package/packages/ampcode/AGENT.md +11 -20
- package/packages/ampcode/agents/code-developer.md +11 -17
- package/packages/ampcode/agents/orchestrator.md +3 -3
- package/packages/ampcode/agents/quality-assurance.md +3 -1
- package/packages/ampcode/{commands/brainstorming.md → skills/brainstorming/SKILL.md} +2 -3
- package/packages/ampcode/{commands/branch-review.md → skills/branch-review/SKILL.md} +13 -13
- package/packages/{claude/commands/docs-builder.md → ampcode/skills/docs-builder/SKILL.md} +1 -1
- package/packages/ampcode/{commands/live-canvas.md → skills/live-canvas/SKILL.md} +8 -4
- package/packages/ampcode/{commands/refactor.md → skills/refactor/SKILL.md} +57 -9
- package/packages/ampcode/{commands/release.md → skills/release/SKILL.md} +4 -4
- package/packages/{claude/commands → ampcode/skills}/remember/AGENT_RULES.md +44 -84
- package/packages/ampcode/{commands/remember.md → skills/remember/SKILL.md} +86 -13
- package/packages/ampcode/{commands → skills}/remember/friction.cjs +0 -0
- package/packages/ampcode/skills/remember/stub-check.cjs +206 -0
- package/packages/ampcode/skills/remember/sync-rules.cjs +178 -0
- package/packages/ampcode/skills/remember/version-check.cjs +214 -0
- package/packages/ampcode/skills/root-cause/SKILL.md +220 -0
- package/packages/ampcode/{commands/trace-back → skills/root-cause}/find-polluter.sh +0 -0
- package/packages/{claude/commands/security.md → ampcode/skills/security/SKILL.md} +1 -1
- package/packages/{claude/commands/ship.md → ampcode/skills/ship/SKILL.md} +1 -1
- package/packages/ampcode/skills/skill-creator/LICENSE.txt +202 -0
- package/packages/ampcode/{commands/skill-creator.md → skills/skill-creator/SKILL.md} +1 -2
- package/packages/ampcode/{commands → skills}/skill-creator/scripts/init_skill.py +0 -0
- package/packages/ampcode/{commands → skills}/skill-creator/scripts/package_skill.py +0 -0
- package/packages/ampcode/{commands → skills}/skill-creator/scripts/quick_validate.py +0 -0
- package/packages/ampcode/{commands/stash.md → skills/stash/SKILL.md} +2 -1
- package/packages/{claude/commands/test-generate.md → ampcode/skills/test-generate/SKILL.md} +2 -2
- package/packages/ampcode/variants.json +2 -2
- package/packages/claude/CLAUDE.md +11 -19
- package/packages/claude/agents/code-developer.md +11 -17
- package/packages/claude/agents/orchestrator.md +4 -5
- package/packages/claude/agents/quality-assurance.md +3 -1
- package/packages/claude/skills/brainstorming/SKILL.md +1 -2
- package/packages/claude/{commands/branch-review.md → skills/branch-review/SKILL.md} +1 -1
- package/packages/{ampcode/commands/docs-builder.md → claude/skills/docs-builder/SKILL.md} +7 -7
- package/packages/claude/skills/live-canvas/SKILL.md +5 -1
- package/packages/claude/{commands/refactor.md → skills/refactor/SKILL.md} +53 -5
- package/packages/claude/{commands/release.md → skills/release/SKILL.md} +1 -1
- package/packages/{ampcode/commands → claude/skills}/remember/AGENT_RULES.md +38 -78
- package/packages/claude/{commands/remember.md → skills/remember/SKILL.md} +86 -13
- package/packages/claude/{commands → skills}/remember/friction.cjs +0 -0
- package/packages/claude/skills/remember/stub-check.cjs +206 -0
- package/packages/claude/skills/remember/sync-rules.cjs +178 -0
- package/packages/claude/skills/remember/version-check.cjs +214 -0
- package/packages/claude/skills/root-cause/SKILL.md +220 -0
- package/packages/{ampcode/commands/security.md → claude/skills/security/SKILL.md} +2 -2
- package/packages/{ampcode/commands/ship.md → claude/skills/ship/SKILL.md} +2 -2
- package/packages/claude/skills/skill-creator/SKILL.md +1 -2
- package/packages/claude/{commands/stash.md → skills/stash/SKILL.md} +2 -1
- package/packages/{ampcode/commands/test-generate.md → claude/skills/test-generate/SKILL.md} +3 -3
- package/packages/claude/variants.json +1 -2
- package/packages/droid/AGENTS.md +10 -16
- package/packages/droid/commands/brainstorming.md +1 -4
- package/packages/droid/commands/branch-review.md +11 -14
- package/packages/droid/commands/docs-builder.md +0 -3
- package/packages/droid/commands/live-canvas.md +7 -5
- package/packages/droid/commands/refactor.md +55 -10
- package/packages/droid/commands/release.md +2 -5
- package/packages/droid/commands/remember/AGENT_RULES.md +38 -78
- package/packages/droid/commands/remember/stub-check.cjs +206 -0
- package/packages/droid/commands/remember/sync-rules.cjs +178 -0
- package/packages/droid/commands/remember/version-check.cjs +214 -0
- package/packages/droid/commands/remember.md +84 -14
- package/packages/droid/commands/root-cause.md +218 -0
- package/packages/droid/commands/security.md +0 -3
- package/packages/droid/commands/ship.md +0 -3
- package/packages/droid/commands/skill-creator/LICENSE.txt +202 -0
- package/packages/droid/commands/skill-creator.md +0 -4
- package/packages/droid/commands/stash.md +0 -2
- package/packages/droid/commands/test-generate.md +1 -4
- package/packages/droid/droids/1-create-prd.md +6 -2
- package/packages/droid/droids/2-generate-tasks.md +1 -2
- package/packages/droid/droids/3-process-task-list.md +1 -2
- package/packages/droid/droids/code-developer.md +12 -19
- package/packages/droid/droids/feature-planner.md +1 -2
- package/packages/droid/droids/market-researcher.md +1 -2
- package/packages/droid/droids/orchestrator.md +3 -4
- package/packages/droid/droids/quality-assurance.md +4 -3
- package/packages/droid/droids/system-architect.md +1 -2
- package/packages/droid/droids/ui-designer.md +1 -2
- package/packages/opencode/AGENTS.md +10 -16
- package/packages/opencode/agent/code-developer.md +11 -17
- package/packages/opencode/agent/orchestrator.md +2 -2
- package/packages/opencode/agent/quality-assurance.md +3 -1
- package/packages/opencode/command/brainstorming.md +1 -4
- package/packages/opencode/command/branch-review.md +11 -15
- package/packages/opencode/command/docs-builder.md +0 -4
- package/packages/opencode/command/live-canvas.md +7 -5
- package/packages/opencode/command/refactor.md +55 -11
- package/packages/opencode/command/release.md +2 -5
- package/packages/opencode/command/remember/AGENT_RULES.md +38 -78
- package/packages/opencode/command/remember/stub-check.cjs +206 -0
- package/packages/opencode/command/remember/sync-rules.cjs +178 -0
- package/packages/opencode/command/remember/version-check.cjs +214 -0
- package/packages/opencode/command/remember.md +84 -14
- package/packages/opencode/command/root-cause.md +218 -0
- package/packages/opencode/command/security.md +0 -4
- package/packages/opencode/command/ship.md +0 -3
- package/packages/opencode/command/skill-creator/LICENSE.txt +202 -0
- package/packages/opencode/command/skill-creator.md +0 -4
- package/packages/opencode/command/stash.md +0 -3
- package/packages/opencode/command/test-generate.md +1 -5
- package/packages/opencode/opencode.jsonc +4 -34
- package/packages/subagentic-manual.md +147 -314
- package/packages/ampcode/agents/context-builder.md +0 -144
- package/packages/ampcode/commands/debug-method.md +0 -297
- package/packages/ampcode/commands/live-canvas/README.md +0 -264
- package/packages/ampcode/commands/optimize.md +0 -61
- package/packages/ampcode/commands/tdd-flow.md +0 -390
- package/packages/ampcode/commands/test-traps/example.ts +0 -158
- package/packages/ampcode/commands/test-traps.md +0 -378
- package/packages/ampcode/commands/trace-back.md +0 -176
- package/packages/ampcode/commands/verify-done.md +0 -152
- package/packages/claude/agents/context-builder.md +0 -145
- package/packages/claude/commands/optimize.md +0 -61
- package/packages/claude/plugins/live-canvas-marketplace/plugins/live-canvas-channel/README.md +0 -89
- package/packages/claude/skills/debug-method/CREATION-LOG.md +0 -119
- package/packages/claude/skills/debug-method/SKILL.md +0 -296
- package/packages/claude/skills/debug-method/test-academic.md +0 -14
- package/packages/claude/skills/debug-method/test-pressure-1.md +0 -58
- package/packages/claude/skills/debug-method/test-pressure-2.md +0 -68
- package/packages/claude/skills/debug-method/test-pressure-3.md +0 -69
- package/packages/claude/skills/live-canvas/README.md +0 -269
- package/packages/claude/skills/tdd-flow/SKILL.md +0 -392
- package/packages/claude/skills/test-traps/SKILL.md +0 -378
- package/packages/claude/skills/test-traps/example.ts +0 -158
- package/packages/claude/skills/trace-back/SKILL.md +0 -176
- package/packages/claude/skills/verify-done/SKILL.md +0 -152
- package/packages/droid/commands/debug-method.md +0 -297
- package/packages/droid/commands/live-canvas/README.md +0 -264
- package/packages/droid/commands/optimize.md +0 -61
- package/packages/droid/commands/tdd-flow.md +0 -390
- package/packages/droid/commands/test-traps/example.ts +0 -158
- package/packages/droid/commands/test-traps.md +0 -378
- package/packages/droid/commands/trace-back.md +0 -176
- package/packages/droid/commands/verify-done.md +0 -152
- package/packages/droid/droids/context-builder.md +0 -144
- package/packages/opencode/agent/context-builder.md +0 -148
- package/packages/opencode/command/debug-method.md +0 -297
- package/packages/opencode/command/live-canvas/README.md +0 -264
- package/packages/opencode/command/optimize.md +0 -61
- package/packages/opencode/command/tdd-flow.md +0 -390
- package/packages/opencode/command/test-traps/example.ts +0 -158
- package/packages/opencode/command/test-traps.md +0 -378
- package/packages/opencode/command/trace-back.md +0 -176
- package/packages/opencode/command/verify-done.md +0 -152
- /package/packages/ampcode/{commands → skills}/docs-builder/docs-builder.cjs +0 -0
- /package/packages/ampcode/{commands → skills}/live-canvas/DESIGN_PRINCIPLES.md +0 -0
- /package/packages/ampcode/{commands → skills}/live-canvas/dev/post-variants.html +0 -0
- /package/packages/ampcode/{commands → skills}/live-canvas/templates/lab-banner.html +0 -0
- /package/packages/ampcode/{commands → skills}/live-canvas/templates/overlay-vanilla.js +0 -0
- /package/packages/claude/{commands → skills}/docs-builder/docs-builder.cjs +0 -0
- /package/packages/claude/skills/{trace-back → root-cause}/find-polluter.sh +0 -0
- /package/packages/droid/commands/{trace-back → root-cause}/find-polluter.sh +0 -0
- /package/packages/opencode/command/{trace-back → root-cause}/find-polluter.sh +0 -0
|
@@ -130,90 +130,50 @@ A problem you see and don't fix goes in the report, never in a comment. Comments
|
|
|
130
130
|
|
|
131
131
|
## Testing Standards
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
### When to
|
|
144
|
-
|
|
145
|
-
- **After the design stabilizes, not during exploration.** Do not
|
|
146
|
-
- **
|
|
147
|
-
- **Write tests for bugs.** Every
|
|
148
|
-
- **Write tests before refactoring.**
|
|
149
|
-
- **
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
- **
|
|
155
|
-
- **
|
|
156
|
-
- **
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
-
|
|
162
|
-
|
|
163
|
-
- **
|
|
164
|
-
- **
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
- **
|
|
169
|
-
- **
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
- **
|
|
177
|
-
- **Separate by type:**
|
|
178
|
-
```
|
|
179
|
-
packages/<pkg>/tests/
|
|
180
|
-
unit/ # Fast, isolated, mocked deps, <1s each
|
|
181
|
-
integration/ # Real DB, filesystem, multi-component, <10s each
|
|
182
|
-
e2e/ # Full workflows, subprocess calls, <60s each
|
|
183
|
-
conftest.py # Shared fixtures for this package
|
|
184
|
-
```
|
|
185
|
-
- **One test file per module** (not per function). `test_auth.py` tests the auth module, not `test_login.py` + `test_logout.py` + `test_session.py`
|
|
186
|
-
- **No duplicate test files.** Before creating a new test file, check if one already exists for that module
|
|
187
|
-
|
|
188
|
-
### Markers and Signals
|
|
189
|
-
|
|
190
|
-
| Marker | Purpose | CI Behavior |
|
|
191
|
-
|--------|---------|-------------|
|
|
192
|
-
| `@pytest.mark.slow` | Runtime > 5s | Run in full suite, skip in quick checks |
|
|
193
|
-
| `@pytest.mark.ml` | Requires ML deps (torch, etc.) | Skip if deps not installed |
|
|
194
|
-
| `@pytest.mark.real_api` | Calls external APIs | Skip in CI — run manually before release |
|
|
195
|
-
|
|
196
|
-
**CI runs for fast signals:**
|
|
197
|
-
- `pytest -m "not slow and not ml and not real_api"` — fast gate on every push (~30s)
|
|
198
|
-
- `pytest` — full suite on PR merge or nightly
|
|
199
|
-
- Package-level runs for targeted debugging: `pytest packages/core/tests/`
|
|
200
|
-
|
|
201
|
-
### Coverage and Ratios
|
|
202
|
-
|
|
203
|
-
- **Do not chase a coverage number.** 80% coverage with meaningless tests is worse than 40% with behavior-testing integration tests
|
|
204
|
-
- **Cover the critical path first.** Data layer, auth, payment, core business logic — before helper utilities
|
|
205
|
-
- **Coverage tells you what's NOT tested, not what IS tested.** High coverage with bad assertions is false confidence
|
|
206
|
-
- **Delete tests that don't catch bugs.** If a test has never failed (or only fails on refactors), it's not providing value
|
|
207
|
-
|
|
208
|
-
**Target ratio:** ~20% unit, ~60% integration, ~15% E2E, ~5% manual/exploratory
|
|
209
|
-
|
|
210
|
-
### Test Tooling Standards
|
|
211
|
-
|
|
212
|
-
- Use `tmp_path` for filesystem tests, `:memory:` or `tmp_path` SQLite for DB tests
|
|
213
|
-
- Use dependency injection over `@patch` — it's more readable and survives refactors
|
|
214
|
-
- Tests must be self-sufficient — no dependency on project directories, user config, or environment state
|
|
215
|
-
- Use factories or builders for test data, not raw constructors with 15 arguments
|
|
216
|
-
- Keep test fixtures close to where they're used. Shared fixtures in `conftest.py`, not a global test utilities package
|
|
133
|
+
Principles, not a framework. Whatever the language, follow its ecosystem's conventions for
|
|
134
|
+
runner, layout and fixtures — these rules govern what a test must *do*, never how a
|
|
135
|
+
particular toolchain spells it.
|
|
136
|
+
|
|
137
|
+
### What a test is for
|
|
138
|
+
|
|
139
|
+
**Test behavior, not implementation.** A suite must give you confidence to refactor freely. If changing internal code without changing behavior breaks tests, those tests are liabilities, not assets.
|
|
140
|
+
|
|
141
|
+
**Shape — the Testing Trophy, not the Pyramid:** static analysis catches the cheapest bugs; few unit tests, for pure logic and algorithms; many integration tests, the sweet spot, real components working together; some end-to-end tests over the critical journeys. Target roughly 20% unit, 60% integration, 15% E2E, 5% manual.
|
|
142
|
+
|
|
143
|
+
### When to write them
|
|
144
|
+
|
|
145
|
+
- **After the design stabilizes, not during exploration.** Do not test a prototype — you will write tests for code you delete tomorrow. First make it work (POC), then make it right (tests), then make it fast
|
|
146
|
+
- **Tests first when you already know the contract.** Pure functions, algorithms, parsers, validators, data transformations — write the test, watch it fail, then implement. When you are still discovering the interface, that same discipline produces churn and false confidence
|
|
147
|
+
- **Write tests for bugs.** Every fix ships a regression test that fails before the fix and passes after — the highest-value test there is
|
|
148
|
+
- **Write tests before refactoring.** Characterization tests lock in current behavior first, then change the code
|
|
149
|
+
- **Write tests when the code has users.** Called by other modules or exposed externally means it needs tests; a helper serving one caller does not need its own file
|
|
150
|
+
- **Do not test glue code.** Something that only wires A to B to C is covered at the integration level
|
|
151
|
+
|
|
152
|
+
### What makes a good test
|
|
153
|
+
|
|
154
|
+
- **Tests real behavior.** Call the public interface, assert on observable output. Never reach into internals
|
|
155
|
+
- **Fails for the right reason.** It breaks when the feature breaks, not when the implementation moves
|
|
156
|
+
- **Reads like a spec.** Someone new to the code should learn what the feature does by reading it
|
|
157
|
+
- **Self-contained.** Sets up its own state, runs, cleans up. No ordering dependencies, and no reliance on project directories, user config, or ambient environment
|
|
158
|
+
- **Deterministic.** Flaky tests erode trust. A dependency on timing, network, or global state is a defect in the test
|
|
159
|
+
- **Never sleep for a condition — poll for it.** Sleeping then asserting is wrong at every value: too short and it flakes under load, too long and the suite drags, and a real async bug looks identical to a guess that was too short. Wait on the condition itself, re-reading the state *inside* the loop, with a timeout that names what it was waiting for. A fixed delay is only correct once you have waited for the triggering condition, the delay comes from a documented interval rather than a guess, and a comment says why
|
|
160
|
+
|
|
161
|
+
### Anti-patterns
|
|
162
|
+
|
|
163
|
+
- **Mocking most of the test.** If mock setup outweighs the logic, you are testing mocks. Prefer the real thing against a temporary directory, an in-memory store, or a disposable container
|
|
164
|
+
- **Partial mocks.** Mirror the complete structure the real thing returns, not only the fields this test reads. A mock missing a field downstream code consumes passes here and fails in production
|
|
165
|
+
- **Smoke tests.** Asserting a result merely exists proves nothing. Assert on specific values, structure, or side effects
|
|
166
|
+
- **Testing private internals.** If it needs its own test, it should be part of the public interface; otherwise the public tests should reach it
|
|
167
|
+
- **Mirroring implementation.** A test that restates the source line by line breaks on every refactor and catches nothing
|
|
168
|
+
- **Test-only production code.** Never add a method, flag, or branch to production solely for tests. Inject the dependency instead
|
|
169
|
+
- **Chasing a coverage number.** 80% of meaningless tests is worse than 40% of behavioural ones. Coverage tells you what is *not* tested, never that what is covered is correct. Cover the critical path first — data, auth, money, core logic — before helpers
|
|
170
|
+
|
|
171
|
+
### Organization
|
|
172
|
+
|
|
173
|
+
- **Mirror the source structure**, at whatever level the ecosystem puts tests. One test file per module, not per function, and never a second file covering a module that already has one
|
|
174
|
+
- **Separate by cost so CI gets a fast signal.** Keep quick isolated tests apart from ones needing real IO or a full workflow, and let the slow ones — long runtimes, heavy optional dependencies, live external APIs — be excluded from the gate that runs on every push and included in the full run
|
|
175
|
+
- **Fixtures live near what uses them**, shared upward only when genuinely shared. Build test data with factories or builders, never a constructor taking fifteen positional arguments
|
|
176
|
+
- **Delete tests that never catch anything.** A test that has only ever failed during refactors is a maintenance cost, not a safety net
|
|
217
177
|
|
|
218
178
|
---
|
|
219
179
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: remember
|
|
3
3
|
description: Consolidate stashes + friction into project memory
|
|
4
|
-
|
|
4
|
+
allowed-tools: Read, Grep, Glob
|
|
5
|
+
disable-model-invocation: true
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
Run friction analysis, then consolidate session stashes + friction antigens into a single project-local MEMORY.md, and inject into AGENT.md. Friction runs automatically (best-effort) — there is no separate `/friction` command. A docs reconcile check runs at the end, detect-only.
|
|
@@ -38,10 +39,31 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
38
39
|
- **Locate `friction.cjs`** — it is bundled next to this command at `remember/friction.cjs`
|
|
39
40
|
(the same directory as `remember.md`, whether installed or run from the package). If it
|
|
40
41
|
exists nowhere, skip to step 1 (stash-only) and tell the user friction.cjs is missing.
|
|
42
|
+
- **Check for a newer liteagents** (best-effort, one line, never blocking) — bundled
|
|
43
|
+
beside `friction.cjs` as `remember/version-check.cjs`. Call it by its **absolute
|
|
44
|
+
path**, exactly as step 7 calls `docs-builder.cjs`: the cwd here is the target repo,
|
|
45
|
+
not this package, so a cwd-relative path fails everywhere except the liteagents repo
|
|
46
|
+
itself.
|
|
47
|
+
```bash
|
|
48
|
+
node ~/.config/amp/skills/remember/version-check.cjs
|
|
49
|
+
```
|
|
50
|
+
**If that path does not exist, use the directory you just resolved for
|
|
51
|
+
`friction.cjs`** — the two ship side by side, so that directory is correct for a
|
|
52
|
+
non-default install and when running from a checkout, where the path above would
|
|
53
|
+
point at the installed copy instead of the one under test.
|
|
54
|
+
It prints one advice line if the installed version is behind the registry, and prints
|
|
55
|
+
nothing otherwise. It exits 0 on every path, caches the registry answer for 24h, and
|
|
56
|
+
is bounded to ~2s, so it cannot stall this run. If it prints a line, relay it verbatim
|
|
57
|
+
in your final report; never act on it and never run the install yourself.
|
|
58
|
+
- **If the script is missing from both locations, say so** — one line, same rule as step
|
|
59
|
+
7's "applicable but could not run". A failed *check* (offline, registry down, timeout)
|
|
60
|
+
stays silent by design: it is a once-a-day nudge, not a result anyone is waiting on. A
|
|
61
|
+
missing *script* means the install is incomplete, which is worth a word.
|
|
41
62
|
- **Resolve the global sessions root** — probe this list top-to-bottom, use the first that
|
|
42
63
|
exists and contains `.jsonl` files directly, or one level down in per-project
|
|
43
64
|
subdirectories (friction.cjs scans exactly those two levels, not a deep recursive walk).
|
|
44
65
|
**Never prompt the user.**
|
|
66
|
+
<!-- mirror:literal:start — every tool's real path, identical in all four kits -->
|
|
45
67
|
```
|
|
46
68
|
# ── Add your own global sessions root at the TOP so it is checked first ──
|
|
47
69
|
~/.claude/projects/ # Claude Code
|
|
@@ -51,6 +73,7 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
51
73
|
~/.codex/sessions/ # Codex CLI (use $CODEX_HOME/sessions/ if set)
|
|
52
74
|
~/.gemini/antigravity-cli/brain/ # Antigravity
|
|
53
75
|
```
|
|
76
|
+
<!-- mirror:literal:end -->
|
|
54
77
|
> Note: `friction.cjs` parses Claude Code's session schema. The Codex/Antigravity roots
|
|
55
78
|
> will resolve but yield no signals until friction learns their formats — open an issue
|
|
56
79
|
> to request one: https://github.com/hamr0/liteagents/issues
|
|
@@ -72,11 +95,26 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
72
95
|
fresh output). **Move only those pipeline files** — anything else in `.amp/memory/`
|
|
73
96
|
(e.g. user-owned rule files) stays where it is. Remove the old dirs only if empty, update the managed MEMORY section in AGENT.md to
|
|
74
97
|
the new reference (step 5), and tell the user exactly what moved.
|
|
75
|
-
- **
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
98
|
+
- **Sync `AGENT_RULES.md` from the installed template** — run the bundled script, which
|
|
99
|
+
does the whole decision itself. Call it by **absolute path**, for the same reason as
|
|
100
|
+
`version-check.cjs` in step 0: the cwd is the target repo, not this package.
|
|
101
|
+
```bash
|
|
102
|
+
node ~/.config/amp/skills/remember/sync-rules.cjs
|
|
103
|
+
```
|
|
104
|
+
It compares `.amp/remember/AGENT_RULES.md` against the template shipped beside it
|
|
105
|
+
and takes one of three actions: **absent** — copies it in; **identical** — does
|
|
106
|
+
nothing at all, no write and no output; **differs** — moves the old body to
|
|
107
|
+
`AGENT_RULES.md.bak` and copies the new one in, reporting both. Relay whatever it
|
|
108
|
+
prints in the step-8 report; it is silent when nothing changed.
|
|
109
|
+
|
|
110
|
+
**This replaced a bootstrap-once rule that never refreshed**, which left a measured 35
|
|
111
|
+
repos many releases behind. The rules doc is a shipped standards document, so it is
|
|
112
|
+
kept current rather than frozen on first write — nothing is destroyed, because a
|
|
113
|
+
differing body is always preserved in the backup first.
|
|
114
|
+
|
|
115
|
+
The comparison is a byte compare done *by the script*, never by you: a model-performed
|
|
116
|
+
copy can re-wrap a line or drop a trailing newline, and the file would then differ
|
|
117
|
+
forever, backing up on every single run.
|
|
80
118
|
- Read all `.amp/stash/*.md` files in the current project
|
|
81
119
|
- Read friction output written in step 0: `.amp/remember/friction/antigen_clusters.json` (preferred) or `.amp/remember/friction/antigen_review.md` (fallback). On the fallback path, step 4c does NO counting — merge quotes into
|
|
82
120
|
matching entries only; never change `sessions`, `last_seen`, or `recurred_while_hot` (the
|
|
@@ -88,7 +126,11 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
88
126
|
length-gate debt on `.amp/remember/MEMORY.md`. Steps 4-5 (friction → ledger count →
|
|
89
127
|
Antigens render) are stash-independent and still run whenever friction produced output
|
|
90
128
|
(see step 4's own guard). If there is also no friction
|
|
91
|
-
output, report "nothing to consolidate" and stop after step 1
|
|
129
|
+
output, report "nothing to consolidate" and stop after step 1 — **but run
|
|
130
|
+
step 5's `stub-check.cjs` before you stop.** The stub shape does not depend on
|
|
131
|
+
there being anything to consolidate, and skipping it on quiet runs is exactly
|
|
132
|
+
how a repo with nothing to remember stays broken forever. `sync-rules.cjs`
|
|
133
|
+
already ran above, for the same reason.
|
|
92
134
|
|
|
93
135
|
2. **Extract from unprocessed stashes** (up to 5 stashes per agent, as few agents as possible — see Guardrails)
|
|
94
136
|
- Each agent reads its batch of stashes together and calls the mid-tier model (see Guardrails) to extract:
|
|
@@ -387,11 +429,32 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
387
429
|
Users trim this section deliberately (a pointer-only variant is common), and rewriting
|
|
388
430
|
it silently re-adds text they removed, on every single run, forever. Observed in the
|
|
389
431
|
field: a run restored the inline rules into a AGENT.md whose owner had cut them, and
|
|
390
|
-
the edit had to be reverted by hand.
|
|
391
|
-
handled
|
|
432
|
+
the edit had to be reverted by hand. Note this no longer matches how `AGENT_RULES.md`
|
|
433
|
+
itself is handled: `sync-rules.cjs` refreshes that file every run, because it is a
|
|
434
|
+
shipped standards document with a backup behind it. This section is prose the user
|
|
435
|
+
owns, with nothing behind it — so it stays bootstrap-once.
|
|
392
436
|
- If an existing pair is present but its **path pointer** is missing or wrong, that is
|
|
393
437
|
load-bearing: **report it and stop**, do not silently rewrite the section around it.
|
|
394
438
|
|
|
439
|
+
- **Then assert the stub SHAPE mechanically** — run the bundled script by **absolute
|
|
440
|
+
path**, for the same reason as steps 0 and 1:
|
|
441
|
+
```bash
|
|
442
|
+
node ~/.config/amp/skills/remember/stub-check.cjs
|
|
443
|
+
```
|
|
444
|
+
It edits only *inside* the marker pairs, and only the mechanism: a MEMORY include that
|
|
445
|
+
is not `@.amp/remember/MEMORY.md` is repaired, and an `@`-include of
|
|
446
|
+
`AGENT_RULES.md` is demoted to a plain pointer. Prose inside the blocks is user-owned
|
|
447
|
+
and is never touched, which is why the bootstrap-once rule above still holds. It will
|
|
448
|
+
**not** repoint a MEMORY include at a file that does not exist — an un-migrated
|
|
449
|
+
`.amp/memory/` repo has a live MEMORY.md at the old path, and breaking a working
|
|
450
|
+
include to satisfy a naming convention is worse than reporting it. Silent when the
|
|
451
|
+
shape is already current; relay whatever it prints in the step-8 report.
|
|
452
|
+
|
|
453
|
+
Measured 2026-09-03: 21 of 37 local repos still carried the pre-v2.19 `@`-include of
|
|
454
|
+
`AGENT_RULES.md`, hot-loading ~300 lines into every session. A shape rule checked by
|
|
455
|
+
asking you to look is a rule that drifts back; this one is a byte-level assertion done
|
|
456
|
+
by the script, never by you.
|
|
457
|
+
|
|
395
458
|
```markdown
|
|
396
459
|
# Project Memory
|
|
397
460
|
> Auto-generated by /remember. Do not edit manually.
|
|
@@ -452,8 +515,10 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
452
515
|
`index-flat` script `/docs-builder` already uses, never a model call. Wrapped so any
|
|
453
516
|
failure here can never block the memory write that already happened in steps 3-6.
|
|
454
517
|
|
|
455
|
-
- **Locate `docs-builder.cjs`** —
|
|
456
|
-
|
|
518
|
+
- **Locate `docs-builder.cjs`** — it ships in the `docs-builder/` directory
|
|
519
|
+
that sits beside this one (under `skills/` on Claude Code and Amp, under
|
|
520
|
+
`commands/` on Droid and opencode), exactly as `friction.cjs` ships beside
|
|
521
|
+
this file. Call it by
|
|
457
522
|
its **absolute path** in the command below — the cwd here is the target repo, not this
|
|
458
523
|
package, so a cwd-relative path fails everywhere except the liteagents repo itself.
|
|
459
524
|
- **Not applicable, stay silent:** if the project has no `docs/` directory, skip without
|
|
@@ -535,7 +600,14 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
535
600
|
ledger: ag-003 "don't commit per change" RECURRED while hot (2/2) → rephrased, attempt 2
|
|
536
601
|
ledger: ag-002 "literal scoped ask" ESCALATED → Fact; 2 phrasings failed. Hook or accept?
|
|
537
602
|
```
|
|
538
|
-
-
|
|
603
|
+
- Relay verbatim whatever `version-check.cjs` (step 0), `sync-rules.cjs` (step 1), and
|
|
604
|
+
`stub-check.cjs` (step 5) printed. Never re-word or summarize them: they are the
|
|
605
|
+
record of a file that was written or a version gap, and a paraphrase of "your body
|
|
606
|
+
was backed up to AGENT_RULES.md.bak" can lose the filename the user needs.
|
|
607
|
+
- Each is silent when nothing changed, so silence is the normal case and there is
|
|
608
|
+
nothing to invent — never report an action that produced no output.
|
|
609
|
+
- Never a silent write: if any of the three wrote or moved a file and you did not
|
|
610
|
+
relay its line, that is a defect.
|
|
539
611
|
- If step 7 ran the auto re-index, say so and name the regenerated files
|
|
540
612
|
(`docs/index.md`, plus `docs/log.md` if touched) so they are staged with this run
|
|
541
613
|
- Confirm MEMORY.md and AGENT.md updated
|
|
@@ -543,7 +615,8 @@ Reads all raw material (`.amp/stash/*.md` + `.amp/remember/friction/antigen_clus
|
|
|
543
615
|
**File locations (all project-local — two dirs: `/stash` owns `.amp/stash/`, `/remember` owns `.amp/remember/`)**
|
|
544
616
|
- Stash files: `.amp/stash/*.md`
|
|
545
617
|
- Memory file: `.amp/remember/MEMORY.md` (single source of truth, referenced as `@.amp/remember/MEMORY.md`)
|
|
546
|
-
- Rules template: `.amp/remember/AGENT_RULES.md` (
|
|
618
|
+
- Rules template: `.amp/remember/AGENT_RULES.md` (refreshed from the bundled package template every `/remember` run by `sync-rules.cjs`; a differing body is backed up first, not silently overwritten — referenced by a plain path pointer, not `@`-referenced — see step 5)
|
|
619
|
+
- Rules backup: `.amp/remember/AGENT_RULES.md.bak` (written by `sync-rules.cjs` only when the existing body differs from the template; a single file, overwritten each time it fires — not timestamped)
|
|
547
620
|
- Antigen ledger: `.amp/remember/ledger.json` (per-rule evidence trail: class, status, attempts/rejected-buffer, recurrence-while-hot)
|
|
548
621
|
- Consolidation report: `.amp/remember/report.md` (latest step-8 report, overwritten each run)
|
|
549
622
|
- Processed manifest: `.amp/remember/.processed`
|
|
File without changes
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* stub-check.cjs — asserts the two managed blocks in the tool config carry the
|
|
6
|
+
* CURRENT stub shape, and repairs the shape when it is wrong.
|
|
7
|
+
*
|
|
8
|
+
* Shape, not content. The blocks' prose is user-owned — step 5 writes it once
|
|
9
|
+
* and never re-imposes it, because users trim it deliberately. What this script
|
|
10
|
+
* touches is only the mechanism:
|
|
11
|
+
*
|
|
12
|
+
* MEMORY block @<PROJECT_DIR>/remember/MEMORY.md — an @-include.
|
|
13
|
+
* A bare `@MEMORY.md` resolves relative to the file that
|
|
14
|
+
* contains it, so in a repo root it names a file that does
|
|
15
|
+
* not exist and hot memory silently never loads.
|
|
16
|
+
*
|
|
17
|
+
* AGENT_RULES block <PROJECT_DIR>/remember/AGENT_RULES.md — a PLAIN pointer.
|
|
18
|
+
* v2.19 demoted it from an @-include on purpose: it is a
|
|
19
|
+
* standards guide to consult when building something new,
|
|
20
|
+
* not hot context, and @-including it loads ~300 lines into
|
|
21
|
+
* every session. Measured 2026-09-03: 21 of 37 local repos
|
|
22
|
+
* still carried the pre-v2.19 @-include.
|
|
23
|
+
*
|
|
24
|
+
* Two deliberate limits:
|
|
25
|
+
*
|
|
26
|
+
* - It only edits INSIDE a marker pair. A pointer elsewhere in the config is
|
|
27
|
+
* the user's prose and is left alone.
|
|
28
|
+
* - It never repoints the MEMORY include at a file that does not exist. An
|
|
29
|
+
* un-migrated `.amp/memory/` repo has a live MEMORY.md at the old path;
|
|
30
|
+
* rewriting it to the new one would break a working include to satisfy a
|
|
31
|
+
* naming convention. That case is reported, not repaired.
|
|
32
|
+
*
|
|
33
|
+
* Missing marker pairs are not this script's business — step 5 creates them.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
const fs = require('fs');
|
|
37
|
+
const path = require('path');
|
|
38
|
+
|
|
39
|
+
// The ONE pair of lines that differs across packages.
|
|
40
|
+
const PROJECT_DIR = '.amp';
|
|
41
|
+
const CONFIG_FILE = 'AGENT.md';
|
|
42
|
+
|
|
43
|
+
const MEM = { start: '<!-- MEMORY:START -->', end: '<!-- MEMORY:END -->' };
|
|
44
|
+
const RULES = { start: '<!-- AGENT_RULES:START -->', end: '<!-- AGENT_RULES:END -->' };
|
|
45
|
+
|
|
46
|
+
const MEMORY_REL = `${PROJECT_DIR}/remember/MEMORY.md`;
|
|
47
|
+
const RULES_REL = `${PROJECT_DIR}/remember/AGENT_RULES.md`;
|
|
48
|
+
|
|
49
|
+
/** lstat, not existsSync: existsSync follows links, so a DANGLING link reads
|
|
50
|
+
* as absent and gets walked straight past. */
|
|
51
|
+
function lexists(p) {
|
|
52
|
+
try { fs.lstatSync(p); return true; } catch (e) { return false; }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* True when writing to `target` would land outside `repo`.
|
|
57
|
+
*
|
|
58
|
+
* There are two ways out and a guard on only one of them is false safety:
|
|
59
|
+
* `target` may itself be a symlink — including a dangling one, which reads as
|
|
60
|
+
* "the file is absent" and is still followed on write — or any parent
|
|
61
|
+
* directory may be a link pointing elsewhere. This runs across a whole fleet
|
|
62
|
+
* of repos, so a relative link only has to reach a sibling checkout.
|
|
63
|
+
*
|
|
64
|
+
* A link that stays INSIDE the repo is not an escape: a repo that keeps its
|
|
65
|
+
* rules or its config behind an in-repo symlink is an ordinary setup, and
|
|
66
|
+
* refusing it would strand that repo forever. So the leaf is followed by hand
|
|
67
|
+
* with readlink — which works on a dangling link, where realpath cannot — and
|
|
68
|
+
* each hop re-resolves the parents, because the file a link points at can sit
|
|
69
|
+
* behind a linked directory of its own.
|
|
70
|
+
*/
|
|
71
|
+
function escapesRepo(repo, target) {
|
|
72
|
+
let root;
|
|
73
|
+
try { root = fs.realpathSync(repo); } catch (e) { return true; }
|
|
74
|
+
|
|
75
|
+
let p = path.resolve(target);
|
|
76
|
+
for (let hop = 0; hop < 40; hop++) {
|
|
77
|
+
// Resolve the existing part of the path. Walk up to the deepest ancestor
|
|
78
|
+
// that exists; anything below it cannot be a link yet.
|
|
79
|
+
const tail = [];
|
|
80
|
+
let dir = path.dirname(p);
|
|
81
|
+
while (!lexists(dir)) {
|
|
82
|
+
tail.unshift(path.basename(dir));
|
|
83
|
+
const up = path.dirname(dir);
|
|
84
|
+
if (up === dir) return true; // walked off the filesystem root
|
|
85
|
+
dir = up;
|
|
86
|
+
}
|
|
87
|
+
try { p = path.join(fs.realpathSync(dir), ...tail, path.basename(p)); }
|
|
88
|
+
catch (e) { return true; } // an ancestor is a dangling link
|
|
89
|
+
|
|
90
|
+
let to;
|
|
91
|
+
try { to = fs.readlinkSync(p); } catch (e) {
|
|
92
|
+
return p !== root && !p.startsWith(root + path.sep); // not a link: decide here
|
|
93
|
+
}
|
|
94
|
+
p = path.resolve(path.dirname(p), to);
|
|
95
|
+
}
|
|
96
|
+
return true; // a link cycle: refuse
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Index range of the lines strictly between a marker pair, or null. */
|
|
100
|
+
function blockRange(lines, markers) {
|
|
101
|
+
const s = lines.findIndex((l) => l.trim() === markers.start);
|
|
102
|
+
if (s === -1) return null;
|
|
103
|
+
const e = lines.findIndex((l, i) => i > s && l.trim() === markers.end);
|
|
104
|
+
if (e === -1) return null;
|
|
105
|
+
return { from: s + 1, to: e }; // [from, to)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @returns {{fixes:string[], notes:string[], changed:boolean}}
|
|
110
|
+
* fixes — repairs written to disk
|
|
111
|
+
* notes — wrong shapes deliberately left alone, with the reason
|
|
112
|
+
*/
|
|
113
|
+
function check(repo) {
|
|
114
|
+
const config = path.join(repo, CONFIG_FILE);
|
|
115
|
+
const fixes = [];
|
|
116
|
+
const notes = [];
|
|
117
|
+
|
|
118
|
+
// Checked before the read, not just before the write: a repair decided
|
|
119
|
+
// from a followed link is already the wrong decision.
|
|
120
|
+
if (escapesRepo(repo, config)) {
|
|
121
|
+
return { fixes, notes: [`${CONFIG_FILE} not checked: it leaves the repo via a symlink`], changed: false };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
let text;
|
|
125
|
+
try { text = fs.readFileSync(config, 'utf8'); } catch (e) {
|
|
126
|
+
return { fixes, notes, changed: false }; // no config: step 5 will create one
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const lines = text.split('\n');
|
|
130
|
+
let changed = false;
|
|
131
|
+
|
|
132
|
+
// ── MEMORY block: must be an @-include naming the explicit path ────────────
|
|
133
|
+
const mem = blockRange(lines, MEM);
|
|
134
|
+
if (mem) {
|
|
135
|
+
const i = lines.findIndex(
|
|
136
|
+
(l, n) => n >= mem.from && n < mem.to && /^@\S*MEMORY\.md\s*$/.test(l.trim()));
|
|
137
|
+
if (i === -1) {
|
|
138
|
+
notes.push(`${CONFIG_FILE}: MEMORY block has no @-include — hot memory does not load`);
|
|
139
|
+
} else {
|
|
140
|
+
const want = `@${MEMORY_REL}`;
|
|
141
|
+
const have = lines[i].trim();
|
|
142
|
+
if (have !== want) {
|
|
143
|
+
if (fs.existsSync(path.join(repo, MEMORY_REL))) {
|
|
144
|
+
lines[i] = want;
|
|
145
|
+
changed = true;
|
|
146
|
+
fixes.push(`${CONFIG_FILE}: MEMORY include repaired, ${have} → ${want}`);
|
|
147
|
+
} else {
|
|
148
|
+
// The old path may be the only one with a file behind it.
|
|
149
|
+
notes.push(
|
|
150
|
+
`${CONFIG_FILE}: MEMORY include is ${have}, not ${want} — left as is, `
|
|
151
|
+
+ `${MEMORY_REL} does not exist yet`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── AGENT_RULES block: must be a PLAIN pointer, never an @-include ─────────
|
|
158
|
+
const rules = blockRange(lines, RULES);
|
|
159
|
+
if (rules) {
|
|
160
|
+
const i = lines.findIndex(
|
|
161
|
+
(l, n) => n >= rules.from && n < rules.to && /^@\S*AGENT_RULES\.md\s*$/.test(l.trim()));
|
|
162
|
+
if (i !== -1) {
|
|
163
|
+
// Demote in place. The path is kept as written — only the @ is dropped,
|
|
164
|
+
// because the @ is the defect and the path may be a deliberate variant.
|
|
165
|
+
const had = lines[i].trim();
|
|
166
|
+
lines[i] = had.slice(1);
|
|
167
|
+
changed = true;
|
|
168
|
+
fixes.push(
|
|
169
|
+
`${CONFIG_FILE}: AGENT_RULES pointer demoted from an @-include (${had} → ${had.slice(1)}) `
|
|
170
|
+
+ `— it is a standards guide, not hot context`);
|
|
171
|
+
} else {
|
|
172
|
+
const hasPointer = lines
|
|
173
|
+
.slice(rules.from, rules.to)
|
|
174
|
+
.some((l) => /AGENT_RULES\.md/.test(l));
|
|
175
|
+
if (!hasPointer) {
|
|
176
|
+
notes.push(`${CONFIG_FILE}: AGENT_RULES block has no path pointer — nothing points at the rules`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (changed) {
|
|
182
|
+
try {
|
|
183
|
+
fs.writeFileSync(config, lines.join('\n'));
|
|
184
|
+
} catch (e) {
|
|
185
|
+
return { fixes: [], notes: [`${CONFIG_FILE} not repaired: ${e.message}`], changed: false };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return { fixes, notes, changed };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function main() {
|
|
193
|
+
const repo = process.argv[2] || process.cwd();
|
|
194
|
+
const r = check(repo);
|
|
195
|
+
for (const line of r.fixes) process.stdout.write(`${line}\n`);
|
|
196
|
+
for (const line of r.notes) process.stdout.write(`${line}\n`);
|
|
197
|
+
// Silent when the shape is already current — the common case.
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (require.main === module) {
|
|
201
|
+
// A passenger on /remember, like version-check.cjs and sync-rules.cjs: it
|
|
202
|
+
// never gets to fail the run it rides in.
|
|
203
|
+
try { main(); } catch (e) { /* silent */ }
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = { check, PROJECT_DIR, CONFIG_FILE, MEMORY_REL, RULES_REL };
|