yadflow 2.3.0 → 2.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 CHANGED
@@ -1,10 +1,28 @@
1
- # [2.3.0](https://github.com/abdelrahmannasr/yadflow/compare/v2.2.0...v2.3.0) (2026-06-13)
1
+ # [2.4.0](https://github.com/abdelrahmannasr/yadflow/compare/v2.3.0...v2.4.0) (2026-06-13)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * address CodeRabbit review on PR [#48](https://github.com/abdelrahmannasr/yadflow/issues/48) ([2f182f7](https://github.com/abdelrahmannasr/yadflow/commit/2f182f72b68e226196b6190802771b0e12b585f9))
7
+
8
+
9
+ ### Features
10
+
11
+ * add DeepTutor learning layer across all SDLC stages ([bd8d4ea](https://github.com/abdelrahmannasr/yadflow/commit/bd8d4eaaa0258242a62ed1b131f7e3f74506af64))
12
+ * make learning-layer output local-only (never committed or pushed) ([aa8f74e](https://github.com/abdelrahmannasr/yadflow/commit/aa8f74eb61855d3a663810a0c68cf8e37fbedd66))
13
+
14
+ # [2.2.0](https://github.com/abdelrahmannasr/yadflow/compare/v2.1.0...v2.2.0) (2026-06-14)
2
15
 
3
16
 
4
17
  ### Features
5
18
 
6
19
  * add parallel test-cases step with pluggable testing-tool connection ([#45](https://github.com/abdelrahmannasr/yadflow/issues/45)) ([19c282f](https://github.com/abdelrahmannasr/yadflow/commit/19c282f6bd737364bca122179b05de8ea94493a9))
7
20
 
21
+
22
+ ### Continuous Integration
23
+
24
+ * wire the hub's gate-sync + verified-commits CI and stamp the CLI version ([#46](https://github.com/abdelrahmannasr/yadflow/issues/46)) ([c856398](https://github.com/abdelrahmannasr/yadflow/commit/c856398a213b17aebea9c46204dbf955b92ea9cf))
25
+
8
26
  # [1.1.0](https://github.com/abdelrahmannasr/sdlc-workflow/compare/v1.0.3...v1.1.0) (2026-06-09)
9
27
 
10
28
 
package/README.md CHANGED
@@ -51,6 +51,8 @@ human**. Detailed walkthroughs for each phase follow below.
51
51
  | `skills/yad-stories/` | Front state 7: break the epic into repo-tagged stories with stable `EP-<slug>-S0N` IDs. |
52
52
  | `skills/yad-test-cases/` | Front state 9: with the test architect author `test-cases.md`; implement the automation in the connected testing tool, or produce artifacts only. |
53
53
  | `skills/yad-connect-repos/` | Connect code repos to the hub (GitHub/GitLab, local-user auth); cache a Repomix pack + **code-map** per repo so the front phases are code-aware. |
54
+ | `skills/yad-connect-learning/` | Connect a learning tool (DeepTutor-first, pluggable) — a CLI subprocess like Repomix; record `.sdlc/learning.json` + an optional grounded knowledge base. |
55
+ | `skills/yad-learn/` | The cross-cutting **learning layer**: tutor any member, at any stage, in the context of what's being built; records a personal, local-only skills log (gitignored, never committed/pushed). Opt-in, never gates. |
54
56
  | `skills/yad-review-gate/` | The reusable **team review + approve gate** (used for all five reviews). |
55
57
  | `skills/yad-spec/` | Build Step A: run the Spec Kit ceremony once per story per repo → `specs/<story-id>/`. |
56
58
  | `skills/yad-implement/` | Build Step B: implement ONE atomic task as a small diff on its own branch. |
@@ -123,10 +125,10 @@ a manual `yad gate sync` racing CI, or GitLab pipelines — two simultaneous syn
123
125
  *commits* via the rebase retry but each works from the state it read at start, so the rarer of two
124
126
  simultaneous advancements can be lost; the next event or scheduled sweep re-syncs and converges.
125
127
 
126
- ### What `setup` walks you through (9 steps)
128
+ ### What `setup` walks you through (10 steps)
127
129
 
128
130
  1. **Preflight** — confirm the hub is a git repo (offers `git init`); check `git`/`node`/`npx`.
129
- 2. **Install the module** — copy all 20 `yad-*` skills into the IDE skill dirs you pick
131
+ 2. **Install the module** — copy all 22 `yad-*` skills into the IDE skill dirs you pick
130
132
  (`.claude/`, `.agents/`, `.zencoder/`, `.opencode/`) and register `_bmad/sdlc/`.
131
133
  3. **Hub platform & roster** — detect GitHub/GitLab from the remote; record reviewers → `.sdlc/hub.json`.
132
134
  4. **Connect a design tool** — record the design tool (Figma / pencil / none) → `.sdlc/design.json` so
@@ -134,10 +136,13 @@ simultaneous advancements can be lost; the next event or scheduled sweep re-sync
134
136
  5. **Connect a testing tool** — record the testing tool (Playwright / cypress / pytest / none) →
135
137
  `.sdlc/testing.json` so the test-cases step can implement the automation; the MCP itself is confirmed
136
138
  later by `yad-connect-testing`.
137
- 6. **Connect code repos** — register each repo into `.sdlc/repos.json` and cache a Repomix pack.
138
- 7. **Wire each repo** CI gates, PR/MR template, and review-comment scaffold.
139
- 8. **AI review** — optionally write `.coderabbit.yaml`.
140
- 9. **Done** — stamp `.sdlc/cli-version.json` and hand off the AI-only steps (code-maps; first epic).
139
+ 6. **Connect a learning tool** — record the learning tool (DeepTutor / none) → `.sdlc/learning.json` so
140
+ the learning layer can tutor the team; the CLI + knowledge base are confirmed later by
141
+ `yad-connect-learning`.
142
+ 7. **Connect code repos** — register each repo into `.sdlc/repos.json` and cache a Repomix pack.
143
+ 8. **Wire each repo** — CI gates, PR/MR template, and review-comment scaffold.
144
+ 9. **AI review** — optionally write `.coderabbit.yaml`.
145
+ 10. **Done** — stamp `.sdlc/cli-version.json` and hand off the AI-only steps (code-maps; first epic).
141
146
 
142
147
  The deterministic file work runs automatically; the AI-only steps are handed to the Claude Code skills
143
148
  with a printed next-action. Re-run `… check --fix` any time the workflow updates — it never re-asks for
@@ -175,10 +180,11 @@ with a fix-it hint per finding. Failures carry stable, greppable codes, also pri
175
180
  | `YAD-CFG-001` | `hub.json` names an unknown platform | expected `github`, `gitlab`, or `null` — fix it or re-run `yad setup` |
176
181
  | `YAD-CFG-002` | `design.json` names an unknown design tool | expected one of `config.yaml` `design.tools` (e.g. `figma`, `pencil`), or `none` — fix it or re-run `yad setup` |
177
182
  | `YAD-CFG-003` | `testing.json` names an unknown testing tool | expected one of `config.yaml` `testing.tools` (e.g. `playwright`, `cypress`, `pytest`), or `none` — fix it or re-run `yad setup` |
183
+ | `YAD-CFG-004` | `learning.json` names an unknown learning tool | expected one of `config.yaml` `learning.tools` (e.g. `deeptutor`), or `none` — fix it or re-run `yad setup` |
178
184
 
179
185
  Filing a bug? Attach `yad doctor --json` — it contains no secrets (names, paths, and check results only).
180
186
 
181
- ## Agent skills (all 20)
187
+ ## Agent skills (all 22)
182
188
 
183
189
  The CLI **installs and wires** the module; the skills below are the **agents you invoke by name** in your
184
190
  AI IDE (e.g. *“run `yad-epic`”*) to actually do the work. State lives in files you can also edit
@@ -201,6 +207,25 @@ directly. Each skill stops at a gate and never auto-advances unless a step has *
201
207
  project/suite references in `.sdlc/testing.json` (local-user / MCP-session auth, no stored tokens),
202
208
  detecting the testing-tool MCP and degrading to artifacts-only when absent. Idempotent and
203
209
  refreshable; one connection per project.
210
+ - **`yad-connect-learning`** — Connects a learning/tutoring tool (DeepTutor-first, pluggable) so the
211
+ cross-cutting learning layer can tutor any team member in the context of what's being built. Records
212
+ the tool + an optional grounded knowledge base in `.sdlc/learning.json` (local-user auth, no stored
213
+ tokens), detecting the **DeepTutor CLI on PATH** (a subprocess like Repomix — DeepTutor ships no MCP)
214
+ and degrading to **harness-native** tutoring when absent. Idempotent and refreshable; one connection
215
+ per project.
216
+
217
+ ### The learning layer (cross-cutting — any member, any stage)
218
+
219
+ - **`yad-learn`** — At **any** SDLC stage, a team member can ask to learn a concept and be tutored *in
220
+ the context of what the team is building* — e.g. *"teach me why the architecture hash-locks the
221
+ contract surface"*. Routes the request to the connected learning tool (`.sdlc/learning.json`,
222
+ DeepTutor-first) grounded in the project knowledge base, or degrades to **harness-native** tutoring
223
+ (the harness model reading the artifacts) when nothing is connected — so it always works. Renders a
224
+ tutorial artifact and appends to a per-member **learning ledger** kept **local-only** (gitignored,
225
+ never committed or pushed — to the hub or any code repo) so it stays a private, personal **skills log**
226
+ (`yad-status` rolls up the local records). **Purely opt-in — it never blocks a gate** and
227
+ never touches epic state, approvals, or the contract lock. *AI builds, the hand decides* — and now the
228
+ hand can also learn, on demand, what it is deciding about.
204
229
 
205
230
  ### Front half — author the "thinking" (once per epic, human-gated)
206
231
 
@@ -297,17 +322,19 @@ detailed sections below expand every phase. Invoke a skill by name in your agent
297
322
 
298
323
  ### 0 — One-time setup
299
324
 
300
- > **Shortcut:** `npx yadflow setup` walks through steps 1, 4, 5 and 6 below
301
- > interactively (module install, hub detect + roster, connect repos, wire each repo). Run
302
- > `… check --fix` any time afterwards to reconcile. The manual steps below are the long-hand
303
- > equivalent and still work.
325
+ > **Shortcut:** `npx yadflow setup` runs the guided wizard interactively module install, hub
326
+ > detect + roster, connect a design/testing/learning tool (each optional), connect repos, wire each
327
+ > repo. Run `… check --fix` any time afterwards to reconcile. The manual steps below are the
328
+ > long-hand equivalent and still work.
304
329
 
305
330
  1. **Install the module:** `bash skills/sdlc/install.sh` (re-run after any BMAD update).
306
331
  2. **Have your code repo(s).** They are **separate git repos** (one `.git` each). For the demo they
307
332
  live under `demo-repos/<repo>/` — regenerate from `demo-repos/README.md`.
308
333
  3. **Optional tools** (the workflow degrades gracefully and records it if any are absent): **Spec Kit**
309
334
  (`/speckit.*`), **Impeccable** (`/impeccable …`), **Repomix** (`npx repomix`, used by
310
- `yad-connect-repos` and `yad-backfill`), **CodeRabbit** (advisory AI review).
335
+ `yad-connect-repos` and `yad-backfill`), **CodeRabbit** (advisory AI review), **DeepTutor**
336
+ (`deeptutor`, the learning layer's tutor — degrades to harness-native, used by `yad-connect-learning`
337
+ and `yad-learn`).
311
338
  4. **Wire each code repo once:** `yad-checks repo:<repo> action: wire` (installs the CI gates —
312
339
  *merges* with any existing CI, never clobbers), `yad-pr-template repo:<repo> action: wire` (PR/MR
313
340
  template + risk routing), `yad-review-comments repo:<repo> action: wire` (review-comment scaffold).
@@ -318,11 +345,16 @@ detailed sections below expand every phase. Invoke a skill by name in your agent
318
345
  (SSH or credential helper; GitHub or GitLab; no stored tokens). Re-run for any new repo. Freshness is a
319
346
  **human decision**: `yad repo list` shows fresh/stale, `yad repo refresh [name]` re-packs a moved repo
320
347
  (skills flag staleness and point here — they never silently re-pack). Greenfield → skip it.
321
- 6. **(Optional) Put the hub on a platform** so the front-half review runs through real PRs:
348
+ 6. **(Optional) Connect tools** so the matching steps do real work (each degrades gracefully and is
349
+ recorded if absent): `yad-connect-design action: connect` (Figma-first → `design.json`, lets
350
+ `yad-ui` materialize screens), `yad-connect-testing action: connect` (Playwright-first →
351
+ `testing.json`, lets `yad-test-cases` implement automation), `yad-connect-learning action: connect`
352
+ (DeepTutor-first → `learning.json`, powers the cross-cutting learning layer).
353
+ 7. **(Optional) Put the hub on a platform** so the front-half review runs through real PRs:
322
354
  `yad-connect-repos action: detect-hub`, then `action: roster` once per reviewer (login → SDLC
323
355
  name + role), and `yad-pr-template repo:hub action: wire` / `yad-review-comments repo:hub action:
324
356
  wire` / `yad-checks repo:hub action: wire`. With no hub platform the front gate just runs file-only.
325
- 7. **Conventions:** commits and PR/MR titles follow Conventional Commits (lowercase after the type), the
357
+ 8. **Conventions:** commits and PR/MR titles follow Conventional Commits (lowercase after the type), the
326
358
  human author owns each commit with an optional per-commit `Co-Authored-By` AI trailer — see
327
359
  [`CONTRIBUTING.md`](CONTRIBUTING.md).
328
360
 
package/cli/doctor.mjs CHANGED
@@ -5,7 +5,7 @@
5
5
  import path from 'node:path';
6
6
  import fs from 'node:fs';
7
7
  import { c, log, ok, info, warn, fail, hand, run, has, exists, readJSON, readJSONStrict } from './lib.mjs';
8
- import { VERSION, PROJECT_FILES, DESIGN_TOOLS, TESTING_TOOLS } from './manifest.mjs';
8
+ import { VERSION, PROJECT_FILES, DESIGN_TOOLS, TESTING_TOOLS, LEARNING_TOOLS } from './manifest.mjs';
9
9
  import { loadLedger, epicRoot } from './epic-state.mjs';
10
10
  import { gitHead } from './setup.mjs';
11
11
  import { cliFor } from './platform.mjs';
@@ -115,6 +115,28 @@ export function projectChecks(checks, root) {
115
115
  else check(checks, 'testing', 'project', 'warn', `testing: ${testing.tool} recorded but the MCP is not confirmed`, 'run `yad-connect-testing` in Claude Code to detect the MCP');
116
116
  }
117
117
 
118
+ // learning.json: parse + shape + tool + CLI confirmation (absent is the normal harness-native default —
119
+ // pre-feature projects have none, so silence rather than warn when the file does not exist). DeepTutor
120
+ // has no MCP, so `source` is deeptutor-cli (found on PATH) or harness-native (degraded).
121
+ const learningPath = path.join(root, PROJECT_FILES.learningConfig);
122
+ if (exists(learningPath)) {
123
+ let learning = null, learningBroken = false;
124
+ try {
125
+ learning = readJSONStrict(learningPath, null);
126
+ } catch (e) {
127
+ learningBroken = true;
128
+ check(checks, 'learning', 'project', 'fail', `${PROJECT_FILES.learningConfig} does not parse [${e.code || 'YAD-STATE-001'}]`, e.hint || 'fix the JSON or restore it from git');
129
+ }
130
+ if (learningBroken) { /* reported above */ }
131
+ else if (typeof learning !== 'object' || Array.isArray(learning) || learning === null) check(checks, 'learning', 'project', 'fail', `${PROJECT_FILES.learningConfig} has the wrong shape [YAD-STATE-002]`, 'expected a JSON object');
132
+ else if (learning.tool === 'none') check(checks, 'learning', 'project', 'ok', 'learning: harness-native');
133
+ else if (!LEARNING_TOOLS.includes(learning.tool)) check(checks, 'learning', 'project', 'fail', `${PROJECT_FILES.learningConfig}: unknown or missing learning tool '${learning.tool}' [YAD-CFG-004]`, `expected one of ${LEARNING_TOOLS.join(', ')}, or none`);
134
+ else if (learning.source === 'deeptutor-cli') check(checks, 'learning', 'project', 'ok', `learning: ${learning.tool} (${learning.source})`);
135
+ else if (learning.source === 'harness-native') check(checks, 'learning', 'project', 'warn', `learning: ${learning.tool} CLI unavailable — yad-learn tutors harness-native`, 'install the deeptutor CLI, then run `yad-connect-learning` (action: refresh)');
136
+ else if (learning.source == null) check(checks, 'learning', 'project', 'warn', `learning: ${learning.tool} recorded but the CLI is not confirmed`, 'run `yad-connect-learning` in Claude Code to detect the CLI');
137
+ else check(checks, 'learning', 'project', 'fail', `${PROJECT_FILES.learningConfig}: unknown source '${learning.source}' [YAD-STATE-002]`, 'expected deeptutor-cli, harness-native, or null');
138
+ }
139
+
118
140
  // repos.json: parse + every entry is a live git repo; staleness vs syncedHead
119
141
  let registry = { repos: [] };
120
142
  let regBroken = false;
package/cli/errors.mjs CHANGED
@@ -22,6 +22,7 @@ export const CODES = {
22
22
  'YAD-CFG-001': 'hub.json names an unknown platform (expected github, gitlab, or null)',
23
23
  'YAD-CFG-002': 'design.json names an unknown design tool (expected one of config.yaml design.tools, or none)',
24
24
  'YAD-CFG-003': 'testing.json names an unknown testing tool (expected one of config.yaml testing.tools, or none)',
25
+ 'YAD-CFG-004': 'learning.json names an unknown learning tool (expected one of config.yaml learning.tools, or none)',
25
26
  };
26
27
 
27
28
  export const err = (code, message, hint) => new YadError(code, message, hint);
package/cli/manifest.mjs CHANGED
@@ -10,7 +10,7 @@ import { readFileSync } from 'node:fs';
10
10
  const { version } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
11
11
  export const VERSION = version;
12
12
 
13
- // The 20 hand-authored yad-* skills (mirrors skills/sdlc/install.sh).
13
+ // The 22 hand-authored yad-* skills (mirrors skills/sdlc/install.sh).
14
14
  export const SKILLS = [
15
15
  'yad-analysis',
16
16
  'yad-epic',
@@ -21,6 +21,8 @@ export const SKILLS = [
21
21
  'yad-connect-repos',
22
22
  'yad-connect-design',
23
23
  'yad-connect-testing',
24
+ 'yad-connect-learning',
25
+ 'yad-learn',
24
26
  'yad-spec',
25
27
  'yad-implement',
26
28
  'yad-checks',
@@ -96,12 +98,22 @@ export const DESIGN_PRIMARY = 'figma';
96
98
  export const TESTING_TOOLS = ['playwright', 'cypress', 'pytest'];
97
99
  export const TESTING_PRIMARY = 'playwright';
98
100
 
101
+ // Supported learning-tool adapters (mirrors skills/sdlc/config.yaml `learning.tools`); `LEARNING_PRIMARY`
102
+ // is the fallback `registerLearning`/setup use when an unknown tool is named, and `none` is the explicit
103
+ // harness-native choice (yad-learn tutors via the harness model when no tool is connected). DeepTutor is
104
+ // a CLI subprocess (no MCP), so the connect skill detects the binary — not an MCP — but the registry +
105
+ // degrade shape mirrors design/testing. (doctor does NOT fall back — an unknown tool there is a hard
106
+ // YAD-CFG-004 fail, mirroring the design-tool YAD-CFG-002.)
107
+ export const LEARNING_TOOLS = ['deeptutor'];
108
+ export const LEARNING_PRIMARY = 'deeptutor';
109
+
99
110
  // Project-level files setup produces (used by `check` to spot missing setup).
100
111
  export const PROJECT_FILES = {
101
112
  reposRegistry: '.sdlc/repos.json',
102
113
  hubConfig: '.sdlc/hub.json',
103
114
  designConfig: '.sdlc/design.json',
104
115
  testingConfig: '.sdlc/testing.json',
116
+ learningConfig: '.sdlc/learning.json',
105
117
  version: '.sdlc/cli-version.json',
106
118
  };
107
119
 
package/cli/setup.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  c, log, step, ok, info, warn, hand, fail, ask, askYesNo, run, has,
6
6
  exists, readJSON, writeJSON,
7
7
  } from './lib.mjs';
8
- import { VERSION, IDE_FOLDER_TARGETS, PROJECT_FILES, DESIGN_TOOLS, DESIGN_PRIMARY, TESTING_TOOLS, TESTING_PRIMARY } from './manifest.mjs';
8
+ import { VERSION, IDE_FOLDER_TARGETS, PROJECT_FILES, DESIGN_TOOLS, DESIGN_PRIMARY, TESTING_TOOLS, TESTING_PRIMARY, LEARNING_TOOLS, LEARNING_PRIMARY } from './manifest.mjs';
9
9
  import { moduleActions, repoActions, hubActions, authorsActions } from './plan.mjs';
10
10
 
11
11
  const ALL_IDES = [...IDE_FOLDER_TARGETS, '.opencode'];
@@ -115,6 +115,34 @@ export function registerTesting(root, { tool, project_url = null, suites = null,
115
115
  return testing;
116
116
  }
117
117
 
118
+ // Record the project's learning-tool connection into .sdlc/learning.json (the deterministic half of the
119
+ // connect loop; CLI detection + the kb build are AI steps, handed off to `yad-connect-learning`). An
120
+ // unknown tool falls back to the primary adapter rather than being rejected — mirrors registerDesign/
121
+ // registerTesting. `none` is the explicit harness-native choice (yad-learn tutors via the harness model).
122
+ // DeepTutor has no MCP, so `source` stays null at setup until the connect skill detects the CLI on PATH.
123
+ export function registerLearning(root, { tool, kb = null, today = null } = {}) {
124
+ // Idempotent re-connect: carry the original first-connect date forward; only lastSyncedAt moves.
125
+ const learningPath = path.join(root, PROJECT_FILES.learningConfig);
126
+ const prev = readJSON(learningPath, null);
127
+ const connectedAt = prev && prev.connectedAt ? prev.connectedAt : today;
128
+ let t = (tool || '').toLowerCase();
129
+ if (t === 'none' || t === '') {
130
+ const off = { tool: 'none', provider: null, version: null, kb: null, kb_sources: [], auth: 'user',
131
+ connectedAt, lastSyncedAt: today, source: 'harness-native' };
132
+ writeJSON(learningPath, off);
133
+ return off;
134
+ }
135
+ if (!LEARNING_TOOLS.includes(t)) { warn(`unknown learning tool '${tool}' — using ${LEARNING_PRIMARY}`); t = LEARNING_PRIMARY; }
136
+ // source stays null until `yad-connect-learning` detects the CLI on PATH (AI step). doctor reports a
137
+ // recorded-but-unconfirmed connection as a warning pointing at that skill.
138
+ const learning = {
139
+ tool: t, provider: null, version: null, kb: kb || null, kb_sources: [], auth: 'user',
140
+ connectedAt, lastSyncedAt: today, source: null,
141
+ };
142
+ writeJSON(learningPath, learning);
143
+ return learning;
144
+ }
145
+
118
146
  function applyActions(actions, { force = false } = {}) {
119
147
  let changed = 0;
120
148
  for (const a of actions) {
@@ -128,7 +156,7 @@ function applyActions(actions, { force = false } = {}) {
128
156
  }
129
157
 
130
158
  export async function runSetup(root, opts = {}) {
131
- const total = 9;
159
+ const total = 10;
132
160
  log(c.bold(`\nSDLC Workflow setup ${c.dim('v' + VERSION)}`));
133
161
  log(c.dim(`target: ${root}`));
134
162
 
@@ -224,8 +252,25 @@ export async function runSetup(root, opts = {}) {
224
252
  : `wrote ${PROJECT_FILES.testingConfig} (${tool})`);
225
253
  }
226
254
 
227
- // 6. Connect code repos
228
- step(6, total, 'Connect code repos');
255
+ // 6. Connect a learning tool (DeepTutor-first, pluggable; the learning layer tutors team members here)
256
+ step(6, total, 'Connect a learning tool (deeptutor / none)');
257
+ const learningPath = path.join(root, PROJECT_FILES.learningConfig);
258
+ if (exists(learningPath) && !(await askYesNo('learning.json exists — reconfigure?', false))) {
259
+ info('keeping existing .sdlc/learning.json');
260
+ } else {
261
+ let tool = (await ask(`Learning tool (${LEARNING_TOOLS.join('/')}/none)`, LEARNING_PRIMARY)).toLowerCase();
262
+ if (![...LEARNING_TOOLS, 'none'].includes(tool)) {
263
+ warn(`unknown learning tool '${tool}' — using ${LEARNING_PRIMARY}`);
264
+ tool = LEARNING_PRIMARY;
265
+ }
266
+ registerLearning(root, { tool, today: opts.today ?? null });
267
+ ok(tool === 'none'
268
+ ? `wrote ${PROJECT_FILES.learningConfig} (harness-native)`
269
+ : `wrote ${PROJECT_FILES.learningConfig} (${tool})`);
270
+ }
271
+
272
+ // 7. Connect code repos
273
+ step(7, total, 'Connect code repos');
229
274
  const regPath = path.join(root, PROJECT_FILES.reposRegistry);
230
275
  const registry = readJSON(regPath, { repos: [] });
231
276
  const known = new Set(registry.repos.map((r) => r.name));
@@ -248,8 +293,8 @@ export async function runSetup(root, opts = {}) {
248
293
  }
249
294
  }
250
295
 
251
- // 7. Wire each connected repo + the hub itself
252
- step(7, total, 'Wire connected repos + the hub (CI gates, PR template, comment scaffold, gate-sync)');
296
+ // 8. Wire each connected repo + the hub itself
297
+ step(8, total, 'Wire connected repos + the hub (CI gates, PR template, comment scaffold, gate-sync)');
253
298
  if (registry.repos.length === 0) info('no repos to wire');
254
299
  for (const repo of registry.repos) {
255
300
  log(` ${c.bold(repo.name)} ${c.dim(`(${repo.platform})`)}`);
@@ -264,8 +309,8 @@ export async function runSetup(root, opts = {}) {
264
309
  // author allowlists for the verified-commits gate (hub + every repo), from the roster emails
265
310
  applyActions(authorsActions(root, registry.repos), { force: true });
266
311
 
267
- // 8. Optional CodeRabbit
268
- step(8, total, 'AI review (CodeRabbit)');
312
+ // 9. Optional CodeRabbit
313
+ step(9, total, 'AI review (CodeRabbit)');
269
314
  for (const repo of registry.repos) {
270
315
  const cr = path.join(path.resolve(root, repo.path), '.coderabbit.yaml');
271
316
  if (exists(cr)) { info(`${repo.name}: .coderabbit.yaml present`); continue; }
@@ -275,8 +320,8 @@ export async function runSetup(root, opts = {}) {
275
320
  }
276
321
  }
277
322
 
278
- // 9. Summary + version stamp
279
- step(9, total, 'Done');
323
+ // 10. Summary + version stamp
324
+ step(10, total, 'Done');
280
325
  writeJSON(path.join(root, PROJECT_FILES.version), { version: VERSION, ideTargets, updatedAt: opts.today ?? null });
281
326
  ok(`stamped ${PROJECT_FILES.version} (v${VERSION})`);
282
327
  log('');
@@ -290,6 +335,10 @@ export async function runSetup(root, opts = {}) {
290
335
  if (testing && testing.tool && testing.tool !== 'none') {
291
336
  hand(`confirm the testing tool: run \`yad-connect-testing\` to detect the ${testing.tool} MCP (or it degrades to artifacts-only)`);
292
337
  }
338
+ const learning = readJSON(learningPath, null);
339
+ if (learning && learning.tool && learning.tool !== 'none') {
340
+ hand(`confirm the learning tool: run \`yad-connect-learning\` to detect the ${learning.tool} CLI (or it degrades to harness-native)`);
341
+ }
293
342
  hand('author your first epic: run `yad-epic`');
294
343
  log('');
295
344
  log(c.dim('Re-run anytime: `yad check` (report) / `yad check --fix` (reconcile).'));
package/docs/index.html CHANGED
@@ -284,7 +284,7 @@
284
284
  <div class="lane">
285
285
  <div class="lane-title">0 · One-time setup (team lead, per project)</div>
286
286
  <div class="flow-v">
287
- <div class="node plain"><strong>Install the module</strong><small><code>npx yadflow setup</code> — copies the 20 skills into your IDE dirs</small></div>
287
+ <div class="node plain"><strong>Install the module</strong><small><code>npx yadflow setup</code> — copies the 22 skills into your IDE dirs</small></div>
288
288
  <div class="arrow-v">▼</div>
289
289
  <div class="node plain"><strong>Wire each repo</strong><small><code>yad-checks</code> · <code>yad-pr-template</code> · <code>yad-review-comments</code> (CI gates, PR template, comment scaffold)</small></div>
290
290
  <div class="arrow-v">▼</div>
@@ -294,6 +294,8 @@
294
294
  <div class="arrow-v">▼</div>
295
295
  <div class="node plain"><strong>Connect a testing tool</strong><small><code>yad-connect-testing</code> → <code>testing.json</code> (Playwright-first, pluggable) so <code>yad-test-cases</code> can implement the automation <em>(optional — degrades to artifacts-only)</em></small></div>
296
296
  <div class="arrow-v">▼</div>
297
+ <div class="node plain"><strong>Connect a learning tool</strong><small><code>yad-connect-learning</code> → <code>learning.json</code> (DeepTutor-first, pluggable) so the learning layer can tutor in context <em>(optional — degrades to harness-native)</em></small></div>
298
+ <div class="arrow-v">▼</div>
297
299
  <div class="node plain"><strong>Optional: hub on a platform</strong><small>detect GitHub/GitLab + reviewer roster, so reviews run on real PRs/MRs</small></div>
298
300
  </div>
299
301
  </div>
@@ -445,7 +447,7 @@ each code repo/
445
447
  <div class="term"><strong>State machine</strong><span class="badge b-core">core</span><br>The core design: the workflow is a fixed set of <em>states</em> (steps). Each state does its work and waits at a gate. The states never change — only the <em>trigger</em> (who moves work forward) changes. That is what lets the team start fully manual and automate gradually without rebuilding anything.</div>
446
448
  <div class="term"><strong>Product hub (product repo)</strong><span class="badge b-core">core</span><br>The git repo that holds the shared “thinking”: epics, architecture, the contract, UI design, stories, reviews and all state. The brain of the project. Code never lives here.</div>
447
449
  <div class="term"><strong>Code repo</strong><span class="badge b-core">core</span><br>A separate git repo holding real application code (e.g. backend, mobile, dashboard). Each story’s spec lives inside the code repo it belongs to, with a link back to the story in the hub.</div>
448
- <div class="term"><strong>Skills source (this repo)</strong><span class="badge b-core">core</span><br>The <code>yadflow</code> repo itself — where the 20 skills live and where you pull updates from. No real product work happens inside it.</div>
450
+ <div class="term"><strong>Skills source (this repo)</strong><span class="badge b-core">core</span><br>The <code>yadflow</code> repo itself — where the 22 skills live and where you pull updates from. No real product work happens inside it.</div>
449
451
  <div class="term"><strong>Front half (“decide” / the brain)</strong><span class="badge b-core">core</span><br>The first half of the workflow, run once per epic in the product hub: analysis (optional) → epic → architecture + contract → UI design → stories — each followed by a human review gate, ending at <code>ready-for-build</code>. <strong>Test cases</strong> is a parallel, non-blocking track that opens at the stories gate and runs alongside the build half. Permanently human-approved.</div>
450
452
  <div class="term"><strong>Back half / build half (“build”)</strong><span class="badge b-core">core</span><br>The second half, run once per story per code repo, inside that repo: spec → implement → checks → PR → ship. These mechanical steps may earn automation over time.</div>
451
453
  <div class="term"><strong>Gate</strong><span class="badge b-core">core</span><br>A stopping point after a step. The step writes its output and <em>waits</em>; a human must approve before the workflow moves on. “Every step stops at a gate” is the heart of the whole system.</div>
@@ -536,7 +538,7 @@ each code repo/
536
538
  <div class="term"><strong>CodeRabbit</strong><span class="badge b-tool">tools</span><br>An AI code-review service used as the advisory first pass on PRs. Optional; never the merge authority.</div>
537
539
  <div class="term"><strong>Graceful degradation</strong><span class="badge b-tool">tools</span><br>The rule that every optional tool (Spec Kit, Impeccable, Repomix, CodeRabbit) can be absent: the workflow falls back to doing the work directly and <em>records</em> that the tool was missing. You can start with none of them.</div>
538
540
  <div class="term"><strong>Tool-agnostic rule</strong><span class="badge b-tool">tools</span><br>Talk to every tool through its commands and files, never through its internal code — so each tool stays swappable.</div>
539
- <div class="term"><strong>Skill</strong><span class="badge b-tool">tools</span><br>One of the 20 named agents (e.g. <code>yad-epic</code>) you invoke by name in your AI IDE. Each skill does one step’s work, writes files, and stops at its gate.</div>
541
+ <div class="term"><strong>Skill</strong><span class="badge b-tool">tools</span><br>One of the 22 named agents (e.g. <code>yad-epic</code>) you invoke by name in your AI IDE. Each skill does one step’s work, writes files, and stops at its gate.</div>
540
542
  <div class="term"><strong>The <code>yad</code> CLI</strong><span class="badge b-tool">tools</span><br>A zero-dependency command-line tool (npm: <code>yadflow</code>) that installs, wires and reconciles the workflow (<code>setup</code>, <code>check --fix</code>, <code>update</code>) and runs the deterministic pieces (<code>gate</code>, <code>commit</code>, <code>open-pr</code>, <code>repo</code>).</div>
541
543
 
542
544
  <h3>People &amp; AI roles</h3>
@@ -679,7 +681,7 @@ each code repo/
679
681
 
680
682
  <!-- ======================================================= -->
681
683
  <section id="skills">
682
- <h2>6. The 20 skills — what each does, how to use it, and when</h2>
684
+ <h2>6. The 22 skills — what each does, how to use it, and when</h2>
683
685
  <p>A <strong>skill</strong> is an agent you invoke <em>by name</em> in your AI IDE — you just ask in
684
686
  plain words, e.g. <em>“run <code>yad-epic</code>”</em>, adding any inputs the skill needs
685
687
  (<code>repo: backend</code>, <code>story: EP-…-S01</code>, <code>action: wire</code>, …).
@@ -747,6 +749,29 @@ yad-connect-testing action: disconnect</code></pre>
747
749
  <div class="row"><span class="lbl lbl-when">When</span> During one-time setup (the wizard records it), and again any time you switch testing tools. <strong>No testing tool? Skip it</strong> — <code>yad-test-cases</code> simply authors the test cases, exactly as before.</div>
748
750
  </div>
749
751
 
752
+ <div class="skillcard" id="sk-connect-learning">
753
+ <h4><code>yad-connect-learning</code></h4>
754
+ <div class="row"><span class="lbl lbl-what">What</span> Connects a <strong>learning/tutoring tool</strong> to the product hub so the cross-cutting <strong>learning layer</strong> can tutor any team member, at any stage, in the context of what's being built. <strong>DeepTutor-first but pluggable.</strong> Unlike the design/testing tools, DeepTutor is a <strong>CLI subprocess</strong> (like Repomix's <code>npx</code>) — it ships no MCP — so this skill detects the <code>deeptutor</code> binary on PATH and optionally builds a project knowledge base from the SDLC artifacts + secret-scanned code-maps. It records the connection in <code>learning.json</code> — <strong>no tokens are ever stored</strong> — and degrades to <strong>harness-native</strong> tutoring when DeepTutor isn't installed.</div>
755
+ <div class="row"><span class="lbl lbl-how">How</span> Run it in the product hub, once per project:</div>
756
+ <pre><code>yad-connect-learning action: connect tool: deeptutor
757
+ yad-connect-learning action: list # show the connection + whether the CLI is available
758
+ yad-connect-learning action: refresh # re-detect the CLI + rebuild the knowledge base
759
+ yad-connect-learning action: disconnect</code></pre>
760
+ <div class="row"><span class="lbl lbl-when">When</span> During one-time setup (the wizard records it), and again any time you switch learning tools. <strong>No DeepTutor? Skip it</strong> — <code>yad-learn</code> still tutors using the harness model reading your artifacts.</div>
761
+ </div>
762
+
763
+ <h3>The learning layer — tutor any member, any stage (cross-cutting)</h3>
764
+
765
+ <div class="skillcard" id="sk-learn">
766
+ <h4><code>yad-learn</code></h4>
767
+ <div class="row"><span class="lbl lbl-what">What</span> The <strong>learning layer</strong>. At <em>any</em> SDLC stage a team member can ask to learn a concept and be tutored <em>in the context of what the team is building</em> — e.g. "teach me why the architecture hash-locks the contract surface." It routes to the connected learning tool (DeepTutor, grounded in the project knowledge base) or degrades to <strong>harness-native</strong> tutoring, renders a tutorial artifact, and appends to a per-member <strong>learning ledger</strong> kept <strong>local-only</strong> (gitignored — never committed or pushed, to the hub or any code repo) so it stays a private, personal skills log (<code>yad-status</code> rolls up the local records). <strong>Purely opt-in — it never blocks a gate</strong> and never touches epic state, approvals, or the contract lock.</div>
768
+ <div class="row"><span class="lbl lbl-how">How</span> Any time, from any stage:</div>
769
+ <pre><code>run yad-learn — concept: "contract versioning" epic: EP-istifta-inquiries stage: architecture-review
770
+ yad-learn action: list # your local skills-log records for this epic
771
+ yad-learn action: complete concept: "contract versioning" # mark it learned</code></pre>
772
+ <div class="row"><span class="lbl lbl-when">When</span> Whenever a member wants to understand what is being built — to review a gate with confidence, onboard onto a domain, or grow a skill. It is additive and reversible: learning never gates the work.</div>
773
+ </div>
774
+
750
775
  <h3>Front half — author the thinking (in the product hub)</h3>
751
776
 
752
777
  <div class="skillcard" id="sk-analysis">
@@ -923,7 +948,7 @@ yad-status EP-istifta-inquiries # one epic in detail</code></pre>
923
948
 
924
949
  <div class="skillcard">
925
950
  <h4><code>npx yadflow setup</code></h4>
926
- <div class="row"><span class="lbl lbl-what">What</span> The guided first-run wizard. Nine steps: preflight (git/node check), install all 20 skills into the IDE dirs you pick, detect the hub’s platform + record the reviewer roster, connect a design tool (Figma-first; optional), connect a testing tool (Playwright-first; optional), connect your code repos, wire each one (CI gates, PR template, comment scaffold), optionally write the AI-review config, and stamp the installed version.</div>
951
+ <div class="row"><span class="lbl lbl-what">What</span> The guided first-run wizard. Ten steps: preflight (git/node check), install all 22 skills into the IDE dirs you pick, detect the hub’s platform + record the reviewer roster, connect a design tool (Figma-first; optional), connect a testing tool (Playwright-first; optional), connect a learning tool (DeepTutor-first; optional), connect your code repos, wire each one (CI gates, PR template, comment scaffold), optionally write the AI-review config, and stamp the installed version.</div>
927
952
  <div class="row"><span class="lbl lbl-how">How</span></div>
928
953
  <pre><code>cd &lt;product-hub-repo&gt;
929
954
  npx yadflow setup</code></pre>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "yadflow",
3
- "version": "2.3.0",
4
- "description": "Yadflow — the gated, team, multi-repo SDLC: author → review → build with a PR-driven review gate and a zero-dependency `yad` CLI (setup, gate, commit, open-pr, repo). A BMAD module + 17 yad-* skills.",
3
+ "version": "2.4.0",
4
+ "description": "Yadflow — the gated, team, multi-repo SDLC: author → review → build with a PR-driven review gate and a zero-dependency `yad` CLI (setup, gate, commit, open-pr, repo). A BMAD module + 22 yad-* skills.",
5
5
  "type": "module",
6
6
  "author": "AbdelRahman Nasr",
7
7
  "license": "MIT",
@@ -50,7 +50,9 @@
50
50
  "bmad",
51
51
  "workflow",
52
52
  "cli",
53
- "spec-driven-development"
53
+ "spec-driven-development",
54
+ "learning",
55
+ "deeptutor"
54
56
  ],
55
57
  "devDependencies": {
56
58
  "@eslint/js": "^9.39.4",
@@ -150,6 +150,27 @@ testing:
150
150
  # NO tokens in the registry (project_url/suites are plain references, never credentials).
151
151
  auth: user
152
152
 
153
+ # Learning tool (yad-connect-learning) — the cross-cutting LEARNING LAYER. At any SDLC stage a team member
154
+ # can invoke `yad-learn` to be tutored on a concept IN THE CONTEXT of what is being built, and the request
155
+ # is recorded in a personal, LOCAL-ONLY skills log (gitignored, never committed/pushed; surfaced read-only
156
+ # by yad-status for the local learner). The tool is
157
+ # DeepTutor (https://github.com/HKUDS/DeepTutor) — an Apache-2.0 Python CLI, reached as a SUBPROCESS like
158
+ # Repomix's `npx` (it has NO MCP), NOT the MCP shape of the design/testing tools. DeepTutor-first but
159
+ # PLUGGABLE: a learning-tool adapter. Connection is one-per-project, recorded at setup; the per-epic,
160
+ # per-member learning ledger (learning-records.json) + rendered tutorials are written by yad-learn.
161
+ learning:
162
+ registry: "{project-root}/.sdlc/learning.json" # project-wide learning connection (NOT per-epic) — the ONLY committed learning file (no secrets/personal data)
163
+ tools: [deeptutor] # supported adapters; an unknown tool falls back to `primary`
164
+ primary: deeptutor # the default/named provider
165
+ degrade: harness-native # no deeptutor CLI => yad-learn tutors via the harness model
166
+ # reading the project artifacts directly (always works, never blocks)
167
+ records: "{project-root}/epics/EP-<slug>/.sdlc/learning-records.json" # per-epic learning ledger (yad-learn) — LOCAL-ONLY, gitignored, never committed/pushed
168
+ artifacts: "{project-root}/epics/EP-<slug>/learning/" # rendered tutorial markdown (yad-learn) — LOCAL-ONLY, gitignored, never committed/pushed
169
+ capabilities: { explain: chat, deep: deep_research, quiz: deep_question } # yad-learn mode -> deeptutor capability
170
+ # Auth: `yad-connect-learning` uses the LOCAL user's own deeptutor CLI config/session and stores NO
171
+ # tokens in the registry (kb name + sources are plain references, never credentials). Opt-in, never a gate.
172
+ auth: user
173
+
153
174
  # Hub platform + front-half review bridge (yad-connect-repos `detect-hub`; yad-review-gate + yad-hub-bridge).
154
175
  # The product hub is itself a git repo on a platform. With the bridge enabled, the front-half review/
155
176
  # comment/approval cycle runs through a real PR/MR on the hub: a review PR is opened per artifact, reviewers
@@ -11,7 +11,7 @@ set -euo pipefail
11
11
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
12
12
  cd "$ROOT"
13
13
 
14
- SKILLS=(yad-analysis yad-epic yad-architecture yad-ui yad-stories yad-test-cases yad-connect-repos yad-connect-design yad-connect-testing yad-spec yad-implement yad-checks yad-pr-template yad-review-comments yad-hub-bridge yad-ship yad-backfill yad-run yad-review-gate yad-status)
14
+ SKILLS=(yad-analysis yad-epic yad-architecture yad-ui yad-stories yad-test-cases yad-connect-repos yad-connect-design yad-connect-testing yad-connect-learning yad-learn yad-spec yad-implement yad-checks yad-pr-template yad-review-comments yad-hub-bridge yad-ship yad-backfill yad-run yad-review-gate yad-status)
15
15
 
16
16
  echo "Installing sdlc module from $ROOT/skills ..."
17
17
 
@@ -1,4 +1,5 @@
1
1
  module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
2
+ SDLC Workflow,yad-analysis,Author Analysis,AN,"Optional front state: with the analyst pressure-test a feature idea and write the discovery brief into analysis.md. Assigns the EP-<slug> ID and seeds .sdlc state (the chain that puts analysis before epic). If skipped, the epic step does this shaping inline. Never auto-advances.",,{idea: one-line feature idea},1-front,,yad-review-gate,false,epics/EP-<slug>/,analysis.md state.json
2
3
  SDLC Workflow,yad-epic,Author Epic,AE,"Front state 1: shape an idea with analyst then pm into epic.md; assign EP-<slug> ID and seed .sdlc state. Never auto-advances.",,{idea: one-line feature idea},1-front,,yad-review-gate,true,epics/EP-<slug>/,epic.md state.json
3
4
  SDLC Workflow,yad-review-gate,Team Review Gate,RG,"Reusable review+approve gate for all five reviews. Shares an artifact for review, records comments and approvals as files, enforces owner + 1 reviewer (escalates on contract/auth/payments; per-repo routing for stories), advances state only when approved.",,{artifact: file under the epic} {action: open|comment|approve|advance},1-front,,,true,epics/EP-<slug>/reviews/,reviews/*.md approvals.json state.json
4
5
  SDLC Workflow,yad-architecture,Author Architecture,AA,"Front state 3: with the architect author architecture.md and the locked contract.md; hash-lock the contract surface. Never auto-advances.",,{epic: EP-<slug>},1-front,yad-review-gate,yad-review-gate,true,epics/EP-<slug>/,architecture.md contract.md contract-lock.json state.json
@@ -8,6 +9,8 @@ SDLC Workflow,yad-test-cases,Author Test Cases,TC,"Front state 9 (PARALLEL, non-
8
9
  SDLC Workflow,yad-connect-repos,Connect Code Repos,CR,"Setup/maintenance: connect code repos to the product hub so the front/brain phases are code-aware. Registers each repo (GitHub or GitLab, local-user auth, no stored tokens) in .sdlc/repos.json and caches a Repomix pack + a lightweight code-map (existing endpoints/events/data-models/modules, secret-scanned). Idempotent and refreshable; staleness tracked by HEAD sha. Run at setup or any time a new repo is added. Not a gated state — never touches epic state or approvals.",,{action: connect|refresh|list|disconnect} {repo: <name>} {path: <path-or-absolute>} {git_url: <ssh-or-https>} {domain_owner: <who>},0-setup,,yad-epic,false,.sdlc/,repos.json code-context/<repo>/pack.md code-context/<repo>/code-map.md
9
10
  SDLC Workflow,yad-connect-design,Connect Design Tool,CD,"Setup/maintenance: connect a design tool (Figma-first, pluggable) to the product hub so the UI design step can materialize the actual feature design (mobile screens / web pages) inside it, alongside ui-design.md + DESIGN.md. Records the tool + project/file references in .sdlc/design.json (local-user / MCP-session auth, no stored tokens), detecting whether a design-tool MCP is available and degrading to markdown-only when absent. Idempotent and refreshable; one connection per project. Not a gated state — never touches epic state or approvals.",,{action: connect|refresh|list|disconnect} {tool: figma|pencil|none} {project_url: <team/project/file url>} {files: {web,mobile}},0-setup,,yad-ui,false,.sdlc/,design.json
10
11
  SDLC Workflow,yad-connect-testing,Connect Testing Tool,CT,"Setup/maintenance: connect a testing tool (Playwright-first, pluggable) to the product hub so the test-cases step can implement the actual automation tests in it, alongside test-cases.md. Records the tool + project/suite references in .sdlc/testing.json (local-user / MCP-session auth, no stored tokens), detecting whether a testing-tool MCP is available and degrading to artifacts-only when absent. Idempotent and refreshable; one connection per project. Not a gated state — never touches epic state or approvals.",,{action: connect|refresh|list|disconnect} {tool: playwright|cypress|pytest|none} {project_url: <project/config reference>} {suites: {<repo>}},0-setup,,yad-test-cases,false,.sdlc/,testing.json
12
+ SDLC Workflow,yad-connect-learning,Connect Learning Tool,CL,"Setup/maintenance: connect a learning/tutoring tool (DeepTutor-first, pluggable) so the cross-cutting learning layer can tutor any team member, at any SDLC stage, in the context of what is being built. Records the tool + an optional grounded knowledge base in .sdlc/learning.json (local-user auth, no stored tokens), detecting whether the DeepTutor CLI is on PATH (a subprocess like Repomix, not an MCP) and degrading to harness-native tutoring when absent. Idempotent and refreshable; one connection per project. Not a gated state — never touches epic state or approvals.",,{action: connect|refresh|list|disconnect} {tool: deeptutor|none} {kb: <name>} {ground: true|false},0-setup,,yad-learn,false,.sdlc/,learning.json
13
+ SDLC Workflow,yad-learn,Learn (Tutor),LN,"Cross-cutting learning layer: at ANY SDLC stage a team member can ask to learn a concept and be tutored in the context of what the team is building. Routes to the connected learning tool (.sdlc/learning.json, DeepTutor-first) grounded in the project knowledge base, or degrades to harness-native tutoring (the harness model reading the artifacts). Renders a tutorial artifact and appends to a per-member learning ledger kept LOCAL-ONLY (gitignored, never committed/pushed to the hub or any code repo) so it stays a private, personal skills log (yad-status rolls up the local records). Purely opt-in — never blocks a gate, never touches epic state, approvals, or the contract lock.",,{concept: <idea>} {context: <focus>} {epic: EP-<slug>} {stage: <sdlc stage>} {member: <who>} {mode: explain|deep|quiz} {action: learn|list|complete},,,,,false,epics/EP-<slug>/,learning-records.json learning/<member>--<concept>.md
11
14
  SDLC Workflow,yad-spec,Author Spec,SP,"Build-half Step A: for one ready-for-build story and one of its repos, run the heavy Spec Kit ceremony once (specify→clarify→plan→analyze→checklist→tasks) inside that code repo, writing specs/<story-id>/ in Spec Kit's layout (drives /speckit.* when installed, else hand-authors and records speckit: not-installed). References the locked contract; never re-invents the surface. Writes link.md back to the story. Never auto-advances.",,{epic: EP-<slug>} {story: EP-<slug>-S0N} {repo: <one of story.repos>},3-build,yad-review-gate,,false,demo-repos/<repo>/specs/<story-id>/,spec.md research.md data-model.md contracts/ plan.md tasks.md link.md
12
15
  SDLC Workflow,yad-implement,Implement Task,IM,"Build-half Step B: with the dev lens, implement ONE atomic task from a story's tasks.md as a small diff (<=3 files) on its own branch feat/<story>-<task>-<slug> in the code repo. Diff stays inside the task's declared files (flag and STOP if it grows beyond them). Commit ends with a Task: <story>-<task> trailer; add Contract-Change: yes only when the locked contract surface is touched (routes back to the architecture gate). Never auto-advances.",,{epic: EP-<slug>} {story: EP-<slug>-S0N} {repo: <one of story.repos>} {task: T0N},3-build,yad-spec,,false,demo-repos/<repo>/,branch+commit per atomic task
13
16
  SDLC Workflow,yad-checks,Check Gates,CK,"Build-half Step C: wire and run the three production-safety CI gates on a code repo — spec-link (every change links a real story/spec via its Task trailer), contract-check (a contract-surface change without Contract-Change + an updated re-locked contract FAILS and routes back to the architecture gate), and build/test/lint. CI-agnostic bash invoked by GitHub Actions and GitLab CI. Blocking in CI; the human still owns the merge. Never auto-advances.",,{repo: <one of an epic's repos>} {action: wire|run} {base: target branch},3-build,yad-implement,,false,demo-repos/<repo>/,checks/*.sh .github/workflows/yad-checks.yml .gitlab-ci.yml
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: yad-connect-learning
3
+ description: 'Connects a learning/tutoring tool (DeepTutor, or another tool — pluggable) to the product hub so the cross-cutting learning layer can tutor any team member, at any SDLC stage, in the context of what is being built. Registers the tool into the project-wide .sdlc/learning.json (local-user auth, no stored tokens), detecting whether the DeepTutor CLI is on PATH and degrading to harness-native tutoring (the harness model reading project artifacts) when it is not. Optionally builds a project knowledge base from the SDLC artifacts + secret-scanned code-maps so tutoring is grounded. Run at setup or any time the learning tool changes. Reusable, idempotent, refreshable. Use when the user says "connect DeepTutor", "connect a learning tool", "refresh the learning connection", or "list the learning connection".'
4
+ ---
5
+
6
+ # SDLC — Connect a Learning Tool (the cross-cutting learning layer)
7
+
8
+ **Goal:** Let any team member pause at **any** SDLC stage and ask to learn a concept — and get tutored
9
+ *in the context of what the team is actually building*. This skill **connects** a learning tool such as
10
+ **DeepTutor** to the product hub and records *how* to reach it (the tool, the CLI, an optional grounded
11
+ knowledge base) — never a credential. The consumer skill **`yad-learn`** does the tutoring per request
12
+ and records the team's skills.
13
+
14
+ This is **setup/maintenance**, not a gated state — it never touches `.sdlc/state.json` or any epic's
15
+ approvals. It only writes the project-wide learning registry. `yad-learn` consumes it: when DeepTutor is
16
+ available it drives the CLI (grounded in the knowledge base); when nothing is connected, `yad-learn`
17
+ degrades to **harness-native** tutoring — the harness model reads the project artifacts directly and
18
+ explains the concept. The learning layer is **purely opt-in and never blocks a gate**.
19
+
20
+ ## Conventions
21
+
22
+ - `{project-root}` resolves from the project working directory (the **product hub**).
23
+ - The integration is **DeepTutor-first but pluggable** (`config.yaml` `learning.tools`): a learning-tool
24
+ *adapter*, like the design/testing adapters. `none` → harness-native (yad-learn still tutors via the
25
+ harness model).
26
+ - **DeepTutor is reached as a CLI SUBPROCESS** (`deeptutor …`), the same shape as Repomix's `npx` — NOT
27
+ an MCP like the design/testing tools (DeepTutor ships no MCP server). The skill detects the **binary on
28
+ PATH** and degrades when it is absent; it never installs DeepTutor.
29
+ - Registry: `{project-root}/.sdlc/learning.json` (project-wide, shared across all epics — NOT per-epic),
30
+ the sibling of `.sdlc/repos.json`, `.sdlc/hub.json`, `.sdlc/design.json`, and `.sdlc/testing.json`.
31
+ - Per-epic, per-member learning records + rendered tutorials are written later by `yad-learn`
32
+ (`epics/EP-<slug>/.sdlc/learning-records.json` and `epics/EP-<slug>/learning/`), not here.
33
+ - Speak in the configured `communication_language`; write documents in `document_output_language`.
34
+
35
+ ## Inputs
36
+
37
+ - `action` — `connect` (default) | `refresh` | `list` | `disconnect`.
38
+ - `tool` — `deeptutor` | another adapter id (`config.yaml` `learning.tools`). `none` records a deliberate
39
+ harness-native project.
40
+ - `kb` — optional knowledge-base name (default `yadflow-<project-slug>`). The DeepTutor kb that grounds
41
+ tutoring in this project.
42
+ - `ground` — `true` (default) | `false`. When `true` and DeepTutor is available, build/refresh the
43
+ knowledge base from the SDLC artifacts + code-maps (the "grounded in the project" piece).
44
+
45
+ ## On Activation
46
+
47
+ ### Step 1 — Resolve the tool and detect the CLI (the learning-tool adapter)
48
+ Determine which tool is being connected from `tool` (default `deeptutor`); reject a `tool` not in
49
+ `config.yaml` `learning.tools` (fall back to the configured `learning.primary` with a warning, the same
50
+ way `registerRepo`/`registerDesign` fall back). Then **detect the tool's CLI on PATH**:
51
+
52
+ - **deeptutor** → run a best-effort `deeptutor --version` (or `deeptutor config show`). If it succeeds,
53
+ record `provider: "deeptutor-cli"` and the reported `version`.
54
+ - another adapter → its named CLI.
55
+
56
+ **Auth is the local user's own** — DeepTutor's own config (`deeptutor init`, `data/user/settings/`) and
57
+ the user's LLM provider keys. The skill **stores no tokens**; `kb`/`kb_sources` are plain references.
58
+
59
+ **Graceful degradation:** if the `deeptutor` binary is not on PATH, record `source: "harness-native"`
60
+ and report that `yad-learn` will still tutor **using the harness model reading the project artifacts**
61
+ (no error — the learning layer is additive and always works; DeepTutor only adds knowledge-base
62
+ grounding, quizzes, and deep research). Do **not** install DeepTutor as part of this step.
63
+
64
+ ### Step 2 — Ground it in the project (optional, when DeepTutor is available)
65
+ When `ground: true` and DeepTutor is available, build or refresh a project **knowledge base** so tutoring
66
+ quotes what is actually being built:
67
+
68
+ ```
69
+ deeptutor kb create <kb> # idempotent: reuse if it exists
70
+ deeptutor kb add <kb> --doc <path> # per source below
71
+ ```
72
+
73
+ Add only **already-committed** artifacts + the **secret-scanned code-maps** (never raw repos): each
74
+ epic's `epic.md`, `architecture.md`, `contract.md`, `ui-design.md`, the `stories/` files, and every
75
+ `.sdlc/code-context/<repo>/code-map.md`. Record the kb name and the source globs in the registry. Skip
76
+ silently (record `kb: null`) when there are no artifacts yet (greenfield-safe).
77
+
78
+ ### Step 3 — Record the connection in the registry
79
+ Upsert into `{project-root}/.sdlc/learning.json` (create the file + parent `.sdlc/` if absent):
80
+
81
+ ```json
82
+ {
83
+ "tool": "deeptutor",
84
+ "provider": "deeptutor-cli",
85
+ "version": "1.4.5",
86
+ "kb": "yadflow-<project-slug>",
87
+ "kb_sources": ["epic.md", "architecture.md", "contract.md", "ui-design.md", "stories/", "code-context/*/code-map.md"],
88
+ "auth": "user",
89
+ "connectedAt": "<YYYY-MM-DD>",
90
+ "lastSyncedAt": "<YYYY-MM-DD>",
91
+ "source": "deeptutor-cli"
92
+ }
93
+ ```
94
+
95
+ - `tool: "none"` records a deliberate harness-native project: `{ "tool": "none", "provider": null,
96
+ "kb": null, "source": "harness-native", ... }`.
97
+ - A DeepTutor connection whose CLI is absent records `{ "tool": "deeptutor", "provider": null,
98
+ "kb": null, "source": "harness-native", ... }` until a `refresh` finds the binary.
99
+ - `connect` is **idempotent** — re-running it overwrites the single connection in place; the original
100
+ `connectedAt` is preserved and only `lastSyncedAt` moves.
101
+
102
+ ### Step 4 — Report (never auto-advance)
103
+ Report the connected `tool`, its `provider`, whether the CLI is available (or that `yad-learn` will run
104
+ harness-native), the `kb`, and that **`yad-learn` will now tutor team members on request**. Nothing
105
+ auto-advances; this is setup.
106
+
107
+ ## Other actions
108
+
109
+ - **`refresh`** — re-detect the CLI, rebuild the knowledge base from the latest artifacts, and update
110
+ `lastSyncedAt`. Same machinery as `connect`. Re-detection may flip `source` between `deeptutor-cli` and
111
+ `harness-native` — report the change.
112
+ - **`list`** — print the current connection: `tool`, `provider`, `version`, the `kb`, and an
113
+ **available/harness-native** flag for the CLI (best-effort). No learning tool connected ⇒
114
+ "harness-native".
115
+ - **`disconnect`** — remove the registry file (or set `tool: "none"`). DeepTutor's own config and
116
+ knowledge bases are **never touched** — only the hub's record of them.
117
+
118
+ ## Hard rules
119
+
120
+ - **Local-user auth only; store no tokens.** Connect through the user's own DeepTutor config / LLM keys;
121
+ never embed a key or any credential in the registry. `kb`/`kb_sources` are plain references.
122
+ - **Degrade gracefully.** No DeepTutor CLI → `yad-learn` tutors harness-native with no error. The
123
+ learning layer is additive and always works — never a blocker.
124
+ - **Setup, not a gate.** Never touch `.sdlc/state.json`, approvals, or the contract lock from here.
125
+ - **Idempotent + refreshable.** `connect`/`refresh` are safe to re-run; a project carries one learning
126
+ connection at a time.
127
+ - **Ground only committed, secret-scanned sources.** Feed the knowledge base from committed SDLC
128
+ artifacts + the already-scanned code-maps — never raw repository contents.
129
+ - **Describe the connection; do not tutor here.** This skill records *how to reach* the tool. The actual
130
+ tutoring + the personal, local-only learning records are produced by `yad-learn`, per request.
131
+ - **The registry is the only committed learning file.** `.sdlc/learning.json` is shared, reviewable
132
+ config (no secrets, no personal data). The records ledger and tutorials `yad-learn` writes are
133
+ local-only — gitignored, never committed or pushed.
134
+
135
+ ## Reference
136
+ - Registry schema + freshness rule: `references/learning-registry.md`.
137
+ - CLI detection, the knowledge-base build recipe, the mode→capability map, and the harness-native degrade
138
+ path: `references/learning-context.md`.
139
+ - The connect pattern this mirrors (testing tool): `../yad-connect-testing/SKILL.md`.
140
+ - The consumer — how `yad-learn` tutors and writes `learning-records.json`: `../yad-learn/SKILL.md`.
@@ -0,0 +1,79 @@
1
+ # Learning context — CLI detection, knowledge-base build, capability map, degrade path
2
+
3
+ How `yad-connect-learning` reaches DeepTutor, grounds it in the project, and how `yad-learn` consumes the
4
+ connection. DeepTutor is a **CLI subprocess** (Apache-2.0, `pip install -U deeptutor`) — it ships **no
5
+ MCP server**, so this adapter detects a **binary on PATH**, the same shape as Repomix's `npx` in
6
+ `yad-connect-repos`/`yad-backfill`, not the MCP shape of the design/testing tools.
7
+
8
+ ## CLI detection
9
+
10
+ Best-effort, never fatal:
11
+
12
+ ```
13
+ deeptutor --version # success => provider: "deeptutor-cli", capture the version
14
+ deeptutor config show # fallback probe if --version is unavailable
15
+ ```
16
+
17
+ - Binary found → `source: "deeptutor-cli"`.
18
+ - Binary absent → `source: "harness-native"` (no error). Report that `yad-learn` will tutor via the
19
+ harness model reading the project artifacts.
20
+
21
+ DeepTutor's own setup (`deeptutor init`, LLM provider keys under `data/user/settings/`) is the **user's**
22
+ responsibility and lives outside this repo. The skill never runs `deeptutor init` and never writes keys.
23
+
24
+ ## Knowledge-base build (grounding)
25
+
26
+ When `ground: true` and the CLI is present, build/refresh a project knowledge base so tutoring quotes
27
+ what is actually being built:
28
+
29
+ ```
30
+ deeptutor kb create <kb> # idempotent — reuse if it already exists
31
+ deeptutor kb add <kb> --doc <path> # once per source path below
32
+ deeptutor kb list # verify
33
+ ```
34
+
35
+ Ingest only **committed, secret-scanned** sources (never raw repos):
36
+
37
+ - Per epic under `epics/EP-<slug>/`: `epic.md`, `architecture.md`, `contract.md`, `ui-design.md`, and the
38
+ `stories/*.md` files.
39
+ - Per connected repo: `.sdlc/code-context/<repo>/code-map.md` (already secret-scanned by
40
+ `yad-connect-repos`). Do **not** add `pack.md` or the raw repo.
41
+
42
+ Record `kb` and `kb_sources` in the registry. If there are no artifacts yet (greenfield), skip and record
43
+ `kb: null` — `yad-learn` falls back to passing context inline.
44
+
45
+ ## Mode → capability map (consumed by `yad-learn`)
46
+
47
+ `config.yaml` `learning.capabilities` maps a `yad-learn` mode to a DeepTutor capability:
48
+
49
+ | `yad-learn` mode | DeepTutor capability | use |
50
+ |------------------|----------------------|-----|
51
+ | `explain` (default) | `chat` | a focused, grounded explanation of the concept |
52
+ | `deep` | `deep_research` | a deeper, multi-source dive |
53
+ | `quiz` | `deep_question` | generate questions to confirm comprehension (records a signal) |
54
+
55
+ `yad-learn` invokes:
56
+
57
+ ```
58
+ deeptutor run <capability> "<concept> — in the context of <scoped artifact/stage>" \
59
+ --kb <kb> --format json
60
+ ```
61
+
62
+ `--format json` streams **NDJSON** — one event per line with a `type` (`content` | `tool_call` |
63
+ `tool_result` | `done`) and a `session_id`. `yad-learn` concatenates `content` events into the tutorial
64
+ and captures `session_id` from the `done` event for the learning record.
65
+
66
+ ## Degrade path (harness-native)
67
+
68
+ When `source: "harness-native"` (no CLI, or `tool: "none"`), `yad-learn` does **not** fail. It tutors
69
+ using the **harness model itself**: it reads the scoped epic's `epic.md` / `architecture.md` /
70
+ `contract.md` / code-maps and explains the concept grounded in them. The local-only learning record is
71
+ written identically (with `"tool": "harness-native"`), so the learning layer always works and always
72
+ records — DeepTutor only adds knowledge-base grounding, deep research, and quizzes.
73
+
74
+ ## Freshness
75
+
76
+ Like the code-context cache, the knowledge base can drift from the artifacts. `refresh` rebuilds it from
77
+ the current committed artifacts and moves `lastSyncedAt`. Rebuilding is a human decision (run `connect`/
78
+ `refresh`); `yad-learn` never silently rebuilds the kb mid-tutorial — at most it notes the kb may be
79
+ stale and proceeds.
@@ -0,0 +1,60 @@
1
+ # Learning registry — schema + freshness rule
2
+
3
+ The registry is the product hub's record of which learning tool is connected and how to reach it. It is
4
+ **project-wide** (one learning tool per project, shared across every epic), so it lives at the product
5
+ root, not under any `epics/EP-<slug>/.sdlc/`.
6
+
7
+ ## Location
8
+
9
+ `{project-root}/.sdlc/learning.json`
10
+
11
+ (`config.yaml` `learning.registry`.) Create the file and its parent `.sdlc/` on the first `connect`.
12
+
13
+ ## Schema
14
+
15
+ ```json
16
+ {
17
+ "tool": "deeptutor", // deeptutor | <adapter id> | none (harness-native)
18
+ "provider": "deeptutor-cli", // the concrete CLI: deeptutor-cli | null
19
+ "version": "1.4.5", // CLI version reported at detect time; null if absent
20
+ "kb": "yadflow-istifta", // grounded knowledge-base name; null if not built
21
+ "kb_sources": ["epic.md", "architecture.md", "contract.md", "ui-design.md", "stories/", "code-context/*/code-map.md"],
22
+ "auth": "user", // ALWAYS the user's own DeepTutor config / LLM keys — never a token
23
+ "connectedAt": "2026-06-14", // first connect (YYYY-MM-DD)
24
+ "lastSyncedAt": "2026-06-14", // last connect/refresh
25
+ "source": "deeptutor-cli" // deeptutor-cli (CLI on PATH) | harness-native (degraded)
26
+ }
27
+ ```
28
+
29
+ ## Rules
30
+
31
+ - **`tool`** selects the adapter; it MUST be one of `config.yaml` `learning.tools` (or `none`). At
32
+ **connect** time an unknown tool is normalized to `learning.primary` with a warning (so the registry
33
+ never persists an unknown value); a registry hand-edited to an unknown or missing tool **fails
34
+ `doctor`** with `YAD-CFG-004` and must be fixed.
35
+ - **Auth is never stored.** No LLM key, token, or any credential in the registry. `kb`/`kb_sources` are
36
+ plain references; DeepTutor is reached through the user's own `deeptutor` config.
37
+ - **`connect` overwrites in place** — a project carries exactly one learning connection at a time;
38
+ switching tools is just another `connect`. There is no array (unlike `repos.json`). The original
39
+ `connectedAt` is preserved across re-connects; only `lastSyncedAt` moves.
40
+ - **`source`** is the authority for availability: `deeptutor-cli` means `yad-learn` can drive the CLI
41
+ (grounded in `kb`); `harness-native` means `yad-learn` tutors via the harness model reading the
42
+ artifacts directly. `refresh` re-detects and may flip it.
43
+ - **`ground` is not persisted.** The `ground: true|false` input only governs whether the AI connect
44
+ step builds/refreshes the knowledge base at connect time; the registry records the *result* (`kb` +
45
+ `kb_sources`), never the flag itself.
46
+ - **`tool: "none"`** is a valid, deliberate state: a project that has chosen harness-native tutoring.
47
+ `yad-learn` treats it exactly like an absent registry — it still tutors, just without DeepTutor.
48
+ - **`disconnect`** removes the file (or sets `tool: "none"`). DeepTutor's own config and knowledge bases
49
+ are never touched.
50
+
51
+ ## Git tracking
52
+
53
+ Commit the **registry** (`learning.json`) — it is small, reviewable, and holds no secrets (references
54
+ only). This mirrors how `repos.json`, `hub.json`, `design.json`, and `testing.json` are committed.
55
+
56
+ ## Greenfield
57
+
58
+ A brand-new product hub has no `learning.json`. That is valid — `yad-learn` treats "no learning tool
59
+ connected" the same as `tool: "none"` and tutors harness-native. The registry appears the first time
60
+ `connect` runs.
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: yad-learn
3
+ description: 'The cross-cutting learning layer: at ANY SDLC stage, a team member can ask to learn a concept and be tutored in the context of what the team is building. Routes the request to the connected learning tool (.sdlc/learning.json, DeepTutor-first) grounded in the project knowledge base, or degrades to harness-native tutoring (the harness model reading the artifacts) when no tool is connected. Renders a tutorial artifact and appends to a per-member learning ledger that is kept LOCAL-ONLY — gitignored, never committed or pushed to the product hub or any code repo — so it stays a private, personal skills log (yad-status rolls up the local records). Purely opt-in — it NEVER blocks a gate and never touches epic state, approvals, or the contract lock. Use when the user says "teach me <concept>", "learn about <concept>", or "yad-learn".'
4
+ ---
5
+
6
+ # SDLC — Learn (the cross-cutting tutor)
7
+
8
+ **Goal:** At any SDLC stage, a team member can pause and ask to learn a concept — e.g. *"teach me why the
9
+ architecture hash-locks the contract surface"* — and get tutored **in the context of this project**. The
10
+ tutorial is rendered as an artifact and the request is recorded in a **personal, local skills log**
11
+ (`yad-status` shows the roll-up of your local records). This makes a learner's own understanding — and
12
+ therefore their **control over what is being built** — explicit, without ever exposing who-learned-what
13
+ to the team.
14
+
15
+ **Learning output is LOCAL-ONLY.** The records ledger and the rendered tutorials are personal artifacts:
16
+ they are **gitignored and must never be committed or pushed** — not to the product hub and not to any
17
+ code repo. The skill ensures the product hub's `.gitignore` lists these paths before it writes them. The
18
+ only committed, shared learning file is the connection registry `.sdlc/learning.json` (no secrets, no
19
+ personal data) — written by `yad-connect-learning`, not here.
20
+
21
+ This is a **cross-cutting, opt-in** skill (like `yad-status`, it runs any time). It is **never a gate**:
22
+ it does not move `currentStep`, never records an approval, and never touches `.sdlc/state.json`, the
23
+ approvals ledger, or the contract lock. It writes only the local learning ledger + tutorial artifacts.
24
+
25
+ ## Conventions
26
+
27
+ - `{project-root}` resolves from the project working directory (the **product hub**).
28
+ - The tutor is reached via the project's learning connection (`.sdlc/learning.json`, written by
29
+ `yad-connect-learning`). **DeepTutor-first** (a CLI subprocess); when no tool is connected (or the
30
+ `deeptutor` binary is absent) it degrades to **harness-native** tutoring — the harness model reads the
31
+ scoped artifacts and explains the concept itself. Either way `yad-learn` always works and always
32
+ records.
33
+ - Per-epic learning records: `epics/EP-<slug>/.sdlc/learning-records.json` (append-only personal log).
34
+ Rendered tutorials: `epics/EP-<slug>/learning/`.
35
+ - When no epic is scoped, records go to `.sdlc/learning-records.json` and tutorials to `.sdlc/learning/`
36
+ (cross-project learning).
37
+ - **Local-only, never committed.** All of the above paths are personal output. Before writing any of
38
+ them, ensure the **product hub's** `.gitignore` ignores learning output (idempotent — append only if
39
+ the lines are absent):
40
+ ```
41
+ # yadflow learning layer — personal, local-only (never commit or push)
42
+ .sdlc/learning-records.json
43
+ .sdlc/learning/
44
+ epics/*/.sdlc/learning-records.json
45
+ epics/*/learning/
46
+ ```
47
+ Never write learning output into a connected **code repo** — it lives only in the product hub, and only
48
+ on the local machine. `.sdlc/learning.json` (the connection registry) is the sole committed learning
49
+ file and is NOT ignored.
50
+ - Speak in the configured `communication_language`; write tutorials in `document_output_language`.
51
+
52
+ ## Inputs
53
+
54
+ - `concept` — **required.** The idea to learn (e.g. "contract versioning", "async/await", "the per-repo
55
+ stories gate").
56
+ - `context` — optional free text narrowing the focus (e.g. "why the surface is hash-locked", "in the
57
+ backend event loop").
58
+ - `epic` — optional `EP-<slug>` to scope the tutorial + record to one epic (default: cross-project).
59
+ - `stage` — optional SDLC stage the learner is at (e.g. `architecture-review`, `implement`), recorded for
60
+ the skills roll-up.
61
+ - `member` — the learner (default: the invoking user).
62
+ - `mode` — `explain` (default) | `deep` | `quiz` (`config.yaml` `learning.capabilities`).
63
+ - `action` — `learn` (default) | `list` | `complete`.
64
+
65
+ ## On Activation (`action: learn`)
66
+
67
+ ### Step 1 — Resolve the connection and route
68
+ Read `.sdlc/learning.json`:
69
+
70
+ - **DeepTutor available** (`source: "deeptutor-cli"`): run the CLI with the mapped capability
71
+ (`explain→chat`, `deep→deep_research`, `quiz→deep_question`), grounded in the kb:
72
+ ```
73
+ deeptutor run <capability> "<concept> — in the context of <epic/stage + scoped artifact>" \
74
+ --kb <kb> --format json
75
+ ```
76
+ Parse the NDJSON: concatenate `content` events into the tutorial body; capture `session_id` from the
77
+ `done` event. `mode: quiz` issues a `deep_question` follow-up and records the comprehension signal.
78
+ - **Harness-native** (`tool: "none"`, absent registry, or `source: "harness-native"`): tutor with the
79
+ harness model. Read the scoped epic's `epic.md` / `architecture.md` / `contract.md` and any connected
80
+ `code-context/<repo>/code-map.md`, and write a focused explanation grounded in them. No error — this is
81
+ the normal degraded path.
82
+
83
+ Keep the tutorial focused (usually < 600 words): explain the concept, then tie it to **one concrete
84
+ example from this project** (an artifact line, a contract field, a story).
85
+
86
+ ### Step 2 — Render the tutorial artifact (local-only)
87
+ First ensure the product hub's `.gitignore` lists the learning-output paths (see Conventions — append the
88
+ block only if absent, so the artifacts can never be committed or pushed). Then write the tutorial to
89
+ `epics/EP-<slug>/learning/<member>--<concept-slug>.md` (or `.sdlc/learning/` when no epic is scoped).
90
+ Front-matter the file with `member`, `concept`, `stage`, `tool`, and `requestedAt`.
91
+
92
+ ### Step 3 — Record in the learning ledger (append-only)
93
+ Append to `epics/EP-<slug>/.sdlc/learning-records.json` (create the array if absent):
94
+
95
+ ```json
96
+ {
97
+ "member": "alice",
98
+ "concept": "contract versioning",
99
+ "context": "why the architecture hash-locks the surface",
100
+ "stage": "architecture-review",
101
+ "mode": "explain",
102
+ "tool": "deeptutor",
103
+ "sessionId": "…",
104
+ "tutorial": "learning/alice--contract-versioning.md",
105
+ "comprehension": null,
106
+ "status": "in-progress",
107
+ "requestedAt": "<YYYY-MM-DD>",
108
+ "completedAt": null
109
+ }
110
+ ```
111
+
112
+ `tool` is `deeptutor` or `harness-native`. `comprehension` holds the quiz signal when `mode: quiz`,
113
+ else `null`.
114
+
115
+ ### Step 4 — Present + confirm (record-only, NO gate)
116
+ Show the tutorial and ask the member to confirm they've reviewed it. This is **record-keeping only** —
117
+ there is no approval and no gate. The learner runs `action: complete` (below) when done.
118
+
119
+ ## Other actions
120
+
121
+ - **`list`** — print the learning records for the scoped epic (or cross-project): who learned what, by
122
+ stage, with status. Read-only.
123
+ - **`complete`** — mark a record `status: "learned"` and set `completedAt` (match on `member` + `concept`,
124
+ newest in-progress record). Record-only; advances nothing.
125
+
126
+ ## Hard rules
127
+
128
+ - **Opt-in, never a gate.** `yad-learn` never moves `currentStep`, never records an approval, and never
129
+ blocks any step. Learning is additive.
130
+ - **Read-only except the learning ledger.** It writes only `learning-records.json` + tutorial artifacts;
131
+ it never touches `state.json`, `approvals.json`, `comments.json`, or the contract lock.
132
+ - **Local-only output.** The records ledger and tutorials are gitignored personal artifacts — never
133
+ commit or push them, and never write them into a code repo. Ensure the hub `.gitignore` covers them
134
+ before writing (see Conventions).
135
+ - **Always works.** No DeepTutor / no connection → tutor harness-native. Never fail because a tool is
136
+ absent.
137
+ - **Grounded.** Prefer the project's own artifacts/kb; a generic answer with no project tie-in is a last
138
+ resort, and say so when that happens.
139
+ - **Attributable.** Every record names the `member` and `stage`, so the `yad-status` roll-up is a true
140
+ picture of the local learner's own skills log.
141
+
142
+ ## Reference
143
+ - Record schema, the mode→capability map, and the harness-native degrade path:
144
+ `references/learning-state.md`.
145
+ - The connection this consumes: `../yad-connect-learning/SKILL.md`.
146
+ - The read-only roll-up: `../yad-status/SKILL.md` (the local skills-log section).
@@ -0,0 +1,75 @@
1
+ # Learning state — record schema, capability map, degrade path
2
+
3
+ How `yad-learn` records a learner's own learning, drives DeepTutor, and degrades. The records are the
4
+ evidence base for the **local skills-log roll-up** in `yad-status`.
5
+
6
+ ## Location
7
+
8
+ - Per-epic ledger: `epics/EP-<slug>/.sdlc/learning-records.json` (append-only JSON array).
9
+ - Cross-project ledger (no epic scoped): `.sdlc/learning-records.json`.
10
+ - Rendered tutorials: `epics/EP-<slug>/learning/<member>--<concept-slug>.md` (or `.sdlc/learning/`).
11
+
12
+ (`config.yaml` `learning.records` and `learning.artifacts`.)
13
+
14
+ **Local-only.** Every path above is personal output and is **gitignored — never committed or pushed**, to
15
+ the product hub or any code repo. `yad-learn` ensures the hub `.gitignore` lists them before writing. The
16
+ only committed learning file is the connection registry `.sdlc/learning.json`.
17
+
18
+ ## Record schema
19
+
20
+ ```json
21
+ {
22
+ "member": "alice", // the learner (default: invoking user)
23
+ "concept": "contract versioning", // what was learned
24
+ "context": "why the surface is hash-locked", // optional focus
25
+ "stage": "architecture-review", // SDLC stage the learner was at; null if unscoped
26
+ "mode": "explain", // explain | deep | quiz
27
+ "tool": "deeptutor", // deeptutor | harness-native
28
+ "sessionId": "…", // DeepTutor session id; null when harness-native
29
+ "tutorial": "learning/alice--contract-versioning.md",
30
+ "comprehension": null, // quiz signal (e.g. "4/5") when mode: quiz, else null
31
+ "status": "in-progress", // in-progress | learned
32
+ "requestedAt": "2026-06-14",
33
+ "completedAt": null // set by `action: complete`
34
+ }
35
+ ```
36
+
37
+ ## Rules
38
+
39
+ - **Append-only.** `learn` pushes a new record. `complete` mutates the newest in-progress record matching
40
+ `member` + `concept` (status → `learned`, set `completedAt`). Never rewrite history.
41
+ - **Attributable.** `member` + `stage` are always set so the local roll-up is accurate.
42
+ - **No secrets.** Records hold concept text + references only — never keys or raw tool output beyond the
43
+ rendered tutorial.
44
+ - **Never commit the ledger or tutorials.** They are personal, local-only artifacts: gitignored, never
45
+ committed or pushed (to the hub or a code repo). Only `.sdlc/learning.json` is committed.
46
+
47
+ ## Mode → DeepTutor capability
48
+
49
+ | mode | capability | invocation |
50
+ |------|------------|------------|
51
+ | `explain` | `chat` | `deeptutor run chat "<concept> — in context of <…>" --kb <kb> --format json` |
52
+ | `deep` | `deep_research` | `deeptutor run deep_research "<…>" --kb <kb> --format json` |
53
+ | `quiz` | `deep_question` | `deeptutor run deep_question "<…>" --kb <kb> --format json` → record `comprehension` |
54
+
55
+ `--format json` is **NDJSON**: one event per line, each with `type` (`content` | `tool_call` |
56
+ `tool_result` | `done`) and `session_id`. Concatenate `content` into the tutorial; read `session_id` from
57
+ `done`.
58
+
59
+ ## Harness-native degrade
60
+
61
+ When `.sdlc/learning.json` is absent, `tool: "none"`, or `source: "harness-native"`:
62
+
63
+ 1. Read the scoped epic's `epic.md` / `architecture.md` / `contract.md` and any
64
+ `code-context/<repo>/code-map.md`.
65
+ 2. Explain `concept` (+ `context`) grounded in what those say, with one concrete example from the project.
66
+ 3. Write the tutorial + record exactly as the DeepTutor path does, with `"tool": "harness-native"` and
67
+ `"sessionId": null`.
68
+
69
+ The learning layer therefore **always works and always records** — DeepTutor only adds kb grounding,
70
+ deep research, and quizzes.
71
+
72
+ ## Greenfield / no epic
73
+
74
+ With no epic scoped, write to the cross-project ledger `.sdlc/learning-records.json` and tutorials to
75
+ `.sdlc/learning/`. `yad-status` reads both the per-epic and cross-project ledgers for the local roll-up.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yad-status
3
- description: 'Read-only view of an SDLC epic: prints the current step, each step''s dials (assistance/automation) and status, and which approvals are still required at the active gate. For stories in the build half it also prints each back-half step''s automation dial, status, and trust record (runs / % approved-unchanged / whether it clears the threshold to be earned), plus the system-wide kill-switch state — so the team can see WHY a step is automated and reverse it with evidence. Surfaces the Phase 5 instrumentation signals: per-step "earned but manual" (nudge cost) and, across multiple epics, a fleet roll-up (scale of read). Use when the user says "yad status", "where is epic EP-...", "what is blocking the gate", "show the trust record", or "fleet status".'
3
+ description: 'Read-only view of an SDLC epic: prints the current step, each step''s dials (assistance/automation) and status, and which approvals are still required at the active gate. For stories in the build half it also prints each back-half step''s automation dial, status, and trust record (runs / % approved-unchanged / whether it clears the threshold to be earned), plus the system-wide kill-switch state — so the team can see WHY a step is automated and reverse it with evidence. Also prints the cross-cutting personal skills-log roll-up from the LOCAL-ONLY learning ledger (gitignored, never committed/pushed — the local learner''s own learning, by stage). Surfaces the Phase 5 instrumentation signals: per-step "earned but manual" (nudge cost) and, across multiple epics, a fleet roll-up (scale of read). Use when the user says "yad status", "where is epic EP-...", "what is blocking the gate", "show the trust record", "team skills", or "fleet status".'
4
4
  ---
5
5
 
6
6
  # SDLC — Status (read-only)
@@ -22,8 +22,10 @@ report all if the user asked for an overview).
22
22
  Read `.sdlc/state.json`, `.sdlc/approvals.json`, `epic.md` frontmatter (for `repos`), and — if present
23
23
  — `.sdlc/contract-lock.json`. For the build half (Phase 4), also read — if present — every
24
24
  `.sdlc/build-state/<story-id>.json`, `.sdlc/trust-log.json`, and the `automation` block of
25
- `skills/sdlc/config.yaml` (`back_steps`, `trust_threshold`, `locked_steps`, `kill_switch`). Do not
26
- modify any of them.
25
+ `skills/sdlc/config.yaml` (`back_steps`, `trust_threshold`, `locked_steps`, `kill_switch`). For the
26
+ cross-cutting learning layer, also read — if present — the **local-only** `.sdlc/learning-records.json`
27
+ (the per-epic learning ledger, gitignored) and the project-wide `{project-root}/.sdlc/learning-records.json`.
28
+ Do not modify any of them.
27
29
 
28
30
  ### Step 3 — Report
29
31
  Print, in this order:
@@ -82,13 +84,28 @@ Print, in this order:
82
84
  recommendation to flip — earning the evidence and flipping the dial stay deliberate human acts
83
85
  (`yad-run action: set-dial`). See `docs/phase-5-build-plan.md` §"What to instrument now".
84
86
 
85
- 9. **Fleet roll-up (overview only).** When the user asked for an overview, or more than one epic exists
86
- under `{project-root}/epics/`, print a one-line-per-epic roll-up across the fleet: each epic's
87
- `currentStep` (front gate) and, for stories in the build half, a count of back-half steps **waiting
88
- at a human gate** and of steps flagged **earned-but-manual**. Close with fleet totals (epics at each
89
- front gate; total earned-but-manual back steps). This is the *scale-of-read* signal the Phase 5
90
- trigger watches — when this roll-up stops fitting in one glance, that is the measured bottleneck.
91
- Still strictly read-only; it only scans the per-epic files.
87
+ 9. **My skills (the learning layer — local-only).** If `.sdlc/learning-records.json` exists for the epic
88
+ (or the project-wide ledger does), print the **personal skills-log** roll-up from it read-only. These
89
+ records are **local-only (gitignored, never committed or pushed)**, so this reflects only the local
90
+ learner's own learning, not the team's. Show:
91
+ - **By member:** each `member` present in the local ledger with the concepts they have `learned` and
92
+ those `in-progress` (count + names).
93
+ - **By stage:** how many learning requests landed at each SDLC `stage` (e.g. `architecture-review: 3`),
94
+ so heavy-learning stages stand out.
95
+ - **Tool:** whether tutoring ran on `deeptutor` (grounded in the kb) or `harness-native`, per the
96
+ records' `tool` field.
97
+ This section is purely informational — learning is opt-in and never gates a step (it is produced by
98
+ `yad-learn`). If no learning ledger exists, omit the section silently (greenfield/learning not used).
99
+
100
+ 10. **Fleet roll-up (overview only).** When the user asked for an overview, or more than one epic exists
101
+ under `{project-root}/epics/`, print a one-line-per-epic roll-up across the fleet: each epic's
102
+ `currentStep` (front gate) and, for stories in the build half, a count of back-half steps **waiting
103
+ at a human gate** and of steps flagged **earned-but-manual**, plus a **local skills-log** count (records
104
+ in the local-only `learning-records.json`: learned / in-progress). Close with fleet totals (epics at
105
+ each front gate; total earned-but-manual back steps; total concepts learned locally across the fleet).
106
+ This is the
107
+ *scale-of-read* signal the Phase 5 trigger watches — when this roll-up stops fitting in one glance,
108
+ that is the measured bottleneck. Still strictly read-only; it only scans the per-epic files.
92
109
 
93
110
  ### Hard rule
94
111
  This skill is strictly read-only. If the user wants to comment, approve, or advance, point them to