@sabaiway/agent-workflow-kit 1.2.0 → 1.4.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 +47 -1
- package/README.md +15 -5
- package/SKILL.md +86 -42
- package/bin/install.mjs +59 -8
- package/bin/install.test.mjs +66 -0
- package/capability.json +21 -0
- package/migrations/1.1.0-communication-language.md +5 -5
- package/migrations/README.md +2 -1
- package/package.json +8 -5
- package/references/contracts.md +62 -0
- package/references/scripts/archive-changelog.mjs +1 -4
- package/references/templates/AGENTS.md +2 -2
- package/tools/delegation.mjs +109 -0
- package/tools/delegation.test.mjs +115 -0
- package/tools/inject-methodology.mjs +111 -0
- package/tools/inject-methodology.test.mjs +124 -0
- package/tools/manifest/fixtures/bad-available/SKILL.md +7 -0
- package/tools/manifest/fixtures/bad-available/capability.json +10 -0
- package/tools/manifest/fixtures/detect-array/SKILL.md +7 -0
- package/tools/manifest/fixtures/detect-array/capability.json +10 -0
- package/tools/manifest/fixtures/malformed-json/capability.json +1 -0
- package/tools/manifest/fixtures/metadata-version/SKILL.md +10 -0
- package/tools/manifest/fixtures/metadata-version/capability.json +9 -0
- package/tools/manifest/fixtures/missing-key/SKILL.md +7 -0
- package/tools/manifest/fixtures/missing-key/capability.json +8 -0
- package/tools/manifest/fixtures/missing-source/SKILL.md +7 -0
- package/tools/manifest/fixtures/missing-source/capability.json +11 -0
- package/tools/manifest/fixtures/nested-version-decoy/SKILL.md +10 -0
- package/tools/manifest/fixtures/nested-version-decoy/capability.json +9 -0
- package/tools/manifest/fixtures/null-root/capability.json +1 -0
- package/tools/manifest/fixtures/provides-roles-mismatch/SKILL.md +7 -0
- package/tools/manifest/fixtures/provides-roles-mismatch/bin/run.sh +2 -0
- package/tools/manifest/fixtures/provides-roles-mismatch/capability.json +11 -0
- package/tools/manifest/fixtures/stub/capability.json +10 -0
- package/tools/manifest/fixtures/traversal-source/SKILL.md +7 -0
- package/tools/manifest/fixtures/traversal-source/capability.json +11 -0
- package/tools/manifest/fixtures/unknown-schema/capability.json +9 -0
- package/tools/manifest/fixtures/valid/SKILL.md +10 -0
- package/tools/manifest/fixtures/valid/bin/run.sh +3 -0
- package/tools/manifest/fixtures/valid/capability.json +18 -0
- package/tools/manifest/fixtures/version-mismatch/SKILL.md +7 -0
- package/tools/manifest/fixtures/version-mismatch/capability.json +9 -0
- package/tools/manifest/fixtures/win-absolute-source/SKILL.md +7 -0
- package/tools/manifest/fixtures/win-absolute-source/capability.json +11 -0
- package/tools/manifest/schema.md +67 -0
- package/tools/manifest/validate.mjs +264 -0
- package/tools/manifest/validate.test.mjs +73 -0
- package/tools/methodology-slot.md +1 -0
- package/tools/release-scan.mjs +103 -0
- package/tools/release-scan.test.mjs +41 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,52 @@ Semantically versioned ([semver](https://semver.org)), newest first. The `versio
|
|
|
4
4
|
is the current release. `upgrade` mode reads a project's `docs/ai/.workflow-version` and applies
|
|
5
5
|
every `migrations/<version>-<slug>.md` newer than it, in semver order.
|
|
6
6
|
|
|
7
|
+
## 1.4.0 — Delegation-aware composition root (agent-workflow family, Plan 1)
|
|
8
|
+
|
|
9
|
+
The kit becomes the **composition root** of the new `agent-workflow` family. **Additive** — the
|
|
10
|
+
kit keeps its entire bundled substrate as a fallback, so the existing one-command install is
|
|
11
|
+
unchanged and **no migration is needed** (`upgrade` reconciles and re-stamps; the deployment
|
|
12
|
+
lineage head stays `1.3.0`). Published from the new `agent-workflow` monorepo.
|
|
13
|
+
|
|
14
|
+
- **Memory extracted to `@sabaiway/agent-workflow-memory`** — the memory substrate (`docs/ai/`,
|
|
15
|
+
the entry point, caps / archive / index, the three setup contracts) now also ships as its own
|
|
16
|
+
package. The kit **delegates** substrate deployment to it when a **kit-owned detector** finds it
|
|
17
|
+
valid, and otherwise uses its own bundled copy. Detection runs the kit's **own shipped**
|
|
18
|
+
`tools/manifest/validate.mjs` (never a validator shipped by the candidate) and requires
|
|
19
|
+
`kind: memory-substrate` **valid** plus all required assets present; unsupported / invalid /
|
|
20
|
+
unavailable / wrong-family / wrong-name → bundled fallback. The fallback decision is made
|
|
21
|
+
**before** any project write.
|
|
22
|
+
- **Family manifest contract** — every member ships a `capability.json` (`schema 1`, JSON,
|
|
23
|
+
dependency-free). The kit **owns and ships** the schema + validator at `tools/manifest/`
|
|
24
|
+
(in the tarball + installer `PAYLOAD`, so an installed kit can run the detector; root CI invokes
|
|
25
|
+
the same file). The kit's own manifest is `kind: composition-root`.
|
|
26
|
+
- **Methodology slot injection** — memory ships an **empty** delimited `workflow:methodology` slot
|
|
27
|
+
in `AGENTS.md`; the kit is its **only** writer, injecting a **bounded** summary + pointer
|
|
28
|
+
(`tools/inject-methodology.mjs` + `tools/methodology-slot.md`) that keeps `AGENTS.md` under its
|
|
29
|
+
≤100-line cap. Marker contract: exactly one ordered pair → replace between; absent → no-op;
|
|
30
|
+
malformed → no-op with an error.
|
|
31
|
+
- **Two-stamp delegation hand-off** — delegated mode: memory writes `.memory-version`, the kit
|
|
32
|
+
injects + writes the fallback `.workflow-version` (→ both stamps); fallback mode: `.workflow-version`
|
|
33
|
+
only. Exactly **one** composition-level commit gate, owned by the kit, after injection. The
|
|
34
|
+
decision + hand-off matrix is codified and unit-tested in `tools/delegation.mjs`
|
|
35
|
+
(`detectMemory` + `handoffPlan`), so it does not depend on agent interpretation.
|
|
36
|
+
- **Release gate — attribution-off** — `tools/release-scan.mjs` fails on AI/reviewer attribution
|
|
37
|
+
(co-author trailers, "Generated with <AI>" footers) anywhere in the release tree, so no agent
|
|
38
|
+
attribution can ship by accident.
|
|
39
|
+
- **Hardened installer** — `copyRecursive` never writes *through* a destination symlink
|
|
40
|
+
(root / intermediate / leaf). `capability.json` + `tools/` added to `files` and the installer
|
|
41
|
+
`PAYLOAD`. `repository`/`homepage`/`bugs` repointed to the `agent-workflow` monorepo.
|
|
42
|
+
|
|
43
|
+
## 1.3.0 — Skill authoring aligned with Anthropic's Skills guidance
|
|
44
|
+
|
|
45
|
+
Internal refinements to how the kernel itself is written — no change to what gets deployed into a
|
|
46
|
+
project, so **no migration is needed** (`upgrade` reconciles and re-stamps to `1.3.0` with nothing
|
|
47
|
+
to apply). Drawn from [*Lessons from building Claude Code: how we use Skills*](https://claude.com/blog/lessons-from-building-claude-code-how-we-use-skills).
|
|
48
|
+
|
|
49
|
+
- **Consolidated Gotchas section in `SKILL.md`** — the blog calls the Gotchas section "the highest-signal content in any skill". The non-obvious traps that were scattered through the procedure (harness-added `Co-Authored-By` vs prose, hidden mode never touching `package.json`, `CLAUDE.md` as a symlink not a copy, source-vs-target dir, no-Node → skip enforcement, never overwrite an existing entry point/hook) are now also a single scannable list.
|
|
50
|
+
- **Setup contracts moved to `references/contracts.md`** — progressive disclosure: `SKILL.md` keeps a lean *Setup contracts* pointer (with one-line defaults), and the full Visibility / Communication / Attribution rules load only when needed. Trims the always-loaded `SKILL.md` by ~40 lines without losing any rule.
|
|
51
|
+
- **Setup questions use structured prompts where supported** — the three bootstrap questions (visibility, language, attribution) and the equivalent `upgrade` migration questions now call for a structured multiple-choice prompt (`AskUserQuestion` in Claude Code) where the agent supports it, falling back to prose elsewhere — keeping cross-agent portability (Codex / Cursor / Devin) intact.
|
|
52
|
+
|
|
7
53
|
## 1.2.0 — Agent attribution is opt-in
|
|
8
54
|
|
|
9
55
|
**Attribution question at setup**
|
|
@@ -23,7 +69,7 @@ every `migrations/<version>-<slug>.md` newer than it, in semver order.
|
|
|
23
69
|
**Conversational language (dialogue only)**
|
|
24
70
|
|
|
25
71
|
- **Bootstrap now asks the conversational language** — a new step 3 in `/agent-workflow-kit`, alongside the visibility question. The agent records the answer in a new *Communication language* block in the project's `AGENTS.md`, so every agent that reads the entry point talks to the user in that language and stops drifting between languages mid-session.
|
|
26
|
-
- **Dialogue-only scope, by design** — the choice governs what the agent writes *for the user to read* (questions, explanations, summaries, status). Code, identifiers, file paths, shell commands, log output, and abbreviations stay in their source language; the deployed `docs/ai/` files and `AGENTS.md`
|
|
72
|
+
- **Dialogue-only scope, by design** — the choice governs what the agent writes *for the user to read* (questions, explanations, summaries, status). Code, identifiers, file paths, shell commands, log output, and abbreviations stay in their source language; the deployed `docs/ai/` files and `AGENTS.md` are not translated either (the conversational choice governs the chat, not the artifacts). See the *Communication contract* in `SKILL.md`.
|
|
27
73
|
- **Existing deployments are covered** — `/agent-workflow-kit upgrade` backfills the block on a pre-1.1.0 project, asking the user their language. See `migrations/1.1.0-communication-language.md` (idempotent, additive).
|
|
28
74
|
|
|
29
75
|
**Clearer install / upgrade guidance**
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ instead of re-reading your whole repo.*
|
|
|
12
12
|
[](./LICENSE)
|
|
13
13
|
[](https://nodejs.org)
|
|
14
14
|
|
|
15
|
-
`v1.
|
|
15
|
+
`v1.4.0` · `Node ≥ 18` · `kernel-only`
|
|
16
16
|
|
|
17
17
|
**Works with any tool that reads `AGENTS.md`** — Claude Code · Codex · Cursor · Devin Desktop (formerly Windsurf) · GitHub Copilot · Gemini CLI · Cline · Aider · and 20+ more.
|
|
18
18
|
|
|
@@ -121,6 +121,12 @@ Then invoke it **inside a project** — first time vs. already-deployed use diff
|
|
|
121
121
|
|
|
122
122
|
<sub>`/agent-workflow-kit` bootstraps a fresh deployment (and asks your **visibility**, **conversational language**, and whether the agent may **attribute work to itself / AI** — default off); `/agent-workflow-kit upgrade` migrates an existing one to the kit's current version. The `npx … init` above is a third, separate thing — it updates the **kit itself**, not any project.</sub>
|
|
123
123
|
|
|
124
|
+
> **New in 1.4.0 — optional memory substrate.** The memory layer is now also published
|
|
125
|
+
> standalone as [`@sabaiway/agent-workflow-memory`](https://www.npmjs.com/package/@sabaiway/agent-workflow-memory).
|
|
126
|
+
> If it is installed, the kit **delegates** substrate deployment to it and injects the workflow
|
|
127
|
+
> methodology; if not, the kit uses its **own bundled copy** — the one command above keeps
|
|
128
|
+
> working with no new dependency. Same `docs/ai/` either way.
|
|
129
|
+
|
|
124
130
|
**Upgrade the kit itself** later — same command with `@latest`:
|
|
125
131
|
|
|
126
132
|
```bash
|
|
@@ -132,11 +138,12 @@ npx @sabaiway/agent-workflow-kit@latest init
|
|
|
132
138
|
<details>
|
|
133
139
|
<summary><b>Manual install</b> — no <code>npx</code></summary>
|
|
134
140
|
|
|
135
|
-
The kit is a single self-contained folder
|
|
141
|
+
The kit is a single self-contained folder inside the `agent-workflow` monorepo. Clone the repo
|
|
142
|
+
and copy the kit into a skill scope yourself, then run the launcher:
|
|
136
143
|
|
|
137
144
|
```bash
|
|
138
|
-
git clone https://github.com/sabaiway/agent-workflow
|
|
139
|
-
|
|
145
|
+
git clone https://github.com/sabaiway/agent-workflow
|
|
146
|
+
cp -r agent-workflow/agent-workflow-kit ~/.claude/skills/agent-workflow-kit
|
|
140
147
|
cd ~/.claude/skills/agent-workflow-kit
|
|
141
148
|
bash launchers/install-launchers.sh
|
|
142
149
|
```
|
|
@@ -210,10 +217,13 @@ agent-workflow-kit/
|
|
|
210
217
|
├── README.md ← you are here
|
|
211
218
|
├── SKILL.md ← agent-facing algorithm
|
|
212
219
|
├── CHANGELOG.md ← version history
|
|
220
|
+
├── capability.json ← agent-workflow family manifest (composition-root)
|
|
213
221
|
├── references/
|
|
214
222
|
├── templates/ ← AGENTS.md + every docs/ai file
|
|
215
223
|
├── scripts/ ← caps / archive / index + tests
|
|
224
|
+
├── contracts.md ← visibility / language / attribution rules
|
|
216
225
|
└── planning.md ← plan lifecycle + continuity
|
|
226
|
+
├── tools/ ← family tooling: manifest schema + validator, methodology-slot injection
|
|
217
227
|
├── launchers/ ← Codex / Devin Desktop / Cursor entries
|
|
218
228
|
└── migrations/ ← per-version upgrade steps
|
|
219
229
|
```
|
|
@@ -221,5 +231,5 @@ agent-workflow-kit/
|
|
|
221
231
|
---
|
|
222
232
|
|
|
223
233
|
<div align="center">
|
|
224
|
-
<sub>Kernel-only · stack-agnostic ·
|
|
234
|
+
<sub>Kernel-only · stack-agnostic · distilled from a multi-year-verified reference implementation.</sub>
|
|
225
235
|
</div>
|
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: agent-workflow-kit
|
|
|
3
3
|
description: Deploy or upgrade a portable AI-agent memory-and-workflow system in any project. Use when the user wants to bootstrap `docs/ai/` + an entry-point `AGENTS.md` (+ `CLAUDE.md` alias) + cap/archive/index enforcement in a new or existing repo, set up the Memory Map and session protocols, install the docs-rotation pre-commit hook, or run `/agent-workflow-kit` / `/agent-workflow-kit upgrade`. Triggers on phrases like "set up the memory system", "deploy the AI workflow here", "bootstrap docs/ai", "upgrade the workflow".
|
|
4
4
|
disable-model-invocation: true
|
|
5
5
|
metadata:
|
|
6
|
-
version: '1.
|
|
6
|
+
version: '1.4.0'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# agent-workflow-kit
|
|
@@ -12,12 +12,66 @@ Deploys a **portable AI-agent memory-and-workflow system** into a project, and u
|
|
|
12
12
|
|
|
13
13
|
The kernel is **stack-agnostic workflow** — `docs/ai/` structure, entry-point doc, session protocols, plan lifecycle, frontmatter caps, 3-tier archive, index-freshness gate. Enforcement ships as **Node `.mjs` scripts** (the reference implementation; non-Node stacks follow the same policy manually).
|
|
14
14
|
|
|
15
|
-
The kernel **artifacts** (this skill, the templates, the deployed `docs/ai/` files)
|
|
15
|
+
The kernel **artifacts** (this skill, the templates, the deployed `docs/ai/` files) stay in their **source language** — for cross-agent and cross-team portability. That is separate from the **conversational language**: the language the agent *talks to the user* in (questions, explanations, summaries, status). That is chosen once at bootstrap (step 3), recorded in the project's `AGENTS.md`, and applied to dialogue only — it never translates file contents, code, identifiers, paths, commands, or abbreviations.
|
|
16
16
|
|
|
17
17
|
This kernel is distilled from a canonical, battle-tested reference implementation. The skill is the single source of truth — projects deploy from it and upgrade against it.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Memory substrate: delegate or fall back (composition root)
|
|
22
|
+
|
|
23
|
+
This kit is the **composition root** of the `agent-workflow` family. The memory substrate
|
|
24
|
+
(`docs/ai/`, the entry-point doc, caps / archive / index, the setup contracts) is owned by
|
|
25
|
+
**`agent-workflow-memory`**. The kit **prefers to delegate** substrate deployment to that skill
|
|
26
|
+
when it is present and healthy, and otherwise uses its **own bundled copy** (`references/`,
|
|
27
|
+
`migrations/`) — so the existing one-command install keeps working with **no new dependency**.
|
|
28
|
+
|
|
29
|
+
**Detection (kit-owned, decided BEFORE any project write).** Run the kit's **own shipped**
|
|
30
|
+
validator — `node ${CLAUDE_SKILL_DIR}/tools/manifest/validate.mjs <memory-skill-dir>` — never a
|
|
31
|
+
validator shipped by the candidate (which could itself be broken). Delegate only when **all**
|
|
32
|
+
hold:
|
|
33
|
+
- result is **valid** and `kind` is `memory-substrate`;
|
|
34
|
+
- **every required asset is present** in the candidate, at its real path:
|
|
35
|
+
`references/templates/`, `references/contracts.md`, `references/scripts/`,
|
|
36
|
+
`scripts/stamp-takeover.mjs`, `migrations/`, `capability.json`. A partial install (manifest +
|
|
37
|
+
`SKILL.md` only) is treated as **invalid**.
|
|
38
|
+
|
|
39
|
+
On **unsupported** (unknown schema), **invalid**, **unavailable**, **wrong-family**, or
|
|
40
|
+
**wrong-name**, **use the bundled copy** — never block. The fallback decision is final once
|
|
41
|
+
made: a partial/broken memory install discovered mid-flow must not disable the working fallback.
|
|
42
|
+
|
|
43
|
+
> The **executable form** of this whole decision lives in
|
|
44
|
+
> [`tools/delegation.mjs`](tools/delegation.mjs): `detectMemory(<memory-dir>)` runs the validator +
|
|
45
|
+
> the required-asset check and returns `delegate` / fallback with a reason; `handoffPlan(delegate)`
|
|
46
|
+
> returns who writes what, which stamps end up present, and that the commit gate is kit-only. Both
|
|
47
|
+
> are unit-tested, so the contract below is pinned by code, not agent interpretation.
|
|
48
|
+
|
|
49
|
+
**Hand-off contract (explicit; tested independent of agent interpretation).**
|
|
50
|
+
- **Delegated** (memory valid): the kit passes the **target project dir** + the **three setup
|
|
51
|
+
answers** (visibility / language / attribution) to `agent-workflow-memory`, which writes
|
|
52
|
+
`docs/ai/` + `AGENTS.md` + **`.memory-version`**. The kit then **injects the bounded
|
|
53
|
+
methodology slot** (below) and writes the kit-fallback **`.workflow-version`**. → **both
|
|
54
|
+
stamps** present.
|
|
55
|
+
- **Fallback** (memory absent/invalid): the kit runs the bootstrap procedure below from its own
|
|
56
|
+
bundled assets and writes **`.workflow-version`** only. Softly suggest installing
|
|
57
|
+
`agent-workflow-memory` — never a prerequisite.
|
|
58
|
+
|
|
59
|
+
**Methodology injection (the kit is the ONLY writer of memory's slot).** After `AGENTS.md`
|
|
60
|
+
exists, inject the bounded methodology fragment into its `workflow:methodology` slot:
|
|
61
|
+
`node ${CLAUDE_SKILL_DIR}/tools/inject-methodology.mjs <project>/AGENTS.md`. It injects a short
|
|
62
|
+
summary + pointer (Phase-1 source: the kit's bundled `tools/methodology-slot.md`) — **not** the
|
|
63
|
+
full `references/planning.md` — and keeps `AGENTS.md` under its ≤100-line cap. Marker contract:
|
|
64
|
+
exactly one ordered `start → end` pair → replace only the bytes between them; markers absent →
|
|
65
|
+
no-op; any malformed state (single, reversed, nested, duplicate) → no-op **with an error**,
|
|
66
|
+
never edit.
|
|
67
|
+
|
|
68
|
+
**One composition-level commit gate.** The delegated memory mode performs **no** commit and
|
|
69
|
+
raises **no** "ask to commit". There is exactly **one** gate, owned by the kit, **after**
|
|
70
|
+
injection: report results and **ask before committing** — never auto-commit. No kit asset is
|
|
71
|
+
ever deleted.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
21
75
|
## Two modes
|
|
22
76
|
|
|
23
77
|
Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to guard against bootstrapping over a live system, but the user makes the final call.
|
|
@@ -29,6 +83,8 @@ Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to
|
|
|
29
83
|
|
|
30
84
|
> Bundled sources below (templates, scripts) live in **this skill's own directory** — `${CLAUDE_SKILL_DIR}/` in Claude Code, or the folder containing this `SKILL.md` in Codex / other agents. Use that as the copy/read source; the working directory is the **target project**, not the skill.
|
|
31
85
|
|
|
86
|
+
> The three setup questions (steps 2–4) are decisions only the user can make and are hard to reverse after a commit. Ask each as a **structured multiple-choice prompt where your agent supports it** (`AskUserQuestion` in Claude Code — one option per choice, recommended one first), otherwise in prose — and **wait for the answer before writing anything**.
|
|
87
|
+
|
|
32
88
|
1. **Recon (read-only).** Before writing anything:
|
|
33
89
|
- `package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml` → stack, package manager, scripts.
|
|
34
90
|
- `ls -la` root → `README`, existing `AGENTS.md`/`CLAUDE.md`, CI configs, linter/formatter configs.
|
|
@@ -36,15 +92,20 @@ Pick the mode from the user's invocation. Auto-detect an existing `docs/ai/` to
|
|
|
36
92
|
- `src/` (or equivalent) 2–3 levels deep → modules, routes/pages, components, services, types.
|
|
37
93
|
- Tests (framework, location, E2E?) and linter rules.
|
|
38
94
|
- Record: stack, package manager, daily commands (`dev`/`test`/`lint`/`type-check`), routes/pages, architecture layers.
|
|
39
|
-
2. **Choose visibility — ASK the user explicitly and wait for the answer, before writing anything.** This decides what gets tracked and is hard to reverse after a commit, so never assume the default silently: `visible` (committed — canonical, recommended) or `hidden` (in-tree, hidden via `~/.gitignore_global`). See
|
|
40
|
-
3. **Choose conversational language — ASK the user explicitly and wait for the answer.** Which language should the agent *talk to them* in — questions, explanations, summaries, status updates? Offer the language they're already writing in as the default. Carry the answer into the `{{COMM_LANGUAGE}}` slot of the *Communication language* block when `AGENTS.md` is created (step 5). See
|
|
41
|
-
4. **Choose agent attribution — ASK the user explicitly and wait for the answer.** May the agent attribute work to itself / to AI — `Co-Authored-By` trailers, "Generated with …" footers, "AI"/agent/model mentions in code, comments, commit messages, PR titles/bodies, or docs? **Default to `off`** (no agent/AI mention anywhere) unless they opt in — people are routinely surprised to find an AI listed as a repo contributor. Carry the answer into the `{{AGENT_ATTRIBUTION}}` slot of the *Attribution* block when `AGENTS.md` is created (step 5). **If `off` and the project uses Claude Code**, also set `"includeCoAuthoredBy": false` in the project's `.claude/settings.json` (create it if absent) — the trailer is added by the harness, so a doc directive alone won't stop it. See
|
|
95
|
+
2. **Choose visibility — ASK the user explicitly and wait for the answer, before writing anything.** This decides what gets tracked and is hard to reverse after a commit, so never assume the default silently: `visible` (committed — canonical, recommended) or `hidden` (in-tree, hidden via `~/.gitignore_global`). See [Visibility contract](references/contracts.md#visibility-contract).
|
|
96
|
+
3. **Choose conversational language — ASK the user explicitly and wait for the answer.** Which language should the agent *talk to them* in — questions, explanations, summaries, status updates? Offer the language they're already writing in as the default. Carry the answer into the `{{COMM_LANGUAGE}}` slot of the *Communication language* block when `AGENTS.md` is created (step 5). See [Communication contract](references/contracts.md#communication-contract). This sets the **dialogue** language only — never the files.
|
|
97
|
+
4. **Choose agent attribution — ASK the user explicitly and wait for the answer.** May the agent attribute work to itself / to AI — `Co-Authored-By` trailers, "Generated with …" footers, "AI"/agent/model mentions in code, comments, commit messages, PR titles/bodies, or docs? **Default to `off`** (no agent/AI mention anywhere) unless they opt in — people are routinely surprised to find an AI listed as a repo contributor. Carry the answer into the `{{AGENT_ATTRIBUTION}}` slot of the *Attribution* block when `AGENTS.md` is created (step 5). **If `off` and the project uses Claude Code**, also set `"includeCoAuthoredBy": false` in the project's `.claude/settings.json` (create it if absent) — the trailer is added by the harness, so a doc directive alone won't stop it. See [Attribution contract](references/contracts.md#attribution-contract).
|
|
42
98
|
5. **Entry-point doc.** If `AGENTS.md` / `CLAUDE.md` already exist (step-1 recon), do **not** overwrite — show the user and ask whether to merge or replace. Otherwise create `AGENTS.md` (the cross-agent standard — Codex / Cursor / Devin Desktop / Copilot read it natively) from `${CLAUDE_SKILL_DIR}/references/templates/AGENTS.md`, and symlink `CLAUDE.md -> AGENTS.md` (`ln -s AGENTS.md CLAUDE.md`) for Claude Code — single source, no duplication. For nested context, add a subdir `AGENTS.md` (+ a `CLAUDE.md` symlink beside it for Claude Code).
|
|
43
99
|
6. **Deploy `docs/ai/`.** Create the 11 files + `pages/` from `${CLAUDE_SKILL_DIR}/references/templates/`. Keep each file's frontmatter (`type / lastUpdated / scope / staleAfter / owner / maxLines`).
|
|
44
100
|
7. **Fill templates** per the table below.
|
|
45
101
|
8. **Install enforcement (Node projects).** Copy `${CLAUDE_SKILL_DIR}/references/scripts/*.mjs` (+ `*.test.mjs`) into the project's `scripts/`. They self-configure (project name from `package.json`, hierarchical/on-demand sections auto-discovered). **If the project has no Node runtime** (step-1 recon), skip this step and the hook in step 9 — follow the cap/archive/index policy manually, or port the scripts to the project's language.
|
|
46
102
|
9. **Wire / hide** per visibility (see contract). Install the pre-commit hook (Node projects): `node scripts/install-git-hooks.mjs`. If the installer reports a pre-existing non-marker hook, stop and ask the user to merge it manually rather than overwriting.
|
|
47
|
-
10. **Stamp
|
|
103
|
+
10. **Stamp the deployment lineage.** Write the **deployment-lineage head** into
|
|
104
|
+
`docs/ai/.workflow-version` (one semver line). The lineage head is **`1.3.0`** — the shared
|
|
105
|
+
`agent-workflow` deployment lineage, **NOT** this kit's package version (`1.4.0`). The two are
|
|
106
|
+
independent axes: a packaging-only release bumps the package but leaves the lineage head until a
|
|
107
|
+
migration actually changes the deployed `docs/ai` structure. A stamp greater than the head →
|
|
108
|
+
STOP (never downgrade).
|
|
48
109
|
11. **Report & ask.** Show `tree docs/ai/`, 2–3 lines on what was filled with real data vs left as TODO, then **ask before committing** — never auto-commit.
|
|
49
110
|
|
|
50
111
|
Fill strategy:
|
|
@@ -59,53 +120,33 @@ Fill strategy:
|
|
|
59
120
|
|
|
60
121
|
### Mode: upgrade
|
|
61
122
|
|
|
62
|
-
1. Read `docs/ai/.workflow-version` (the project's stamped
|
|
63
|
-
2. Compare to this
|
|
123
|
+
1. Read `docs/ai/.workflow-version` (the project's stamped lineage). If missing, treat as a pre-versioned deployment and offer to re-bootstrap conservatively.
|
|
124
|
+
2. Compare to the **deployment-lineage head** (`1.3.0` — NOT this kit's package version). If equal → report "up to date" and stop. If the stamp is **greater than the head** or unparseable → **STOP and report** (never downgrade).
|
|
64
125
|
3. Show the relevant `${CLAUDE_SKILL_DIR}/CHANGELOG.md` diff (entries newer than the project's stamp).
|
|
65
126
|
4. Apply `${CLAUDE_SKILL_DIR}/migrations/<version>-<slug>.md` in **semver order**, only those newer than the project's stamp. Migrations are **idempotent** — safe to re-run.
|
|
66
|
-
5. Reconcile drift: add any kernel files/scripts the project is missing; never clobber project-authored content (their `decisions.md`, `known_issues.md`, page specs stay). If `AGENTS.md` has no *Communication language* block (pre-1.1.0 deployment), **ask the user their conversational language** and insert the block — see `migrations/1.1.0-communication-language.md`. If it has no *Attribution* block (pre-1.2.0 deployment), **ask whether the agent may attribute work to itself / AI** and insert the block (defaulting to `off`) — see `migrations/1.2.0-agent-attribution.md`.
|
|
67
|
-
6. Re-stamp `docs/ai/.workflow-version` to the
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Visibility contract
|
|
72
|
-
|
|
73
|
-
The user chooses at bootstrap whether the AI artifacts are visible in the repo or hidden — an **explicit up-front question** (step 2), never an assumed default. The two modes then diverge:
|
|
74
|
-
|
|
75
|
-
- **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.
|
|
76
|
-
- **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/.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.
|
|
77
|
-
|
|
78
|
-
Not in this version: a fully-external hidden mode (artifacts relocated outside the repo tree). Deferred to a later release + migration.
|
|
127
|
+
5. Reconcile drift: add any kernel files/scripts the project is missing; never clobber project-authored content (their `decisions.md`, `known_issues.md`, page specs stay). Any user question a migration raises follows the same rule as bootstrap — **structured multiple-choice where supported** (`AskUserQuestion` in Claude Code), otherwise prose. If `AGENTS.md` has no *Communication language* block (pre-1.1.0 deployment), **ask the user their conversational language** and insert the block — see `migrations/1.1.0-communication-language.md`. If it has no *Attribution* block (pre-1.2.0 deployment), **ask whether the agent may attribute work to itself / AI** and insert the block (defaulting to `off`) — see `migrations/1.2.0-agent-attribution.md`.
|
|
128
|
+
6. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0`, not the package version). Report changes; **ask before committing**.
|
|
79
129
|
|
|
80
130
|
---
|
|
81
131
|
|
|
82
|
-
##
|
|
83
|
-
|
|
84
|
-
The user chooses at bootstrap (step 3) which language the agent **talks to them** in. The choice is recorded in the *Communication language* block of the project's `AGENTS.md`, so every agent that reads the entry point honours it — and stops drifting between languages mid-session.
|
|
85
|
-
|
|
86
|
-
Scope — **dialogue only**:
|
|
132
|
+
## Gotchas
|
|
87
133
|
|
|
88
|
-
-
|
|
89
|
-
- **Always in their source language (usually English)** — code, identifiers, file paths, shell commands, log/console output, error strings, config keys, and abbreviations/acronyms. Translating these breaks copy-paste, search, and tooling.
|
|
90
|
-
- **Files stay English** — the deployed `docs/ai/` files, `AGENTS.md`, and this kernel are English-only regardless of the chosen language (cross-agent / cross-team portability). The conversational language is about the *chat*, not the *artifacts*.
|
|
134
|
+
The non-obvious traps — scan these before bootstrapping or upgrading. Each is also enforced inline in the procedure above; this is the consolidated high-signal list.
|
|
91
135
|
|
|
92
|
-
|
|
136
|
+
- **Source vs target directory.** Templates and scripts are read from the skill's own dir (`${CLAUDE_SKILL_DIR}/` in Claude Code, the `SKILL.md` folder elsewhere). The **working directory is the target project** — never write kernel files back into the skill.
|
|
137
|
+
- **The `Co-Authored-By` trailer is added by the harness, not by prose.** When attribution is `off`, a doc directive alone won't stop it — for Claude Code you **must** also set `"includeCoAuthoredBy": false` in the project's `.claude/settings.json` (create it if absent). Other tools: disable their equivalent co-author/footer setting.
|
|
138
|
+
- **Hidden mode must never touch `package.json`.** Editing it is a *tracked* change and leaks the whole system. Hidden mode wires nothing into `package.json`; the pre-commit hook (untracked in `.git/hooks/`) calls `node scripts/<x>.mjs` directly. After hiding, **verify `git status` shows the artifacts as ignored**.
|
|
139
|
+
- **`CLAUDE.md` is a symlink, not a copy.** `ln -s AGENTS.md CLAUDE.md` — single source, no duplication. A copy drifts; a symlink can't.
|
|
140
|
+
- **Never overwrite an existing entry point or hook.** If `AGENTS.md` / `CLAUDE.md` already exist, or the installer reports a pre-existing non-marker git hook, **stop and ask** the user to merge vs replace — don't clobber.
|
|
141
|
+
- **No Node runtime → skip enforcement.** If the project has no Node (recon step 1), skip bootstrap steps 8–9 (scripts + hook) and follow the cap/archive/index policy manually, or port the scripts to the project's language.
|
|
142
|
+
- **Conversational language never translates artifacts.** It governs *dialogue only*. Code, identifiers, paths, commands, log output, abbreviations, and every deployed `docs/ai/` / `AGENTS.md` file stay in their source language. See [Communication contract](references/contracts.md#communication-contract).
|
|
143
|
+
- **Never auto-commit.** Report quality-gate results and wait for explicit approval — in both modes.
|
|
93
144
|
|
|
94
145
|
---
|
|
95
146
|
|
|
96
|
-
##
|
|
97
|
-
|
|
98
|
-
The user chooses at bootstrap (step 4) whether the agent may **attribute work to itself or to AI**. The choice is recorded in the *Attribution* block of the project's `AGENTS.md`, so every agent that reads the entry point honours it. **Default is `off`** — people are routinely surprised to find an AI listed as a repo contributor (a `Co-Authored-By` trailer is enough to do it), so opt-in, never opt-out.
|
|
99
|
-
|
|
100
|
-
When attribution is **`off`**, no mention of the agent, AI, or the model appears **anywhere**:
|
|
101
|
-
|
|
102
|
-
- **No `Co-Authored-By` trailers** and **no "Generated with …" footers** on commits or PRs.
|
|
103
|
-
- **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.
|
|
104
|
-
- **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 kit also sets `"includeCoAuthoredBy": false` in the project's `.claude/settings.json`. Other tools: disable their equivalent co-author/footer setting if present.
|
|
105
|
-
|
|
106
|
-
When **`on`**, the agent may add its standard trailer / footer per the user's tooling defaults. This block is about *attribution*, not authorship of the actual changes — quality, tests, and the "ask before commit" rule are unchanged either way.
|
|
147
|
+
## Setup contracts
|
|
107
148
|
|
|
108
|
-
|
|
149
|
+
The three setup choices — **visibility** (step 2), **conversational language** (step 3), and **agent attribution** (step 4) — each have a full contract in [`references/contracts.md`](references/contracts.md). Load it when you need the complete rule (e.g. while filling the matching `AGENTS.md` block, or when an `upgrade` migration touches one). Defaults, in brief: visibility = `visible` (committed); language = whatever the user is already writing in; attribution = `off`. Ask each as a structured multiple-choice prompt where supported (`AskUserQuestion` in Claude Code), otherwise in prose.
|
|
109
150
|
|
|
110
151
|
---
|
|
111
152
|
|
|
@@ -149,9 +190,12 @@ Deploy these into `AGENTS.md`; remove rows that don't apply to the stack.
|
|
|
149
190
|
|
|
150
191
|
## References
|
|
151
192
|
|
|
193
|
+
- [`references/contracts.md`](references/contracts.md) — the three setup contracts (visibility, conversational language, agent attribution) in full; the *Setup contracts* section above points here.
|
|
152
194
|
- [`references/planning.md`](references/planning.md) — plan vocabulary (Plan→Phase→Step→Substep), lifecycle, `queue.md` series-index, mandatory Cleanup, session-continuity heuristic.
|
|
153
195
|
- [`references/templates/`](references/templates/) — stack-agnostic `AGENTS.md`, `agent_rules.md`, and all `docs/ai/` files to deploy.
|
|
154
196
|
- [`references/scripts/`](references/scripts/) — the Node enforcement scripts (caps + staleness + index-freshness gate, 3-tier archive, hook installer) and their unit tests.
|
|
155
197
|
- [`migrations/`](migrations/) — per-version upgrade steps; see `migrations/README.md`.
|
|
156
198
|
- [`launchers/`](launchers/) — run the bootstrapper from non-Claude agents (`SKILL.md` is a native Codex skill; a Devin Desktop workflow launcher + install script). See `launchers/README.md`.
|
|
199
|
+
- [`tools/`](tools/) — the family-wide tooling the kit **owns and ships**: `manifest/{schema.md,validate.mjs}` (the `capability.json` schema + the validator the kit runs as the memory detector, and root CI invokes), `delegation.mjs` (the executable delegate/fallback decision + hand-off plan), `inject-methodology.mjs` + `methodology-slot.md` (the bounded slot injection), and `release-scan.mjs` (the attribution-off release gate). See [`tools/manifest/schema.md`](tools/manifest/schema.md).
|
|
200
|
+
- [`capability.json`](capability.json) — the kit's own `agent-workflow` family manifest (`kind: composition-root`).
|
|
157
201
|
- [`CHANGELOG.md`](CHANGELOG.md) — version history of this kernel.
|
package/bin/install.mjs
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
// Dependency-free, Node >= 18.
|
|
20
20
|
|
|
21
21
|
import { readFile, mkdir, readdir, copyFile, lstat, readlink, symlink } from 'node:fs/promises';
|
|
22
|
-
import { existsSync } from 'node:fs';
|
|
23
|
-
import { dirname, join, resolve } from 'node:path';
|
|
22
|
+
import { existsSync, lstatSync } from 'node:fs';
|
|
23
|
+
import { dirname, join, resolve, relative, sep, isAbsolute } from 'node:path';
|
|
24
24
|
import { fileURLToPath } from 'node:url';
|
|
25
25
|
import { homedir } from 'node:os';
|
|
26
26
|
import { spawnSync } from 'node:child_process';
|
|
@@ -29,7 +29,18 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
29
29
|
const PKG_ROOT = resolve(__dirname, '..');
|
|
30
30
|
|
|
31
31
|
// The deployable skill = everything except the npm wrapper (package.json, bin/).
|
|
32
|
-
|
|
32
|
+
// capability.json (the family manifest) + tools/ (the family schema + validator the kit runs
|
|
33
|
+
// as the memory detector) must land in the installed skill dir too.
|
|
34
|
+
const PAYLOAD = [
|
|
35
|
+
'SKILL.md',
|
|
36
|
+
'README.md',
|
|
37
|
+
'CHANGELOG.md',
|
|
38
|
+
'capability.json',
|
|
39
|
+
'references',
|
|
40
|
+
'launchers',
|
|
41
|
+
'migrations',
|
|
42
|
+
'tools',
|
|
43
|
+
];
|
|
33
44
|
|
|
34
45
|
const tildify = (path) => path.replace(homedir(), '~');
|
|
35
46
|
|
|
@@ -42,7 +53,39 @@ const readVersion = async () => {
|
|
|
42
53
|
}
|
|
43
54
|
};
|
|
44
55
|
|
|
45
|
-
|
|
56
|
+
// lstat without following symlinks; null when absent. existsSync FOLLOWS symlinks (so a
|
|
57
|
+
// *dangling* symlink reads as absent) — lstat is what lets the guard catch a dangling dest symlink.
|
|
58
|
+
const lstatNoFollow = (path) => {
|
|
59
|
+
try {
|
|
60
|
+
return lstatSync(path);
|
|
61
|
+
} catch (err) {
|
|
62
|
+
if (err && err.code === 'ENOENT') return null;
|
|
63
|
+
throw err; // EACCES/EIO etc. must NOT fail open (be read as "not a symlink")
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Symlink-traversal guard: refuse to write *through* any symlink at or above `dest` within
|
|
68
|
+
// `root` (root / intermediate dir / leaf, including a dangling one), or to a dest outside `root`.
|
|
69
|
+
const assertContainedRealPath = (root, dest) => {
|
|
70
|
+
const rel = relative(root, dest);
|
|
71
|
+
if (rel.startsWith('..') || isAbsolute(rel)) {
|
|
72
|
+
throw new Error(`[agent-workflow-kit] refusing to write outside the target dir: ${dest}`);
|
|
73
|
+
}
|
|
74
|
+
if (lstatNoFollow(root)?.isSymbolicLink()) {
|
|
75
|
+
throw new Error(`[agent-workflow-kit] refusing to install into a symlinked target dir: ${root}`);
|
|
76
|
+
}
|
|
77
|
+
const walk = (acc, part) => {
|
|
78
|
+
const cur = join(acc, part);
|
|
79
|
+
if (lstatNoFollow(cur)?.isSymbolicLink()) {
|
|
80
|
+
throw new Error(`[agent-workflow-kit] refusing to write through a symlink at ${cur} (would escape ${root}).`);
|
|
81
|
+
}
|
|
82
|
+
return cur;
|
|
83
|
+
};
|
|
84
|
+
rel.split(sep).filter(Boolean).reduce(walk, root);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const copyRecursive = async (src, dest, root) => {
|
|
88
|
+
assertContainedRealPath(root, dest); // never write through a dest symlink (root/intermediate/leaf)
|
|
46
89
|
const stat = await lstat(src);
|
|
47
90
|
if (stat.isSymbolicLink()) {
|
|
48
91
|
if (existsSync(dest)) return; // additive: never delete/replace an existing entry
|
|
@@ -51,7 +94,7 @@ const copyRecursive = async (src, dest) => {
|
|
|
51
94
|
} else if (stat.isDirectory()) {
|
|
52
95
|
await mkdir(dest, { recursive: true });
|
|
53
96
|
const entries = await readdir(src);
|
|
54
|
-
await Promise.all(entries.map((entry) => copyRecursive(join(src, entry), join(dest, entry))));
|
|
97
|
+
await Promise.all(entries.map((entry) => copyRecursive(join(src, entry), join(dest, entry), root)));
|
|
55
98
|
} else {
|
|
56
99
|
await mkdir(dirname(dest), { recursive: true });
|
|
57
100
|
await copyFile(src, dest);
|
|
@@ -105,17 +148,25 @@ const main = async () => {
|
|
|
105
148
|
if (args.help) return printHelp(version);
|
|
106
149
|
if (args.version) return console.log(version);
|
|
107
150
|
|
|
108
|
-
|
|
109
|
-
|
|
151
|
+
// Critical payload must be present, or the install would silently ship a kit that can't run
|
|
152
|
+
// its own detector (tools/) or family contract (capability.json). Fail loudly, don't filter away.
|
|
153
|
+
const REQUIRED = ['SKILL.md', 'capability.json', 'references', 'tools', 'migrations'];
|
|
154
|
+
const missing = REQUIRED.filter((entry) => !existsSync(resolve(PKG_ROOT, entry)));
|
|
155
|
+
if (missing.length > 0) {
|
|
156
|
+
console.error(`[agent-workflow-kit] package payload incomplete — missing: ${missing.join(', ')} (corrupt install?)`);
|
|
110
157
|
process.exit(1);
|
|
111
158
|
}
|
|
112
159
|
|
|
113
160
|
const target = resolveTarget(args.dir);
|
|
114
161
|
const wasPresent = existsSync(resolve(target, 'SKILL.md'));
|
|
162
|
+
if (lstatNoFollow(target)?.isSymbolicLink()) {
|
|
163
|
+
console.error(`[agent-workflow-kit] target dir is a symlink — refusing to write through it: ${tildify(target)}`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
115
166
|
await mkdir(target, { recursive: true });
|
|
116
167
|
await Promise.all(
|
|
117
168
|
PAYLOAD.filter((entry) => existsSync(resolve(PKG_ROOT, entry))).map((entry) =>
|
|
118
|
-
copyRecursive(resolve(PKG_ROOT, entry), resolve(target, entry)),
|
|
169
|
+
copyRecursive(resolve(PKG_ROOT, entry), resolve(target, entry), target),
|
|
119
170
|
),
|
|
120
171
|
);
|
|
121
172
|
console.log(`[agent-workflow-kit] ${wasPresent ? 'updated the kit to' : 'installed'} v${version} -> ${tildify(target)}`);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { mkdtemp, rm, mkdir, symlink, readdir } from 'node:fs/promises';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { tmpdir } from 'node:os';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const INSTALLER = join(dirname(fileURLToPath(import.meta.url)), 'install.mjs');
|
|
11
|
+
// --no-launchers so the test never wires Codex/Devin on the host.
|
|
12
|
+
const runInstaller = (target) =>
|
|
13
|
+
spawnSync(process.execPath, [INSTALLER, '--dir', target, '--no-launchers'], { encoding: 'utf8' });
|
|
14
|
+
|
|
15
|
+
describe('kit installer — payload + symlink-traversal hardening', () => {
|
|
16
|
+
let dir;
|
|
17
|
+
beforeEach(async () => {
|
|
18
|
+
dir = await mkdtemp(join(tmpdir(), 'aw-kit-install-'));
|
|
19
|
+
});
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
await rm(dir, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('installs the critical payload (capability.json + tools/ + references/) and not the npm wrapper', () => {
|
|
25
|
+
const target = join(dir, 'agent-workflow-kit');
|
|
26
|
+
const res = runInstaller(target);
|
|
27
|
+
assert.equal(res.status, 0, res.stderr);
|
|
28
|
+
for (const f of ['SKILL.md', 'capability.json', 'tools/manifest/validate.mjs', 'tools/delegation.mjs', 'references']) {
|
|
29
|
+
assert.ok(existsSync(join(target, f)), `missing installed entry: ${f}`);
|
|
30
|
+
}
|
|
31
|
+
assert.equal(existsSync(join(target, 'bin/install.mjs')), false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('refuses to write through a symlinked INTERMEDIATE dest component (no leak)', async () => {
|
|
35
|
+
const target = join(dir, 'target');
|
|
36
|
+
const evil = join(dir, 'evil');
|
|
37
|
+
await mkdir(target, { recursive: true });
|
|
38
|
+
await mkdir(evil, { recursive: true });
|
|
39
|
+
await symlink(evil, join(target, 'references'));
|
|
40
|
+
const res = runInstaller(target);
|
|
41
|
+
assert.notEqual(res.status, 0);
|
|
42
|
+
assert.match(res.stderr, /symlink/i);
|
|
43
|
+
assert.deepEqual(await readdir(evil), []);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('refuses a DANGLING destination symlink', async () => {
|
|
47
|
+
const target = join(dir, 'target');
|
|
48
|
+
await mkdir(target, { recursive: true });
|
|
49
|
+
await symlink(join(dir, 'nowhere'), join(target, 'references'));
|
|
50
|
+
const res = runInstaller(target);
|
|
51
|
+
assert.notEqual(res.status, 0);
|
|
52
|
+
assert.match(res.stderr, /symlink/i);
|
|
53
|
+
assert.equal(existsSync(join(dir, 'nowhere')), false);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('refuses a symlinked TARGET root (no leak)', async () => {
|
|
57
|
+
const real = join(dir, 'real');
|
|
58
|
+
const root = join(dir, 'root');
|
|
59
|
+
await mkdir(real, { recursive: true });
|
|
60
|
+
await symlink(real, root);
|
|
61
|
+
const res = runInstaller(root);
|
|
62
|
+
assert.notEqual(res.status, 0);
|
|
63
|
+
assert.match(res.stderr, /symlink/i);
|
|
64
|
+
assert.deepEqual(await readdir(real), []);
|
|
65
|
+
});
|
|
66
|
+
});
|
package/capability.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"family": "agent-workflow",
|
|
3
|
+
"schema": 1,
|
|
4
|
+
"name": "agent-workflow-kit",
|
|
5
|
+
"kind": "composition-root",
|
|
6
|
+
"version": "1.4.0",
|
|
7
|
+
"provides": [],
|
|
8
|
+
"roles": {},
|
|
9
|
+
"detect": {
|
|
10
|
+
"installed": {
|
|
11
|
+
"env": "AGENT_WORKFLOW_KIT_DIR",
|
|
12
|
+
"default": "~/.claude/skills/agent-workflow-kit",
|
|
13
|
+
"file": "SKILL.md"
|
|
14
|
+
},
|
|
15
|
+
"deployed": { "file": "docs/ai/.workflow-version" }
|
|
16
|
+
},
|
|
17
|
+
"install": { "npm": "@sabaiway/agent-workflow-kit" },
|
|
18
|
+
"cost": "none",
|
|
19
|
+
"quota": null,
|
|
20
|
+
"provenance": { "author": "sabaiway", "source": "github:sabaiway/agent-workflow" }
|
|
21
|
+
}
|
|
@@ -10,8 +10,8 @@ language* block in the project's `AGENTS.md` so every agent that reads the entry
|
|
|
10
10
|
honours it instead of drifting between languages. Pre-1.1.0 deployments have no such block.
|
|
11
11
|
|
|
12
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`
|
|
14
|
-
|
|
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
15
|
|
|
16
16
|
## Steps
|
|
17
17
|
|
|
@@ -29,8 +29,8 @@ English (the kernel is English-only). This migration changes *one* doc block, no
|
|
|
29
29
|
## 🗣️ Communication language
|
|
30
30
|
|
|
31
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**
|
|
33
|
-
> This sets the **dialogue** language only
|
|
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
34
|
```
|
|
35
35
|
|
|
36
36
|
5. Keep `AGENTS.md` within its ≤100-line budget (the block is ~6 lines; it fits). Do **not**
|
|
@@ -43,7 +43,7 @@ English (the kernel is English-only). This migration changes *one* doc block, no
|
|
|
43
43
|
- The docs cap-validator is still green (`node scripts/check-docs-size.mjs` for Node projects)
|
|
44
44
|
— the entry point did not bust its line budget.
|
|
45
45
|
- From now on the agent's replies are in the chosen language; paths/commands/identifiers
|
|
46
|
-
remain
|
|
46
|
+
remain in their source language.
|
|
47
47
|
|
|
48
48
|
## Rollback
|
|
49
49
|
|
package/migrations/README.md
CHANGED
|
@@ -10,7 +10,8 @@ releases add files/templates, which `upgrade` reconciles without a migration.
|
|
|
10
10
|
1. Read the project's stamped version from `docs/ai/.workflow-version`.
|
|
11
11
|
2. Select every migration whose `<version>` is **strictly newer** than the stamp.
|
|
12
12
|
3. Apply them in **ascending semver order**.
|
|
13
|
-
4. Re-stamp `docs/ai/.workflow-version` to the
|
|
13
|
+
4. Re-stamp `docs/ai/.workflow-version` to the **deployment-lineage head** (`1.3.0` today — the
|
|
14
|
+
shared lineage, **not** this skill's package version `1.4.0`). A stamp greater than the head → STOP.
|
|
14
15
|
|
|
15
16
|
## Authoring rules
|
|
16
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sabaiway/agent-workflow-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Portable, cross-agent memory & workflow for AI coding agents — Claude Code, Codex, Cursor, Devin Desktop. One command deploys an AGENTS.md entry point + docs/ai context with cap/archive/index enforcement into any repo.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -25,13 +25,14 @@
|
|
|
25
25
|
"memory",
|
|
26
26
|
"developer-tools"
|
|
27
27
|
],
|
|
28
|
-
"homepage": "https://github.com/sabaiway/agent-workflow
|
|
28
|
+
"homepage": "https://github.com/sabaiway/agent-workflow#readme",
|
|
29
29
|
"bugs": {
|
|
30
|
-
"url": "https://github.com/sabaiway/agent-workflow
|
|
30
|
+
"url": "https://github.com/sabaiway/agent-workflow/issues"
|
|
31
31
|
},
|
|
32
32
|
"repository": {
|
|
33
33
|
"type": "git",
|
|
34
|
-
"url": "git+https://github.com/sabaiway/agent-workflow
|
|
34
|
+
"url": "git+https://github.com/sabaiway/agent-workflow.git",
|
|
35
|
+
"directory": "agent-workflow-kit"
|
|
35
36
|
},
|
|
36
37
|
"license": "MIT",
|
|
37
38
|
"author": "sabaiway",
|
|
@@ -44,9 +45,11 @@
|
|
|
44
45
|
"SKILL.md",
|
|
45
46
|
"README.md",
|
|
46
47
|
"CHANGELOG.md",
|
|
48
|
+
"capability.json",
|
|
47
49
|
"references/",
|
|
48
50
|
"launchers/",
|
|
49
|
-
"migrations/"
|
|
51
|
+
"migrations/",
|
|
52
|
+
"tools/"
|
|
50
53
|
],
|
|
51
54
|
"engines": {
|
|
52
55
|
"node": ">=18"
|