You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As a maintainer installing an external KB with install --source I want the install to honour what the source declares and to report what it actually did So that a legitimate external KB installs with its own namespacing and ends on a green summary, instead of applying the consuming project's prefix and reporting missing registries as failures
Where: apps/pair-cli/src/commands/install/handler.ts (summary + registry resolution), apps/pair-cli/src/config/loader.ts (source-config resolution), and apps/website/content/docs/customization/external-kb.mdx (which documents both defects as known limitations today).
Consolidates #397 (maintainer decision, 2026-08-05). The two defects were filed separately from the same #391 review, but they touch the same handler, and both are documented as caveats on the same docs page. Separate cards would have meant two PRs on one file with a rebase between them, and two passes over the same paragraph.
Epic Context
Parent Epic: none — standalone defects from the #391 review Status: Refined Priority: P1 (Should-Have) — confirmed: both defects sit on the primary path of the external-KB feature
Classification
risk:yellow · cost: green (not projected — Active: risk only)
Matrix — per dimension
Dimension
Tier
Source
Note
Service/domain criticality
yellow
KB default
tech/risk-matrix.md declares no ## Criticality Table → Medium default (D21)
Change/diff risk
yellow
story scope
Two behaviours in one handler plus a config-resolution change with a documented precedence rule. Contained, but it changes what install reports and what it applies
Business impact
yellow
subdomain class
Integration & Process Standardization (Supporting) — install/distribution
Security relevance
green
path heuristic
Reads a config file from the source KB; no credentials, no execution of source content
Coupling balance
green
subdomain volatility + integrations
No new cross-context integration
Tier = yellow (max rule). Gate checks for 🟡: lint + type + build + unit.
Problem — two defects, one surface
A — registries absent from the source are reported as failed (was #396)
Installing a KB that legitimately does not ship every registry (an external KB ships knowledge + skills, never adoption) ends in a red summary:
! Installation finished with errors (2 ok, 3 failed, 79ms)
with exit code 0 and no explanation of which registries were absent or why that is fine. A registry the source does not contain is not an error — it is nothing to install. There is also no way to declare the intent up front.
B — the source KB's own registry declaration is ignored (was #397)
An external KB declares its registries in its own pair.config.json (e.g. skills.prefix: "acme-kb"), but install --source <kb> resolves the consuming project's config (loadConfigWithOverrides), never the source's. With a default consuming project, the KB's skills install as pair-example-skill instead of acme-kb-example-skill, and the maintainer's declared namespacing silently does not apply. Today the only workaround is copying the KB's pair.config.json into the consuming project by hand.
Why they are one card
Both are on install/handler.ts; B additionally touches config/loader.ts. Both are currently written up as known limitations on the same docs page (external-kb.mdx), along with the caveats in the scaffolded README and the seed skill. Fixing one and not the other leaves that page half-corrected — and a reader with a caveat that no longer applies is worse served than one with two that do.
Acceptance Criteria
Functional Requirements
Given-When-Then Format:
Given a source KB that ships only knowledge + skills Wheninstall --source runs Then the summary reads as success and names the skipped registries with the reason, e.g. ✓ Installation complete (2 ok, 3 skipped — not shipped by this source); no registry is counted as failed
Given a registry present in the source that genuinely fails to install When install runs Then it is still reported as failed — skipped never masks a real failure, and the exit code reflects it
Given an external KB declaring skills.prefix: "acme-kb" When a default-configured project runs install --source <kb> Then its skills install as acme-kb-<skill> — the source's declaration is honoured without the consumer copying any config
Given a consuming project that has deliberately overridden the registry When install runs Then the project's own configuration wins, and the precedence is documented (source declaration < consuming project override) — no silent surprise in either direction
Given the summary When it distinguishes ok / skipped / failed Then the exit code follows the failures only, so automation can trust it (today it is 0 while the text says "with errors" — the two disagree)
Given the documentation When this story lands Then the caveats are removed from external-kb.mdx, the scaffolded README template and the seed skill template — all three places that currently tell the reader to work around these defects
Business Rules
Absent is not failed. A registry the source does not ship is a non-event; only a registry that exists and breaks is a failure.
Exit code and text never disagree. Whatever the summary claims, the status code says the same thing.
The source declares, the consumer overrides. The KB's declaration applies by default; an explicit override in the consuming project wins. Stated once, in the docs, as precedence.
A fixed defect leaves no caveat behind. The three documents that describe the workaround are part of the change, not a follow-up.
Edge Cases and Error Handling
Source config malformed: fall back to the consuming project's resolution and warn — never abort the install over a source's bad config, and never apply a half-parsed declaration.
Source declares a prefix that collides with an existing installed skill name: report the collision rather than overwriting.
Source declares registries the CLI does not know (newer KB, older CLI): skipped with a distinct reason ("declared by source, unknown to this CLI"), not silently dropped.
Everything skipped (a source that ships nothing installable): success is the wrong answer — report it as a no-op with the reason.
--source pointing at the official KB: precedence must not change the current behaviour for the default path.
Definition of Done Checklist
All acceptance criteria implemented and verified
Test written first for both halves: skipped-vs-failed distinction, and source-prefix honoured
Unit coverage for the reporting module (ok / skipped / failed, and exit code parity)
Round-trip coverage proving the prefix survives without copying the KB's config
Precedence rule (source < consumer override) documented where the config schema is described
Caveats removed from external-kb.mdx, scaffolded README template, seed skill template
External-KB smoke scenario asserts the green summary
Final Story Points: 3 (M) — the two halves were 2 + 2 as separate cards; together they are 3, because the handler and the docs page are touched once Confidence Level: High Sizing Justification: Half A is a reporting distinction plus exit-code parity. Half B is a resolution change with one precedence rule. The saving from consolidation is real but modest: one pass over handler.ts, one over the docs page, one review.
Sprint Capacity Validation
Sprint Fit Assessment: Yes Development Time Estimate: ~0.5 day Testing Time Estimate: ~0.25 day
Dependencies and Coordination
Story Dependencies
Prerequisite Stories: none Dependent Stories: none Shared Components: install/handler.ts, config/loader.ts, external-kb.mdx → no overlap with #395 (kb-manager/cache-manager.ts), so the two run in parallel. That separation is the point of the 2026-08-05 consolidation decision: same-file cards merge, different-file cards stay apart
External Dependencies
Related: #391 / #279 (where both were found) · #397 (consolidated here) · #395 (sibling from the same review, kept separate: it corrupts state outside the project and is P0)
Validation and Testing Strategy
Acceptance Testing Approach
Testing Methods: unit tests for the reporting distinction and for config precedence (source-only, consumer-override, malformed source); a round-trip install of a fixture external KB asserting both the prefix and the green summary; the external-KB smoke scenario extended. Test Data Requirements: fixture external KB shipping a subset of registries and declaring a prefix; a consuming project with and without its own override.
Success Metrics
A legitimate external KB installs with a green summary that names what was skipped and why
Its declared prefix applies with no hand-copied config
No document still tells the reader to work around either defect
Notes and Additional Context
Refinement Session Insights (2026-08-05):
Consolidated by decision, on evidence: both halves live in install/handler.ts and both are documented as caveats on the same page. Kept separate, they would have serialized on one file for a purely bureaucratic reason.
AC5 was added in refinement: today the text says "finished with errors" while the exit code is 0. Fixing the wording without fixing that disagreement would leave automation trusting the wrong signal.
AC6 is part of the fix, not documentation hygiene: three documents currently instruct the reader to work around these defects. A stale workaround costs more than the defect it describes.
Technical Analysis
Implementation Approach
Technical Strategy: separate "not shipped" from "failed" in the install reporting, and resolve registry declarations from the source KB with the consuming project's explicit override taking precedence.
Key Components:
install/handler.ts — summary composition (ok / skipped / failed) + exit-code parity, and the registry resolution call site
config/loader.ts — resolve the source KB's pair.config.json, with documented precedence
Story Statement
As a maintainer installing an external KB with
install --sourceI want the install to honour what the source declares and to report what it actually did
So that a legitimate external KB installs with its own namespacing and ends on a green summary, instead of applying the consuming project's prefix and reporting missing registries as failures
Where:
apps/pair-cli/src/commands/install/handler.ts(summary + registry resolution),apps/pair-cli/src/config/loader.ts(source-config resolution), andapps/website/content/docs/customization/external-kb.mdx(which documents both defects as known limitations today).Epic Context
Parent Epic: none — standalone defects from the #391 review
Status: Refined
Priority: P1 (Should-Have) — confirmed: both defects sit on the primary path of the external-KB feature
Classification
risk:yellow· cost: green (not projected —Active: riskonly)Matrix — per dimension
tech/risk-matrix.mddeclares no## Criticality Table→ Medium default (D21)Integration & Process Standardization(Supporting) — install/distributionTier = yellow (max rule). Gate checks for 🟡: lint + type + build + unit.
Problem — two defects, one surface
A — registries absent from the source are reported as failed (was #396)
Installing a KB that legitimately does not ship every registry (an external KB ships
knowledge+skills, neveradoption) ends in a red summary:with exit code 0 and no explanation of which registries were absent or why that is fine. A registry the source does not contain is not an error — it is nothing to install. There is also no way to declare the intent up front.
B — the source KB's own registry declaration is ignored (was #397)
An external KB declares its registries in its own
pair.config.json(e.g.skills.prefix: "acme-kb"), butinstall --source <kb>resolves the consuming project's config (loadConfigWithOverrides), never the source's. With a default consuming project, the KB's skills install aspair-example-skillinstead ofacme-kb-example-skill, and the maintainer's declared namespacing silently does not apply. Today the only workaround is copying the KB'spair.config.jsoninto the consuming project by hand.Why they are one card
Both are on
install/handler.ts; B additionally touchesconfig/loader.ts. Both are currently written up as known limitations on the same docs page (external-kb.mdx), along with the caveats in the scaffolded README and the seed skill. Fixing one and not the other leaves that page half-corrected — and a reader with a caveat that no longer applies is worse served than one with two that do.Acceptance Criteria
Functional Requirements
Given-When-Then Format:
Given a source KB that ships only
knowledge+skillsWhen
install --sourcerunsThen the summary reads as success and names the skipped registries with the reason, e.g.
✓ Installation complete (2 ok, 3 skipped — not shipped by this source); no registry is counted as failedGiven a registry present in the source that genuinely fails to install
When install runs
Then it is still reported as failed —
skippednever masks a real failure, and the exit code reflects itGiven an external KB declaring
skills.prefix: "acme-kb"When a default-configured project runs
install --source <kb>Then its skills install as
acme-kb-<skill>— the source's declaration is honoured without the consumer copying any configGiven a consuming project that has deliberately overridden the registry
When install runs
Then the project's own configuration wins, and the precedence is documented (source declaration < consuming project override) — no silent surprise in either direction
Given the summary
When it distinguishes ok / skipped / failed
Then the exit code follows the failures only, so automation can trust it (today it is 0 while the text says "with errors" — the two disagree)
Given the documentation
When this story lands
Then the caveats are removed from
external-kb.mdx, the scaffolded README template and the seed skill template — all three places that currently tell the reader to work around these defectsBusiness Rules
Edge Cases and Error Handling
--sourcepointing at the official KB: precedence must not change the current behaviour for the default path.Definition of Done Checklist
external-kb.mdx, scaffolded README template, seed skill templateStory Sizing and Sprint Readiness
Refined Story Points
Final Story Points: 3 (M) — the two halves were 2 + 2 as separate cards; together they are 3, because the handler and the docs page are touched once
Confidence Level: High
Sizing Justification: Half A is a reporting distinction plus exit-code parity. Half B is a resolution change with one precedence rule. The saving from consolidation is real but modest: one pass over
handler.ts, one over the docs page, one review.Sprint Capacity Validation
Sprint Fit Assessment: Yes
Development Time Estimate: ~0.5 day
Testing Time Estimate: ~0.25 day
Dependencies and Coordination
Story Dependencies
Prerequisite Stories: none
Dependent Stories: none
Shared Components:
install/handler.ts,config/loader.ts,external-kb.mdx→ no overlap with #395 (kb-manager/cache-manager.ts), so the two run in parallel. That separation is the point of the 2026-08-05 consolidation decision: same-file cards merge, different-file cards stay apartExternal Dependencies
Related: #391 / #279 (where both were found) · #397 (consolidated here) · #395 (sibling from the same review, kept separate: it corrupts state outside the project and is P0)
Validation and Testing Strategy
Acceptance Testing Approach
Testing Methods: unit tests for the reporting distinction and for config precedence (source-only, consumer-override, malformed source); a round-trip install of a fixture external KB asserting both the prefix and the green summary; the external-KB smoke scenario extended.
Test Data Requirements: fixture external KB shipping a subset of registries and declaring a prefix; a consuming project with and without its own override.
Success Metrics
Notes and Additional Context
Refinement Session Insights (2026-08-05):
install/handler.tsand both are documented as caveats on the same page. Kept separate, they would have serialized on one file for a purely bureaucratic reason.cache-manager.ts, it corrupts state outside the project, and it is P0 — bundling it here would have shipped a critical fix alongside two conveniences, classified by the worst dimension of the bundle.Technical Analysis
Implementation Approach
Technical Strategy: separate "not shipped" from "failed" in the install reporting, and resolve registry declarations from the source KB with the consuming project's explicit override taking precedence.
Key Components:
install/handler.ts— summary composition (ok / skipped / failed) + exit-code parity, and the registry resolution call siteconfig/loader.ts— resolve the source KB'spair.config.json, with documented precedenceexternal-kb.mdx, scaffolded README template, seed skill template — caveats removedData Flow:
--source→ source config (if valid) → merged with consumer overrides (consumer wins) → per-registry install → outcome classified ok / skipped / failed → summary + exit code.Integration Points: install path, config resolution, docs site, smoke suite.
Design: not required
Technical Risks and Mitigation
skippedused to hide a real failure