@kaddo/cli 3.20.0 → 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +3 -0
  2. package/dist/index.js +525 -77
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -505,6 +505,9 @@ create --from roadmap → owners → guard → explain`.
505
505
  | v3.16 | Knowledge Capsules: `kaddo capsule export/add`, External Knowledge in context/explain, new `capsule-agent` |
506
506
  | v3.17 | Knowledge Graph Export: `kaddo graph export` (`.kaddo/graph.json` + `.mmd`, `--scope`/`--format`); graph summary in context/explain |
507
507
  | v3.18 | Graph relationship quality & metadata hints: `graph-hints.md`/`.json`, quality levels, `graph-agent`; hints in context/explain/understand |
508
+ | v3.19 | Read-only MCP server `@kaddo/mcp` (resources, tools, prompts over stdio) |
509
+ | v3.20 | MCP derived tools: safe regeneration of context/explain/understand/graph/capsule-draft under `.kaddo/` |
510
+ | v3.21 | Reusable Skills layer (`kaddo add skills`); skills in context/explain/understand, agent prompts and MCP |
508
511
 
509
512
  **Optional modules (installed with `kaddo add`):**
510
513
 
package/dist/index.js CHANGED
@@ -1487,6 +1487,386 @@ var guardAdvancedModule = {
1487
1487
  ]
1488
1488
  };
1489
1489
 
1490
+ // src/skills/skills.ts
1491
+ function skill(id, title, group, appliesTo, body) {
1492
+ const frontMatter2 = [
1493
+ "---",
1494
+ "type: skill",
1495
+ `id: ${id}`,
1496
+ `title: ${title}`,
1497
+ "version: 1",
1498
+ `group: ${group}`,
1499
+ "applies_to:",
1500
+ ...appliesTo.map((a) => ` - ${a}`),
1501
+ "---",
1502
+ ""
1503
+ ].join("\n");
1504
+ return { id, title, group, appliesTo, content: frontMatter2 + body.trimStart() };
1505
+ }
1506
+ var ADR_WRITING = skill(
1507
+ "adr-writing",
1508
+ "ADR Writing Skill",
1509
+ "tech",
1510
+ ["decision-agent", "architecture-agent", "implementation-agent"],
1511
+ `
1512
+ # ADR Writing Skill
1513
+
1514
+ ## Purpose
1515
+
1516
+ Standardize how Architecture Decision Records are written so every decision is captured the same
1517
+ way and stays auditable.
1518
+
1519
+ ## When to use
1520
+
1521
+ When a real, consequential technical decision is being made or recognized \u2014 and only then.
1522
+
1523
+ ## Inputs
1524
+
1525
+ The context pack, the relevant Work Item or architecture note, and the decision being made.
1526
+
1527
+ ## Output
1528
+
1529
+ A single ADR containing: context, the decision, alternatives considered, consequences, the code
1530
+ paths it governs (\`code:\` globs when known) and the decision status (proposed / accepted /
1531
+ superseded).
1532
+
1533
+ ## Rules
1534
+
1535
+ - One ADR = one decision. Never mix unrelated decisions.
1536
+ - Never invent decisions; never write an ADR without a clear reason.
1537
+ - Record alternatives honestly, including the one chosen and why.
1538
+ - Prefer narrow governed \`code:\` globs over broad ones.
1539
+
1540
+ ## Quality checklist
1541
+
1542
+ - Context explains why the decision was needed.
1543
+ - The decision and its alternatives are explicit.
1544
+ - Consequences (positive and negative) are stated.
1545
+ - Status and governed paths are present.
1546
+
1547
+ ## Example output
1548
+
1549
+ \`\`\`md
1550
+ # ADR-0007 \u2014 Use SQLite for local persistence
1551
+ Status: accepted
1552
+ ## Context
1553
+ ...
1554
+ ## Decision
1555
+ ...
1556
+ ## Alternatives considered
1557
+ ...
1558
+ ## Consequences
1559
+ ...
1560
+ \`\`\`
1561
+ `
1562
+ );
1563
+ var WORK_ITEM_REFINEMENT = skill(
1564
+ "work-item-refinement",
1565
+ "Work Item Refinement Skill",
1566
+ "delivery",
1567
+ ["work-item-agent", "backlog-agent", "roadmap-agent"],
1568
+ `
1569
+ # Work Item Refinement Skill
1570
+
1571
+ ## Purpose
1572
+
1573
+ Standardize how a Work Item is sharpened from a rough idea into a ready, implementable item.
1574
+
1575
+ ## When to use
1576
+
1577
+ When improving a draft Work Item, or turning a backlog idea / roadmap candidate into a ready item.
1578
+
1579
+ ## Inputs
1580
+
1581
+ The context pack and the Work Item (draft or candidate).
1582
+
1583
+ ## Output
1584
+
1585
+ An improved Work Item with: problem, expected result, scope, out of scope, acceptance criteria,
1586
+ validation (how to test it), definition of done, open questions and dependencies.
1587
+
1588
+ ## Rules
1589
+
1590
+ - Do not implement code.
1591
+ - Do not expand scope without explicit confirmation.
1592
+ - Do not create mega Work Items \u2014 split when it covers multiple outcomes.
1593
+ - Keep acceptance criteria testable.
1594
+
1595
+ ## Quality checklist
1596
+
1597
+ - Problem and expected result are unambiguous.
1598
+ - Scope and out-of-scope are explicit.
1599
+ - Acceptance criteria and validation are present and testable.
1600
+ - Open questions and dependencies are surfaced, not hidden.
1601
+
1602
+ ## Example output
1603
+
1604
+ A Work Item markdown with the sections above filled in, ready for the implementation-agent.
1605
+ `
1606
+ );
1607
+ var OWNERSHIP_SUGGESTION = skill(
1608
+ "ownership-suggestion",
1609
+ "Ownership Suggestion Skill",
1610
+ "tech",
1611
+ ["ownership-agent", "work-item-agent", "graph-agent", "implementation-agent"],
1612
+ `
1613
+ # Ownership Suggestion Skill
1614
+
1615
+ ## Purpose
1616
+
1617
+ Standardize how precise \`code:\` ownership globs are proposed so Guard can relate code changes to
1618
+ the right knowledge.
1619
+
1620
+ ## When to use
1621
+
1622
+ When a Work Item or artifact is missing ownership, or its ownership is too broad/inaccurate.
1623
+
1624
+ ## Inputs
1625
+
1626
+ The context pack, the Work Item, and the technical inventory / codebase notes.
1627
+
1628
+ ## Output
1629
+
1630
+ A \`code:\` glob proposal, e.g.
1631
+
1632
+ \`\`\`yaml
1633
+ code:
1634
+ - src/database/**
1635
+ - src/cli/**
1636
+ \`\`\`
1637
+
1638
+ ## Rules
1639
+
1640
+ - Prefer small, specific globs; avoid \`src/**\`.
1641
+ - Use only real paths; validate intent against the Work Item.
1642
+ - Explain uncertainty instead of guessing.
1643
+ - Propose only \u2014 the human applies with \`kaddo owners suggest\`.
1644
+
1645
+ ## Quality checklist
1646
+
1647
+ - Every glob maps to a real path relevant to the item.
1648
+ - No catch-all globs.
1649
+ - Uncertainty is marked.
1650
+
1651
+ ## Example output
1652
+
1653
+ The YAML \`code:\` block above plus a one-line rationale per glob.
1654
+ `
1655
+ );
1656
+ var GRAPH_METADATA_REVIEW = skill(
1657
+ "graph-metadata-review",
1658
+ "Graph Metadata Review Skill",
1659
+ "tech",
1660
+ ["graph-agent", "ownership-agent", "work-item-agent"],
1661
+ `
1662
+ # Graph Metadata Review Skill
1663
+
1664
+ ## Purpose
1665
+
1666
+ Standardize how \`kaddo graph export\` hints become precise relationship front matter.
1667
+
1668
+ ## When to use
1669
+
1670
+ When relationship quality is partial/sparse/empty, or when reviewing \`.kaddo/graph-hints.md\`.
1671
+
1672
+ ## Inputs
1673
+
1674
+ The context pack, \`.kaddo/graph.json\` and \`.kaddo/graph-hints.md\`, plus the affected artifacts.
1675
+
1676
+ ## Output
1677
+
1678
+ Front matter proposals, e.g.
1679
+
1680
+ \`\`\`yaml
1681
+ capabilities:
1682
+ - local-persistence
1683
+ decisions:
1684
+ - ADR-0001
1685
+ code:
1686
+ - src/database/**
1687
+ capsules:
1688
+ - orders-service
1689
+ \`\`\`
1690
+
1691
+ ## Rules
1692
+
1693
+ - Never invent relationships, paths or IDs.
1694
+ - Do not try to resolve every hint at once \u2014 propose what is justified.
1695
+ - Do not modify artifacts; the human applies and re-runs \`kaddo graph export\`.
1696
+
1697
+ ## Quality checklist
1698
+
1699
+ - Each proposal maps to a real artifact/path/capability/ADR/capsule.
1700
+ - Globs are narrow; uncertainty is marked.
1701
+
1702
+ ## Example output
1703
+
1704
+ The YAML proposal above, grouped per artifact, with a short reason each.
1705
+ `
1706
+ );
1707
+ var CAPSULE_WRITING = skill(
1708
+ "capsule-writing",
1709
+ "Capsule Writing Skill",
1710
+ "integration",
1711
+ ["capsule-agent", "architecture-agent", "product-agent"],
1712
+ `
1713
+ # Capsule Writing Skill
1714
+
1715
+ ## Purpose
1716
+
1717
+ Standardize how a Knowledge Capsule is written/reviewed so external consumers get safe, useful
1718
+ context.
1719
+
1720
+ ## When to use
1721
+
1722
+ When creating or refining a Knowledge Capsule for sharing with another project.
1723
+
1724
+ ## Inputs
1725
+
1726
+ The context pack, capabilities, current-state, decisions and any public contracts.
1727
+
1728
+ ## Output
1729
+
1730
+ A capsule with: purpose, responsibilities, capabilities, contracts, dependencies, risks, owners,
1731
+ out of scope and usage notes.
1732
+
1733
+ ## Rules
1734
+
1735
+ - Never include secrets, tokens, credentials, source code, PII or unnecessary internal detail.
1736
+ - Never invent contracts; mark unknowns.
1737
+ - Summarize boundaries; prefer "unknown" over guessing.
1738
+
1739
+ ## Quality checklist
1740
+
1741
+ - Purpose and boundaries are clear.
1742
+ - Contracts are real, not invented.
1743
+ - No secrets/source/PII included.
1744
+
1745
+ ## Example output
1746
+
1747
+ A \`*.capsule.md\` with the sections above.
1748
+ `
1749
+ );
1750
+ var LEARNING_CAPTURE = skill(
1751
+ "learning-capture",
1752
+ "Learning Capture Skill",
1753
+ "delivery",
1754
+ ["implementation-agent", "guard-agent", "architecture-agent", "work-item-agent"],
1755
+ `
1756
+ # Learning Capture Skill
1757
+
1758
+ ## Purpose
1759
+
1760
+ Standardize how a Work Item's learning is captured when it closes.
1761
+
1762
+ ## When to use
1763
+
1764
+ When finishing a Work Item, after implementation and verification.
1765
+
1766
+ ## Inputs
1767
+
1768
+ The Work Item, the diff/result, and any decisions or surprises that came up.
1769
+
1770
+ ## Output
1771
+
1772
+ A learning record: what was implemented, what changed, what was learned, what decision emerged,
1773
+ which knowledge must be updated, and what remains pending.
1774
+
1775
+ ## Rules
1776
+
1777
+ - Do not close a Work Item without validation.
1778
+ - Do not hide failures; record them honestly.
1779
+ - Do not assume everything is done if errors remain.
1780
+
1781
+ ## Quality checklist
1782
+
1783
+ - Implemented vs changed vs learned are distinct.
1784
+ - Knowledge to update is named (ADR / capabilities / current-state).
1785
+ - Pending items are listed.
1786
+
1787
+ ## Example output
1788
+
1789
+ A short learning section appended to the Work Item or a learning note.
1790
+ `
1791
+ );
1792
+ var IMPLEMENTATION_PLANNING = skill(
1793
+ "implementation-planning",
1794
+ "Implementation Planning Skill",
1795
+ "delivery",
1796
+ ["implementation-agent", "work-item-agent"],
1797
+ `
1798
+ # Implementation Planning Skill
1799
+
1800
+ ## Purpose
1801
+
1802
+ Standardize the plan produced before implementation starts.
1803
+
1804
+ ## When to use
1805
+
1806
+ Before writing code for a ready Work Item.
1807
+
1808
+ ## Inputs
1809
+
1810
+ The context pack and the ready Work Item.
1811
+
1812
+ ## Output
1813
+
1814
+ A plan with: technical scope, expected files, risks, validations, out of scope, implementation
1815
+ steps, and stop criteria (when to pause and ask).
1816
+
1817
+ ## Rules
1818
+
1819
+ - Do not start coding without confirmation.
1820
+ - Do not expand scope.
1821
+ - Never make commits or push \u2014 suggest only.
1822
+
1823
+ ## Quality checklist
1824
+
1825
+ - Scope and expected files are explicit.
1826
+ - Risks and validations are listed.
1827
+ - Stop criteria are defined.
1828
+
1829
+ ## Example output
1830
+
1831
+ A numbered plan covering the sections above, ending with a request to confirm before coding.
1832
+ `
1833
+ );
1834
+ var SKILLS = [
1835
+ ADR_WRITING,
1836
+ WORK_ITEM_REFINEMENT,
1837
+ OWNERSHIP_SUGGESTION,
1838
+ GRAPH_METADATA_REVIEW,
1839
+ CAPSULE_WRITING,
1840
+ LEARNING_CAPTURE,
1841
+ IMPLEMENTATION_PLANNING
1842
+ ];
1843
+ var SKILL_GROUPS = {
1844
+ delivery: ["work-item-refinement", "implementation-planning", "learning-capture"],
1845
+ tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review"],
1846
+ integration: ["capsule-writing"]
1847
+ };
1848
+ var SKILL_GROUP_NAMES = Object.keys(SKILL_GROUPS);
1849
+ var RECOMMENDED_SKILLS = [...SKILL_GROUPS.delivery, ...SKILL_GROUPS.tech];
1850
+ function skillInstallPath(id) {
1851
+ return `knowledge/skills/${id}/skill.md`;
1852
+ }
1853
+ function selectSkills(opts) {
1854
+ if (opts.all) {
1855
+ return { ids: SKILLS.map((s) => s.id), label: "all skills" };
1856
+ }
1857
+ if (opts.group) {
1858
+ const group = opts.group;
1859
+ const ids = SKILL_GROUPS[group];
1860
+ if (!ids) {
1861
+ throw new Error(
1862
+ `Unknown skill group "${opts.group}". Valid groups: ${SKILL_GROUP_NAMES.join(", ")}.`
1863
+ );
1864
+ }
1865
+ return { ids, label: `group: ${group}` };
1866
+ }
1867
+ return { ids: RECOMMENDED_SKILLS, label: "recommended skills" };
1868
+ }
1869
+
1490
1870
  // src/agents/responsibility.ts
1491
1871
  var RESPONSIBILITY_MATRIX = {
1492
1872
  "business-agent": {
@@ -1758,14 +2138,30 @@ function renderLanguageRule() {
1758
2138
  ""
1759
2139
  ].join("\n");
1760
2140
  }
2141
+ function renderSkillsSection(agent) {
2142
+ const applicable = SKILLS.filter((s) => s.appliesTo.includes(agent));
2143
+ if (applicable.length === 0) return "";
2144
+ return [
2145
+ "## Reusable Skills",
2146
+ "",
2147
+ "Apply these reusable skills when relevant (install with `kaddo add skills`; read them in",
2148
+ "`knowledge/skills/` or via the Kaddo MCP server):",
2149
+ "",
2150
+ ...applicable.map((s) => `- **${s.id}** \u2014 ${s.title}.`),
2151
+ ""
2152
+ ].join("\n");
2153
+ }
1761
2154
  function withResponsibilityTrace(fileName, content) {
1762
2155
  const agent = fileName.replace(/\.md$/, "");
1763
2156
  if (!RESPONSIBILITY_MATRIX[agent]) return content;
2157
+ const skills = renderSkillsSection(agent);
2158
+ const skillsBlock = skills ? `${skills}
2159
+ ` : "";
1764
2160
  return `${content.trimEnd()}
1765
2161
 
1766
2162
  ${renderLanguageRule()}
1767
2163
  ${renderAgentBoundaries(agent)}
1768
- ${renderAgentTrace(agent)}`;
2164
+ ${skillsBlock}${renderAgentTrace(agent)}`;
1769
2165
  }
1770
2166
 
1771
2167
  // src/agents/prompts.ts
@@ -3532,74 +3928,40 @@ var agentsModule = {
3532
3928
  };
3533
3929
 
3534
3930
  // src/modules/skills.ts
3931
+ var skillsReadme = {
3932
+ path: "knowledge/skills/README.md",
3933
+ content: [
3934
+ "# Skills",
3935
+ "",
3936
+ "Reusable **skill** definitions \u2014 capabilities shared across agents. A skill does not decide",
3937
+ "WHAT to do (that is the agent); it defines HOW to do one thing well. Agents orchestrate;",
3938
+ "skills standardize; knowledge grounds; MCP exposes.",
3939
+ "",
3940
+ "Skills never execute anything \u2014 they are reusable instructions, not tools. They never run",
3941
+ "git, never call an LLM and never modify files.",
3942
+ "",
3943
+ "## Installed skills",
3944
+ "",
3945
+ ...SKILLS.map((s) => `- \`${s.id}\` (${s.group}) \u2014 ${s.title}. Applies to: ${s.appliesTo.join(", ")}.`),
3946
+ "",
3947
+ "## Groups",
3948
+ "",
3949
+ ...Object.entries(SKILL_GROUPS).map(([g, ids]) => `- **${g}**: ${ids.join(", ")}`),
3950
+ "",
3951
+ "Install: `kaddo add skills` (recommended), `--all`, or `--group <delivery|tech|integration>`."
3952
+ ].join("\n")
3953
+ };
3954
+ var skillFiles = SKILLS.map((s) => ({
3955
+ path: skillInstallPath(s.id),
3956
+ content: s.content
3957
+ }));
3535
3958
  var skillsModule = {
3536
3959
  name: "skills",
3537
- description: "Reusable skills \u2014 capabilities shared across agents, teams, or projects",
3960
+ description: "Reusable skills \u2014 capabilities shared across agents (adr-writing, work-item-refinement, \u2026)",
3538
3961
  configKey: "module_skills",
3539
3962
  dirs: ["knowledge/skills"],
3540
- files: [
3541
- {
3542
- path: "knowledge/skills/.gitkeep",
3543
- content: ""
3544
- },
3545
- {
3546
- path: "knowledge/skills/README.md",
3547
- content: [
3548
- "# Skills",
3549
- "",
3550
- "This directory contains skill definitions \u2014 reusable capabilities that agents",
3551
- "or team members can invoke.",
3552
- "",
3553
- "A skill is a well-defined, repeatable capability with:",
3554
- "- Clear inputs and outputs",
3555
- "- A defined trigger (when to use it)",
3556
- "- Known preconditions",
3557
- "",
3558
- "Skills differ from agents: a skill is a single capability,",
3559
- "an agent is an orchestrator that uses skills."
3560
- ].join("\n")
3561
- }
3562
- ],
3563
- workItemTypes: [
3564
- {
3565
- name: "skill",
3566
- knowledgeLevel: "K3",
3567
- description: "Skill \u2014 a reusable capability shared across agents, teams, or projects.",
3568
- questions: [
3569
- {
3570
- id: "what_it_does",
3571
- prompt: "What does this skill do?",
3572
- placeholder: "e.g. Reads the artifact front matters and returns ownership gaps",
3573
- frontMatterField: "what_it_does",
3574
- required: true
3575
- },
3576
- {
3577
- id: "trigger",
3578
- prompt: "When should this skill be invoked?",
3579
- placeholder: "e.g. When a guard FYI has no matching artifact with code globs",
3580
- frontMatterField: "trigger",
3581
- required: true
3582
- },
3583
- {
3584
- id: "inputs_outputs",
3585
- prompt: "What are the inputs and outputs?",
3586
- placeholder: "e.g. Input: list of touched files. Output: suggested artifact IDs to update",
3587
- frontMatterField: "inputs_outputs",
3588
- required: true
3589
- }
3590
- ],
3591
- qualityGate: [
3592
- "Skill is scoped to a single, reusable capability.",
3593
- "Trigger condition is explicit.",
3594
- "Inputs and outputs are defined."
3595
- ],
3596
- extraFrontMatter: {
3597
- skill_type: "analysis",
3598
- reusable_by: [],
3599
- code: []
3600
- }
3601
- }
3602
- ]
3963
+ files: [skillsReadme, ...skillFiles],
3964
+ workItemTypes: []
3603
3965
  };
3604
3966
 
3605
3967
  // src/modules/global-docs.ts
@@ -5346,7 +5708,7 @@ function runIgnoreRemove(artifactId) {
5346
5708
  }
5347
5709
 
5348
5710
  // src/commands/explain.ts
5349
- import matter3 from "gray-matter";
5711
+ import matter4 from "gray-matter";
5350
5712
  import { parse as parseYaml9 } from "yaml";
5351
5713
 
5352
5714
  // src/core/delivery-phase.ts
@@ -6084,6 +6446,42 @@ function loadGraphHints(dir) {
6084
6446
  }
6085
6447
  }
6086
6448
 
6449
+ // src/services/installed-skills.ts
6450
+ import matter3 from "gray-matter";
6451
+ var SKILLS_DIR = join("knowledge", "skills");
6452
+ function discoverInstalledSkills(dir) {
6453
+ const base = join(dir, SKILLS_DIR);
6454
+ if (!exists(base) || !isDir(base)) return [];
6455
+ const out = [];
6456
+ for (const entry of readDir(base)) {
6457
+ const skillFile = join(base, entry, "skill.md");
6458
+ if (!isFile(skillFile)) continue;
6459
+ try {
6460
+ const { data } = matter3(readFile(skillFile));
6461
+ if (data.type && String(data.type) !== "skill") continue;
6462
+ const id = String(data.id ?? entry);
6463
+ out.push({
6464
+ id,
6465
+ title: String(data.title ?? id),
6466
+ group: String(data.group ?? "unknown"),
6467
+ appliesTo: Array.isArray(data.applies_to) ? data.applies_to.map(String).filter(Boolean) : [],
6468
+ relPath: `${SKILLS_DIR.replace(/\\/g, "/")}/${entry}/skill.md`
6469
+ });
6470
+ } catch {
6471
+ }
6472
+ }
6473
+ return out.sort((a, b) => a.id.localeCompare(b.id));
6474
+ }
6475
+ function skillGroupCounts(skills) {
6476
+ const counts = {};
6477
+ for (const s of skills) counts[s.group] = (counts[s.group] ?? 0) + 1;
6478
+ return counts;
6479
+ }
6480
+ function skillsForAgents(skills, agents) {
6481
+ const set = new Set(agents.map((a) => a.replace(/\.md$/, "")));
6482
+ return skills.filter((s) => s.appliesTo.some((a) => set.has(a))).map((s) => s.id);
6483
+ }
6484
+
6087
6485
  // src/core/knowledge-discovery.ts
6088
6486
  var KNOWLEDGE4 = "knowledge";
6089
6487
  var CONSOLIDATED_TYPE = {
@@ -6416,6 +6814,10 @@ function buildProjectExplanation(dir) {
6416
6814
  externalCapsules: loadExternalCapsules(dir),
6417
6815
  graph: loadGraphSummary(dir),
6418
6816
  graphHints: loadGraphHints(dir),
6817
+ skills: (() => {
6818
+ const installed = discoverInstalledSkills(dir);
6819
+ return { total: installed.length, byGroup: skillGroupCounts(installed) };
6820
+ })(),
6419
6821
  layers,
6420
6822
  roadmap,
6421
6823
  mappedModules,
@@ -6566,6 +6968,15 @@ function renderExplanationHuman(exp) {
6566
6968
  if (exp.graph.generatedAt) lines.push(`- Last exported: ${exp.graph.generatedAt}`);
6567
6969
  lines.push("");
6568
6970
  }
6971
+ if (exp.skills.total > 0) {
6972
+ lines.push(`## Skills installed: ${exp.skills.total}`);
6973
+ const groups = Object.entries(exp.skills.byGroup).sort((a, b) => a[0].localeCompare(b[0]));
6974
+ if (groups.length > 0) {
6975
+ lines.push("Groups:");
6976
+ for (const [g, n] of groups) lines.push(`- ${g}: ${n}`);
6977
+ }
6978
+ lines.push("");
6979
+ }
6569
6980
  if (exp.missingKnowledge.length > 0) {
6570
6981
  lines.push("## Missing Knowledge");
6571
6982
  for (const m of exp.missingKnowledge) lines.push(`- ${m}`);
@@ -6609,7 +7020,7 @@ function readKnowledge(dir) {
6609
7020
  if (!exists(knowledgePath)) return null;
6610
7021
  try {
6611
7022
  const raw = readFile(knowledgePath);
6612
- const { data, content } = matter3(raw);
7023
+ const { data, content } = matter4(raw);
6613
7024
  return { content, data };
6614
7025
  } catch {
6615
7026
  return null;
@@ -6620,7 +7031,7 @@ function readRoadmap(dir) {
6620
7031
  if (!exists(roadmapPath)) return null;
6621
7032
  try {
6622
7033
  const raw = readFile(roadmapPath);
6623
- const { content } = matter3(raw);
7034
+ const { content } = matter4(raw);
6624
7035
  return content.trim();
6625
7036
  } catch {
6626
7037
  return null;
@@ -6789,7 +7200,7 @@ function runExplain(opts) {
6789
7200
  }
6790
7201
 
6791
7202
  // src/core/context-pack.ts
6792
- import matter4 from "gray-matter";
7203
+ import matter5 from "gray-matter";
6793
7204
  var CONTEXT_PACK_VERSION = "1";
6794
7205
  var ARCH_DIR6 = "knowledge";
6795
7206
  function readScanJson(dir) {
@@ -6802,7 +7213,7 @@ function readScanJson(dir) {
6802
7213
  }
6803
7214
  }
6804
7215
  function firstParagraph2(markdown) {
6805
- const body = matter4(markdown).content.trim();
7216
+ const body = matter5(markdown).content.trim();
6806
7217
  const para = body.split("\n\n").map((p2) => p2.trim()).find((p2) => p2 && !p2.startsWith("#"));
6807
7218
  return para ?? "";
6808
7219
  }
@@ -6975,6 +7386,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
6975
7386
  external: loadExternalCapsules(dir),
6976
7387
  graph: loadGraphSummary(dir),
6977
7388
  graphHints: loadGraphHints(dir),
7389
+ skills: discoverInstalledSkills(dir).map((s) => s.id),
6978
7390
  mappedModules,
6979
7391
  missing,
6980
7392
  // VS-052: the handoff is driven by the REAL phase, not project.state, so the pack never
@@ -7168,6 +7580,12 @@ function renderContextPack(pack) {
7168
7580
  `);
7169
7581
  }
7170
7582
  }
7583
+ if (pack.skills.length > 0) {
7584
+ parts.push("## Skills\n");
7585
+ parts.push("Available reusable skills (agents apply these; content is not inlined):\n");
7586
+ parts.push(pack.skills.map((s) => `- ${s}`).join("\n") + "\n");
7587
+ parts.push("Read full skill definitions in `knowledge/skills/` or via the Kaddo MCP server (`kaddo://skills`).\n");
7588
+ }
7171
7589
  parts.push("## Missing Context\n");
7172
7590
  if (missing.length > 0) {
7173
7591
  parts.push(missing.map((m) => `- ${m}`).join("\n") + "\n");
@@ -7489,6 +7907,14 @@ function runUnderstand() {
7489
7907
  if (assessment.nextStep) {
7490
7908
  console.log(`Next step: ${assessment.nextStep}`);
7491
7909
  }
7910
+ const installedSkills = discoverInstalledSkills(dir);
7911
+ if (installedSkills.length > 0 && assessment.recommendedAgents.length > 0) {
7912
+ const recSkills = skillsForAgents(installedSkills, assessment.recommendedAgents);
7913
+ if (recSkills.length > 0) {
7914
+ console.log("Recommended skills:");
7915
+ for (const s of recSkills) console.log(` - ${s}`);
7916
+ }
7917
+ }
7492
7918
  if (exp.externalCapsules.length > 0) {
7493
7919
  console.log("");
7494
7920
  console.log("External knowledge:");
@@ -7803,7 +8229,7 @@ function runStatus() {
7803
8229
  }
7804
8230
 
7805
8231
  // src/commands/learn.ts
7806
- import matter5 from "gray-matter";
8232
+ import matter6 from "gray-matter";
7807
8233
  var ARCH_DIR9 = "knowledge";
7808
8234
  var WORK_ITEMS_DIR2 = "knowledge/delivery/work-items";
7809
8235
  function findWorkItemFile(dir, id) {
@@ -7815,7 +8241,7 @@ function findWorkItemFile(dir, id) {
7815
8241
  }
7816
8242
  function updateWorkItemFile(filePath, learning) {
7817
8243
  const raw = readFile(filePath);
7818
- const { data, content } = matter5(raw);
8244
+ const { data, content } = matter6(raw);
7819
8245
  data.status = "done";
7820
8246
  data.completed_at = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
7821
8247
  let updatedContent = content;
@@ -7840,7 +8266,7 @@ ${learning.trim()}
7840
8266
  ${learning.trim()}
7841
8267
  `;
7842
8268
  }
7843
- const newRaw = matter5.stringify(updatedContent, data);
8269
+ const newRaw = matter6.stringify(updatedContent, data);
7844
8270
  writeFile(filePath, newRaw);
7845
8271
  }
7846
8272
  async function runLearn(artifactId) {
@@ -7968,6 +8394,12 @@ function selectAgentModuleFiles(files, opts, state) {
7968
8394
  );
7969
8395
  return { files: selected, label };
7970
8396
  }
8397
+ function selectSkillModuleFiles(files, opts) {
8398
+ const { ids, label } = selectSkills({ all: opts.all, group: opts.group });
8399
+ const wanted = new Set(ids.map((id) => skillInstallPath(id)));
8400
+ const selected = files.filter((f) => f.path.endsWith("README.md") || wanted.has(f.path));
8401
+ return { files: selected, label };
8402
+ }
7971
8403
  function markModuleInstalled(dir, configKey, moduleName) {
7972
8404
  const configPath = join(dir, CONFIG_PATH5);
7973
8405
  if (!exists(configPath)) return;
@@ -8028,6 +8460,15 @@ function runAdd(moduleName, opts = {}, dir = cwd()) {
8028
8460
  console.error(err instanceof Error ? err.message : String(err));
8029
8461
  process.exit(1);
8030
8462
  }
8463
+ } else if (mod.name === "skills") {
8464
+ try {
8465
+ const sel = selectSkillModuleFiles(mod.files, opts);
8466
+ filesToInstall = sel.files;
8467
+ log2.info(`Installing skills (${sel.label}).`);
8468
+ } catch (err) {
8469
+ console.error(err instanceof Error ? err.message : String(err));
8470
+ process.exit(1);
8471
+ }
8031
8472
  }
8032
8473
  const written = [];
8033
8474
  const skipped = [];
@@ -8058,6 +8499,13 @@ function runAdd(moduleName, opts = {}, dir = cwd()) {
8058
8499
  outro2("Agents installed. Kaddo prepares context \u2014 your LLM does the interpretation.");
8059
8500
  return;
8060
8501
  }
8502
+ if (mod.name === "skills") {
8503
+ log2.info("Skills are reusable capabilities agents apply \u2014 they never run anything.");
8504
+ log2.info("More skills: `kaddo add skills --all` or `--group <delivery|tech|integration>`.");
8505
+ log2.info("Read them in `knowledge/skills/` or via the Kaddo MCP server (`kaddo://skills`).");
8506
+ outro2("Skills installed. Agents orchestrate; skills standardize.");
8507
+ return;
8508
+ }
8061
8509
  if (mod.workItemTypes.length > 0) {
8062
8510
  log2.info(`New work item types available:`);
8063
8511
  for (const t of mod.workItemTypes) {
@@ -8068,7 +8516,7 @@ function runAdd(moduleName, opts = {}, dir = cwd()) {
8068
8516
  }
8069
8517
 
8070
8518
  // src/core/ownership-suggest.ts
8071
- import matter6 from "gray-matter";
8519
+ import matter7 from "gray-matter";
8072
8520
  var SCAN_PATH = ".kaddo/scan.json";
8073
8521
  function normalizeGlob(input) {
8074
8522
  let g = input.trim().replace(/\\/g, "/");
@@ -8190,11 +8638,11 @@ function suggestGlobs(artifact, signals) {
8190
8638
  return [...new Set(out)];
8191
8639
  }
8192
8640
  function applyOwnership(raw, globs, mode = "replace") {
8193
- const parsed = matter6(raw);
8641
+ const parsed = matter7(raw);
8194
8642
  const existing = toStringArray3(parsed.data.code);
8195
8643
  const next = mode === "append" ? [.../* @__PURE__ */ new Set([...existing, ...globs])] : [...new Set(globs)];
8196
8644
  const data = { ...parsed.data, code: next };
8197
- return matter6.stringify(parsed.content, data);
8645
+ return matter7.stringify(parsed.content, data);
8198
8646
  }
8199
8647
 
8200
8648
  // src/commands/owners.ts
@@ -10444,7 +10892,7 @@ modulesCmd.command("map").description("Register a secondary repository as a modu
10444
10892
  modulesCmd.command("list").description("List mapped modules").action(() => {
10445
10893
  runModulesList();
10446
10894
  });
10447
- program.command("add [module]").description("Install an optional Kaddo module (adr, incident, rfc, migration, legacy, agents, standards, security, stack, git-strategy)").option("--all", "For `add agents`: install every agent (not just the recommended set)").option("--group <name>", "For `add agents`: install one layer group (business, product, tech, delivery, utilities)").action((moduleName, opts) => {
10895
+ program.command("add [module]").description("Install an optional Kaddo module (adr, incident, rfc, migration, legacy, agents, skills, standards, security, stack, git-strategy)").option("--all", "For `add agents` / `add skills`: install every item (not just the recommended set)").option("--group <name>", "For `add agents`: business|product|tech|delivery|utilities. For `add skills`: delivery|tech|integration").action((moduleName, opts) => {
10448
10896
  runAdd(moduleName ?? "", { all: opts.all, group: opts.group });
10449
10897
  });
10450
10898
  program.parseAsync(process.argv).catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.20.0",
3
+ "version": "3.21.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {