@sabaiway/agent-workflow-memory 1.0.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/LICENSE +21 -0
  3. package/README.md +61 -0
  4. package/SKILL.md +201 -0
  5. package/bin/install.mjs +185 -0
  6. package/bin/install.test.mjs +76 -0
  7. package/capability.json +27 -0
  8. package/migrations/1.1.0-communication-language.md +51 -0
  9. package/migrations/1.2.0-agent-attribution.md +57 -0
  10. package/migrations/README.md +46 -0
  11. package/migrations/legacy-stamp-takeover.md +72 -0
  12. package/package.json +53 -0
  13. package/references/contracts.md +62 -0
  14. package/references/scripts/_expect-shim.mjs +41 -0
  15. package/references/scripts/archive-changelog.mjs +438 -0
  16. package/references/scripts/archive-changelog.test.mjs +212 -0
  17. package/references/scripts/archive-issues.mjs +179 -0
  18. package/references/scripts/archive-issues.test.mjs +95 -0
  19. package/references/scripts/check-docs-size.mjs +353 -0
  20. package/references/scripts/check-docs-size.test.mjs +180 -0
  21. package/references/scripts/install-git-hooks.mjs +83 -0
  22. package/references/templates/AGENTS.md +96 -0
  23. package/references/templates/active_plan.md +31 -0
  24. package/references/templates/agent_rules.md +85 -0
  25. package/references/templates/architecture.md +49 -0
  26. package/references/templates/changelog.md +24 -0
  27. package/references/templates/current_state.md +36 -0
  28. package/references/templates/decisions.md +44 -0
  29. package/references/templates/env_commands.md +41 -0
  30. package/references/templates/handover.md +37 -0
  31. package/references/templates/known_issues.md +33 -0
  32. package/references/templates/pages/PAGE_TEMPLATE.md +53 -0
  33. package/references/templates/pages/index.md +23 -0
  34. package/references/templates/pages/shared-patterns.md +30 -0
  35. package/references/templates/tech_reference.md +34 -0
  36. package/references/templates/technical_specification.md +37 -0
  37. package/scripts/package-content.test.mjs +78 -0
  38. package/scripts/stamp-takeover.mjs +181 -0
  39. package/scripts/stamp-takeover.test.mjs +166 -0
  40. package/scripts/standalone-bootstrap.test.mjs +111 -0
@@ -0,0 +1,51 @@
1
+ # Migration 1.1.0-communication-language
2
+
3
+ **From:** versions < 1.1.0 **To:** 1.1.0
4
+
5
+ ## Why
6
+
7
+ 1.1.0 adds a **conversational language** setting: the language the agent *talks to the
8
+ user* in (questions, explanations, summaries, status). It is recorded in a *Communication
9
+ language* block in the project's `AGENTS.md` so every agent that reads the entry point
10
+ honours it instead of drifting between languages. Pre-1.1.0 deployments have no such block.
11
+
12
+ Scope is **dialogue only** — code, identifiers, paths, commands, log output, and
13
+ abbreviations stay in their source language, and the `docs/ai/` files + `AGENTS.md` are not
14
+ translated either. This migration changes *one* doc block, nothing else.
15
+
16
+ ## Steps
17
+
18
+ 1. Open the project's entry point `AGENTS.md` (the real file; `CLAUDE.md` is a symlink to it).
19
+ 2. **Idempotency check** — if it already contains a `## 🗣️ Communication language` heading,
20
+ this migration is done; skip to Verification.
21
+ 3. **Ask the user** which language the agent should converse in (questions, explanations,
22
+ summaries, status). Offer the language they're already writing in as the default.
23
+ 4. Insert this block immediately **after the opening blockquote** (before `## 🧭 Memory Map`),
24
+ replacing `<their language>` with the answer from step 3:
25
+
26
+ ```markdown
27
+ ---
28
+
29
+ ## 🗣️ Communication language
30
+
31
+ > **Talk to the user in <their language>** — every question, explanation, summary, and status update.
32
+ > Keep code, identifiers, file paths, shell commands, log output, and abbreviations in their **source language** — translating them breaks copy-paste, search, and tooling.
33
+ > This sets the **dialogue** language only — it does not translate the files in `docs/ai/` or this entry point, which stay in their source language (for cross-agent / cross-team portability).
34
+ ```
35
+
36
+ 5. Keep `AGENTS.md` within its ≤100-line budget (the block is ~6 lines; it fits). Do **not**
37
+ touch any other section, and do **not** translate existing file contents.
38
+
39
+ ## Verification
40
+
41
+ - `AGENTS.md` has exactly one `## 🗣️ Communication language` block, with a real language in
42
+ place of `<their language>` (no leftover `{{COMM_LANGUAGE}}` placeholder).
43
+ - The docs cap-validator is still green (`node scripts/check-docs-size.mjs` for Node projects)
44
+ — the entry point did not bust its line budget.
45
+ - From now on the agent's replies are in the chosen language; paths/commands/identifiers
46
+ remain in their source language.
47
+
48
+ ## Rollback
49
+
50
+ Delete the inserted `## 🗣️ Communication language` block (and its trailing `---`) from
51
+ `AGENTS.md`. No other files were changed.
@@ -0,0 +1,57 @@
1
+ # Migration 1.2.0-agent-attribution
2
+
3
+ **From:** versions < 1.2.0 **To:** 1.2.0
4
+
5
+ ## Why
6
+
7
+ 1.2.0 makes **agent attribution opt-in**. The agent may attribute work to itself / AI —
8
+ `Co-Authored-By` trailers, "Generated with …" footers, AI/agent/model mentions in code,
9
+ comments, commit messages, PR titles/bodies, branch names, or docs — **only if the user
10
+ allows it**. Default is `off`. The choice is recorded in an *Attribution* block in the
11
+ project's `AGENTS.md`; pre-1.2.0 deployments have no such block.
12
+
13
+ A single `Co-Authored-By` trailer is enough to list an AI as a repo contributor, and GitHub
14
+ keeps it permanently via PR refs — so the safe default is "no mention anywhere".
15
+
16
+ ## Steps
17
+
18
+ 1. Open the project's entry point `AGENTS.md` (the real file; `CLAUDE.md` is a symlink to it).
19
+ 2. **Idempotency check** — if it already contains a `## ✍️ Attribution` heading, skip to Verification.
20
+ 3. **Ask the user**: may the agent attribute work to itself / AI anywhere (commits, PRs, code,
21
+ comments, docs)? **Default to `off`** unless they opt in.
22
+ 4. Insert this block immediately **after the *Communication language* block** (or, if that is
23
+ absent, after the opening blockquote — before `## 🧭 Memory Map`), replacing `<off|on>` with
24
+ the answer from step 3:
25
+
26
+ ```markdown
27
+ ---
28
+
29
+ ## ✍️ Attribution
30
+
31
+ > **Agent attribution: <off|on>** (chosen at setup).
32
+ > **off** → never attribute work to the agent, AI, or the model: no `Co-Authored-By` trailers, no "Generated with …" footers, no AI/agent/model mentions in code, comments, commit messages, PR titles/bodies, branch names, or docs. Author everything as the human.
33
+ > **on** → the agent may add its standard `Co-Authored-By` trailer / footer per your tooling defaults.
34
+ > Claude Code also honours `includeCoAuthoredBy` in `.claude/settings.json`; this block binds every agent for everything written by hand.
35
+ ```
36
+
37
+ 5. **If the answer is `off` and the project uses Claude Code**, also set the harness flag so the
38
+ automatic trailer stops (a doc directive cannot stop a harness-added trailer):
39
+ - Ensure `.claude/settings.json` exists in the project root; create it as `{}` if absent.
40
+ - Set `"includeCoAuthoredBy": false` (merge into the existing JSON; do not clobber other keys).
41
+ - For other tools, disable their equivalent co-author / footer setting if present.
42
+ 6. Keep `AGENTS.md` within its ≤100-line budget (the block is ~7 lines; it fits). Do **not**
43
+ retroactively rewrite existing git history here — that is a separate, deliberate operation.
44
+
45
+ ## Verification
46
+
47
+ - `AGENTS.md` has exactly one `## ✍️ Attribution` block, with `off` or `on` (no leftover
48
+ `{{AGENT_ATTRIBUTION}}` placeholder).
49
+ - If `off` + Claude Code: `.claude/settings.json` contains `"includeCoAuthoredBy": false`, and
50
+ the file is valid JSON (`node -e "JSON.parse(require('fs').readFileSync('.claude/settings.json'))"`).
51
+ - The docs cap-validator is still green (`node scripts/check-docs-size.mjs` for Node projects).
52
+
53
+ ## Rollback
54
+
55
+ Delete the inserted `## ✍️ Attribution` block (and its trailing `---`) from `AGENTS.md`, and
56
+ remove the `includeCoAuthoredBy` key from `.claude/settings.json` if you added it. No other
57
+ files were changed.
@@ -0,0 +1,46 @@
1
+ # Migrations
2
+
3
+ Each upgrade step is one file: `migrations/<version>-<slug>.md`, where `<version>` is the
4
+ skill release that introduced the change (matches a `CHANGELOG.md` heading) and `<slug>`
5
+ is a short kebab-case name. Empty until the first change that needs migrating — most
6
+ releases add files/templates, which `upgrade` reconciles without a migration.
7
+
8
+ ## How `upgrade` applies them
9
+
10
+ 1. Read the project's stamped version from `docs/ai/.memory-version` (the deployment-lineage
11
+ stamp owned by this substrate). On a deployment that has only the legacy `docs/ai/.workflow-version`
12
+ (a kit fallback bootstrap), `legacy-stamp-takeover.md` runs first and copies that value into
13
+ `.memory-version` verbatim — see that migration.
14
+ 2. Select every migration whose `<version>` is **strictly newer** than the stamp.
15
+ 3. Apply them in **ascending semver order**.
16
+ 4. Re-stamp `docs/ai/.memory-version` to the deployment-lineage head (`1.3.0` today — the shared
17
+ lineage sequence, **not** this package's npm version). The legacy `.workflow-version`, if present,
18
+ is never deleted.
19
+
20
+ ## Authoring rules
21
+
22
+ - **Idempotent** — safe to re-run; check before mutating (e.g. "if the file already has X, skip").
23
+ - **Non-destructive** — never clobber project-authored content (their `decisions.md`, `known_issues.md`, page specs). Add/rename/restructure only what the kernel owns.
24
+ - **Self-contained** — exact paths + commands, readable cold, like a mini-plan.
25
+ - **Mention rollback** — note how to undo if the step is risky.
26
+
27
+ ## Template
28
+
29
+ ```markdown
30
+ # Migration <version>-<slug>
31
+
32
+ **From:** versions < <version> **To:** <version>
33
+
34
+ ## Why
35
+ <what changed in the kernel and why a project needs to follow>
36
+
37
+ ## Steps
38
+ 1. <exact, idempotent action with paths/commands>
39
+ 2. ...
40
+
41
+ ## Verification
42
+ <how to confirm the project is now consistent — e.g. docs cap-validator green>
43
+
44
+ ## Rollback
45
+ <how to undo, or "n/a — additive only">
46
+ ```
@@ -0,0 +1,72 @@
1
+ # Migration legacy-stamp-takeover
2
+
3
+ **From:** a deployment stamped only with the legacy `docs/ai/.workflow-version` (a kit-fallback
4
+ bootstrap, or a pre-extraction kit deployment) **To:** the memory substrate's
5
+ `docs/ai/.memory-version`
6
+
7
+ This is the **no-Node manual fallback** for `scripts/stamp-takeover.mjs`. The script is the
8
+ source of truth (pure state machine + atomic writes, unit-tested per row); this file documents
9
+ the same table so a non-Node project can do it by hand. Run it **first** in `upgrade`, before
10
+ any other migration.
11
+
12
+ ## Why
13
+
14
+ The deployment stamp moved from `.workflow-version` (owned by the kit) to `.memory-version`
15
+ (owned by this substrate). They track the **same** shared deployment-lineage sequence — never
16
+ their package versions. The current lineage head is **`1.3.0`** (`LINEAGE_HEAD`). This migration
17
+ adopts an existing legacy stamp into the new file **without** changing the lineage value and
18
+ **without** deleting the legacy stamp (both may coexist; each tool migrates from its own stamp).
19
+
20
+ ## State table (idempotent)
21
+
22
+ Look at `docs/ai/` and act by row. `V` is the legacy stamp's value; `head` = `1.3.0`.
23
+
24
+ | `docs/ai/` state | Action |
25
+ |---|---|
26
+ | only `.workflow-version=V` | copy `V` **verbatim** → `.memory-version`; **leave** `.workflow-version`; then apply only memory migrations `> V` |
27
+ | both `.memory-version` and `.workflow-version` | **no-op** for takeover; migrate from `.memory-version` |
28
+ | only `.memory-version` | no takeover; migrate from it |
29
+ | no stamp | conservative re-bootstrap offer (existing behaviour) |
30
+ | any present stamp unparseable, or `> head` (future) | **STOP and report** — never downgrade or guess |
31
+
32
+ ## Steps (manual)
33
+
34
+ 1. **Inspect** the two files. Distinguish *absent* (the file does not exist) from a *read failure*
35
+ (it exists but `cat` fails — permission/I/O): only absence is "no stamp"; a read failure must
36
+ **STOP** (don't treat it as absent):
37
+ ```bash
38
+ for f in docs/ai/.memory-version docs/ai/.workflow-version; do
39
+ if [ ! -e "$f" ]; then echo "$f: (absent)";
40
+ elif v=$(cat "$f"); then echo "$f: $v";
41
+ else echo "$f: READ FAILED — STOP and report"; exit 1; fi
42
+ done
43
+ ```
44
+ 2. **Validate** each value that exists: it must be `MAJOR.MINOR.PATCH`, non-empty, and **not** greater
45
+ than `1.3.0`. If any present stamp is empty, unparseable, or in the future → **STOP and report**;
46
+ do nothing else.
47
+ 3. **Apply** the matching row above. For the "only `.workflow-version=V`" row, copy verbatim and
48
+ write **atomically** — create an exclusive randomized temp in `docs/ai/` (so a planted temp-name
49
+ symlink can't be followed), then `mv` it over the target:
50
+ ```bash
51
+ v=$(cat docs/ai/.workflow-version)
52
+ tmp=$(mktemp docs/ai/.memory-version.XXXXXX) && printf '%s\n' "$v" > "$tmp" && mv "$tmp" docs/ai/.memory-version
53
+ ```
54
+ 4. Continue the normal `upgrade` flow: apply memory migrations strictly newer than the resolved
55
+ stamp, then re-stamp `.memory-version` to the lineage head.
56
+
57
+ Node projects do all of this in one call — pass the project's `docs/ai` directory:
58
+ ```bash
59
+ node "${CLAUDE_SKILL_DIR}/scripts/stamp-takeover.mjs" docs/ai # runs applyTakeover() on docs/ai
60
+ ```
61
+
62
+ ## Verification
63
+
64
+ - `docs/ai/.memory-version` exists and equals the resolved lineage value (a single semver line,
65
+ trailing newline). `docs/ai/.workflow-version`, if it existed, is **unchanged**.
66
+ - Re-running this migration changes nothing (idempotent).
67
+ - No `.memory-version.tmp-*` files remain in `docs/ai/`.
68
+
69
+ ## Rollback
70
+
71
+ Delete `docs/ai/.memory-version` (the legacy `.workflow-version` was never modified). No other
72
+ files were changed.
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@sabaiway/agent-workflow-memory",
3
+ "version": "1.0.0",
4
+ "description": "Portable, cross-agent memory substrate for AI coding agents — an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement, deployable standalone or as part of the agent-workflow family. The memory layer of the agent-workflow family.",
5
+ "keywords": [
6
+ "ai-agents",
7
+ "ai-coding",
8
+ "coding-agent",
9
+ "llm",
10
+ "ai-tools",
11
+ "claude-code",
12
+ "codex",
13
+ "cursor",
14
+ "agents-md",
15
+ "agent-memory",
16
+ "context-engineering",
17
+ "cross-agent",
18
+ "memory",
19
+ "developer-tools"
20
+ ],
21
+ "homepage": "https://github.com/sabaiway/agent-workflow#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/sabaiway/agent-workflow/issues"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/sabaiway/agent-workflow.git",
28
+ "directory": "agent-workflow-memory"
29
+ },
30
+ "license": "MIT",
31
+ "author": "sabaiway",
32
+ "type": "module",
33
+ "bin": {
34
+ "agent-workflow-memory": "bin/install.mjs"
35
+ },
36
+ "files": [
37
+ "bin/",
38
+ "SKILL.md",
39
+ "README.md",
40
+ "CHANGELOG.md",
41
+ "LICENSE",
42
+ "capability.json",
43
+ "references/",
44
+ "scripts/",
45
+ "migrations/"
46
+ ],
47
+ "engines": {
48
+ "node": ">=18"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ }
53
+ }
@@ -0,0 +1,62 @@
1
+ # Setup contracts
2
+
3
+ The three choices the bootstrap makes with the user — **visibility**, **conversational
4
+ language**, and **agent attribution** — each have a contract below. `SKILL.md` links here so the
5
+ main procedure stays lean; load this file when you need the full rule for a contract (e.g. while
6
+ filling the matching `AGENTS.md` block, or when an `upgrade` migration touches it).
7
+
8
+ Ask each as a **structured multiple-choice prompt where your agent supports it** (`AskUserQuestion`
9
+ in Claude Code), otherwise in prose — and always wait for the answer before writing.
10
+
11
+ ---
12
+
13
+ ## Visibility contract
14
+
15
+ The user chooses at bootstrap whether the AI artifacts are visible in the repo or hidden — an
16
+ **explicit up-front question** (bootstrap step 2), never an assumed default. The two modes then
17
+ diverge:
18
+
19
+ - **visible** — artifacts are committed. Wire the project's `package.json` scripts (`docs:check` / `docs:index` / `docs:index:check` / `docs:archive` / `docs:archive:check` / `docs:archive:issues` / `docs:archive:issues:check` / `prepare: node scripts/install-git-hooks.mjs`) and add a minimal `.gitignore` (`docs/plans/`, `.claude/settings.local.json`). This is the canonical model.
20
+ - **hidden** (in-tree) — same files on disk, but the repo "looks normal": append the artifact paths (`AGENTS.md`, `CLAUDE.md`, `docs/ai/`, `docs/plans/`, `scripts/*.mjs` you added, `docs/ai/.memory-version`, and — if a kit fallback bootstrap stamped one — `docs/ai/.workflow-version`) to the global excludes file git **already uses** (`git config --get core.excludesFile`); if none is set, point it at `~/.gitignore_global` (`git config --global core.excludesFile ~/.gitignore_global`) and append there. **Verify `git status` shows the artifacts as ignored** afterwards. **Do not edit `package.json`** — that is a tracked change and would leak; the pre-commit hook (always untracked in `.git/hooks/`) calls the scripts via `node scripts/<x>.mjs` directly.
21
+
22
+ Not in this version: a fully-external hidden mode (artifacts relocated outside the repo tree).
23
+ Deferred to a later release + migration.
24
+
25
+ ---
26
+
27
+ ## Communication contract
28
+
29
+ The user chooses at bootstrap (step 3) which language the agent **talks to them** in. The choice is
30
+ recorded in the *Communication language* block of the project's `AGENTS.md`, so every agent that
31
+ reads the entry point honours it — and stops drifting between languages mid-session.
32
+
33
+ Scope — **dialogue only**:
34
+
35
+ - **In the chosen language** — everything the agent produces *for the user to read*: questions, explanations, plan summaries, status updates, commit-message prose if asked, review notes.
36
+ - **Always in their source language** — code, identifiers, file paths, shell commands, log/console output, error strings, config keys, and abbreviations/acronyms. Translating these breaks copy-paste, search, and tooling.
37
+ - **Files aren't translated** — the deployed `docs/ai/` files, `AGENTS.md`, and this kernel stay in their source language regardless of the chosen language (cross-agent / cross-team portability). The conversational language is about the *chat*, not the *artifacts*.
38
+
39
+ Default to the language the user is already writing in; confirm rather than assume. On `upgrade`, a
40
+ pre-1.1.0 deployment with no block gets one (the agent asks).
41
+
42
+ ---
43
+
44
+ ## Attribution contract
45
+
46
+ The user chooses at bootstrap (step 4) whether the agent may **attribute work to itself or to AI**.
47
+ The choice is recorded in the *Attribution* block of the project's `AGENTS.md`, so every agent that
48
+ reads the entry point honours it. **Default is `off`** — people are routinely surprised to find an
49
+ AI listed as a repo contributor (a `Co-Authored-By` trailer is enough to do it), so opt-in, never
50
+ opt-out.
51
+
52
+ When attribution is **`off`**, no mention of the agent, AI, or the model appears **anywhere**:
53
+
54
+ - **No `Co-Authored-By` trailers** and **no "Generated with …" footers** on commits or PRs.
55
+ - **No AI/agent/model references** in code, comments, commit messages, PR titles/bodies, branch names, or `docs/` prose. The work reads as the human author's.
56
+ - **Two enforcement layers** — the *Attribution* block binds everything an agent writes **by hand**; the automatic `Co-Authored-By` trailer is added by the **harness**, not the prose, so for **Claude Code** the bootstrap also sets `"includeCoAuthoredBy": false` in the project's `.claude/settings.json`. Other tools: disable their equivalent co-author/footer setting if present.
57
+
58
+ When **`on`**, the agent may add its standard trailer / footer per the user's tooling defaults. This
59
+ block is about *attribution*, not authorship of the actual changes — quality, tests, and the "ask
60
+ before commit" rule are unchanged either way.
61
+
62
+ On `upgrade`, a pre-1.2.0 deployment with no block gets one (the agent asks, defaulting to `off`).
@@ -0,0 +1,41 @@
1
+ // Minimal dependency-free `expect` shim mapping the Vitest matchers used by the
2
+ // kernel's *.test.mjs onto node:assert, so the suite runs under `node --test` with
3
+ // zero dependencies. Supports only the matchers these tests use.
4
+ import assert from 'node:assert/strict';
5
+
6
+ const has = (actual, expected) => {
7
+ if (typeof actual === 'string') return actual.includes(expected);
8
+ if (Array.isArray(actual)) return actual.includes(expected);
9
+ return false;
10
+ };
11
+
12
+ const matchers = (actual, negate) => ({
13
+ toBe: (expected) =>
14
+ negate ? assert.notStrictEqual(actual, expected) : assert.strictEqual(actual, expected),
15
+ toEqual: (expected) =>
16
+ negate ? assert.notDeepStrictEqual(actual, expected) : assert.deepStrictEqual(actual, expected),
17
+ toContain: (expected) =>
18
+ assert.ok(
19
+ negate ? !has(actual, expected) : has(actual, expected),
20
+ `expected ${JSON.stringify(actual)} ${negate ? 'not ' : ''}to contain ${JSON.stringify(expected)}`,
21
+ ),
22
+ toMatch: (re) => (negate ? assert.doesNotMatch(actual, re) : assert.match(actual, re)),
23
+ toHaveLength: (n) =>
24
+ negate ? assert.notStrictEqual(actual.length, n) : assert.strictEqual(actual.length, n),
25
+ toBeNull: () => (negate ? assert.notStrictEqual(actual, null) : assert.strictEqual(actual, null)),
26
+ toBeInstanceOf: (Ctor) =>
27
+ assert.ok(
28
+ negate ? !(actual instanceof Ctor) : actual instanceof Ctor,
29
+ `expected value ${negate ? 'not ' : ''}to be instance of ${Ctor.name}`,
30
+ ),
31
+ toBeGreaterThan: (n) =>
32
+ assert.ok(negate ? !(actual > n) : actual > n, `expected ${actual} ${negate ? 'not ' : ''}> ${n}`),
33
+ toBeLessThan: (n) =>
34
+ assert.ok(negate ? !(actual < n) : actual < n, `expected ${actual} ${negate ? 'not ' : ''}< ${n}`),
35
+ });
36
+
37
+ export const expect = (actual) => {
38
+ const api = matchers(actual, false);
39
+ api.not = matchers(actual, true);
40
+ return api;
41
+ };