@hraness/kb 0.18.1 → 0.19.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 (38) hide show
  1. package/README.md +79 -21
  2. package/dist/authoring.js +2 -2
  3. package/dist/benchmark.js +3 -3
  4. package/dist/cli.js +16 -12
  5. package/dist/evaluation-builder.js +5 -5
  6. package/dist/evaluation-kb.js +5 -5
  7. package/dist/graph.js +3 -1
  8. package/dist/{index-zxdy5pby.js → index-5m2ydj5q.js} +2 -2
  9. package/dist/{index-cxfrakt7.js → index-ekpwvbra.js} +5 -2
  10. package/dist/{index-jsmvyyvf.js → index-ey46z1zf.js} +4 -4
  11. package/dist/{index-cv6fh7z5.js → index-gm9t95d9.js} +1 -1
  12. package/dist/{index-01jj6rbv.js → index-gxr0fctd.js} +3 -3
  13. package/dist/index-nd6nynv2.js +1162 -0
  14. package/dist/{index-s2gw5aw9.js → index-qwgsmtsz.js} +1 -1
  15. package/dist/{index-zzhgcwyt.js → index-vxmf14m1.js} +3 -3
  16. package/dist/{index-n5dd7r0v.js → index-xw9ac71d.js} +2 -2
  17. package/dist/{index-1vrd1rmn.js → index-ykvvkd77.js} +1 -1
  18. package/dist/index.js +30 -8
  19. package/dist/percolate.js +22 -2
  20. package/dist/portfolio.js +5 -5
  21. package/dist/sdk.js +4 -4
  22. package/dist/search.js +2 -2
  23. package/dist/semantic.js +3 -3
  24. package/dist/workflows/decision-context.js +5 -5
  25. package/dist/workflows/index.js +5 -5
  26. package/package.json +1 -1
  27. package/skills/kb/AGENTS.md +3 -0
  28. package/skills/kb/SKILL.md +39 -31
  29. package/skills/kb/agents/openai.yaml +2 -2
  30. package/skills/kb/references/companion-skills.md +96 -0
  31. package/skills/kb/references/customize.md +123 -0
  32. package/skills/kb/references/percolate.md +39 -7
  33. package/skills/kb/templates/companion-skill.template.md +57 -0
  34. package/src/authoring.ts +5 -3
  35. package/src/cli.ts +12 -7
  36. package/src/graph.ts +8 -1
  37. package/src/percolate.ts +1088 -17
  38. package/dist/index-dyqwejk5.js +0 -531
@@ -0,0 +1,123 @@
1
+ # Customize a KB setup
2
+
3
+ Design the smallest KB arrangement that answers the user's recurring memory
4
+ questions. Begin with an interview and read-only inspection. Do not install a
5
+ runtime, initialize a vault, build an index, access an account, or write a file
6
+ before the proposal has the user's approval.
7
+
8
+ ## Establish the boundary
9
+
10
+ Identify the repositories, vaults, people, agents, and time horizons in scope.
11
+ Ask what the KB must help a future agent recover, which information must remain
12
+ outside it, and which existing instructions govern the target paths. Treat the
13
+ user's explicit request as authorization for the named work. Do not extend it
14
+ to another path, repository, account, application, or integration.
15
+
16
+ For a new vault, ask for or propose an exact location. Do not require an
17
+ existing `index.md`. For an existing vault, resolve its front door and read the
18
+ applicable `AGENTS.md` files before proposing changes.
19
+
20
+ ## Inspect without mutation
21
+
22
+ Inspect only the surfaces needed to understand the current setup. Typical
23
+ evidence includes directory structure, existing Markdown conventions, scoped
24
+ agent guides, active plans, source records, repository paths, and available
25
+ local commands. Keep filesystem, application, account, network, and
26
+ integration access within the user's stated scope and the host's actual
27
+ permissions.
28
+
29
+ Do not run `kb doctor`, `kb init`, `kb index`, QMD, hybrid or semantic search,
30
+ an installer, or a command that may create a cache during this phase. Do not
31
+ create a hidden profile such as `.context/me.md` or infer personal context from
32
+ an ambient account.
33
+
34
+ ## Interview in small batches
35
+
36
+ Ask only questions whose answers change the proposed structure. Prefer a small
37
+ batch about one decision at a time:
38
+
39
+ - Which recurring questions should the KB answer?
40
+ - Which sources, maintained explanations, plans, and repository rules already
41
+ exist?
42
+ - Which writes should happen automatically, require review, or never happen?
43
+ - Which recurring action is common enough to justify a companion skill?
44
+
45
+ Summarize each resolved decision before moving to the next uncertain one. A
46
+ short interview may conclude that the standard profile or no change is best.
47
+
48
+ ## Propose the smallest useful change
49
+
50
+ Describe the exact files and surfaces before editing. Use this table:
51
+
52
+ | Surface | Exact target | Read | Write | Purpose | Approval |
53
+ | --- | --- | --- | --- | --- | --- |
54
+ | Vault | `<path>` | `<bounded inputs>` | `<files or none>` | `<memory question>` | `<approved or pending>` |
55
+
56
+ Propose zero to three companion skills. Each proposed skill must own a distinct
57
+ recurring request that the main `kb` router cannot express clearly enough. Do
58
+ not add a skill only to restate repository policy or wrap one command.
59
+
60
+ State the verification, idempotence, retry, and failure behavior for every
61
+ write. Keep Markdown and Git authoritative. Treat indexes, embeddings,
62
+ catalogs, graph reports, and caches as replaceable views.
63
+
64
+ ## Obtain approval
65
+
66
+ Present the proposal and wait when its writes are not already authorized by
67
+ the user's explicit request. Approval applies to the exact targets and
68
+ operations shown. A changed path, expanded repository, additional skill,
69
+ account surface, network action, or broader write requires renewed approval.
70
+
71
+ Silence, a denial, or an ambiguous response is not approval. Inspection does
72
+ not grant write authority. Discovery of a command, application, account, or
73
+ integration does not authorize its use.
74
+
75
+ ## Scaffold within the approved boundary
76
+
77
+ Create only approved paths. For a companion skill, read [Companion skill
78
+ contracts](companion-skills.md) and copy
79
+ [`companion-skill.template.md`](../templates/companion-skill.template.md) to
80
+ `<explicit-skill-root>/<name>/SKILL.md`. Never edit the template inside an
81
+ installed package or `node_modules`.
82
+
83
+ If approved execution needs the KB CLI, prepare the runtime now using the main
84
+ skill's pinned installation instructions. Installation does not authorize
85
+ `kb init`, indexing, semantic search, or vault writes. Run only the approved
86
+ commands and exact allowlisted writes.
87
+
88
+ The scaffold executor writes filesystem targets only. It never performs an
89
+ application, account, network, or integration write. A companion skill may
90
+ describe one of those later actions, but its execution is a separate runtime
91
+ request with its own exact proposal, approval, tool boundary, and result.
92
+
93
+ On a repeated request, compare the desired bytes with the approved targets.
94
+ Treat an exact match as a no-op. Stop on divergent existing content, a symlink,
95
+ a path that escapes the approved root, an unapproved external surface, or a
96
+ partial write. Report the retained state instead of overwriting, silently
97
+ retrying, or widening the boundary.
98
+
99
+ ## Start with real material
100
+
101
+ Use a small amount of material that exercises the agreed structure: one saved
102
+ source, one maintained explanation, one plan, or one repository-context
103
+ mapping. Do not manufacture empty directories, placeholder notes, a complete
104
+ ontology, or speculative metadata merely to make the vault look populated.
105
+
106
+ ## Verify and hand off
107
+
108
+ Verify every approved file and record the exact paths changed. Run the
109
+ narrowest applicable KB checks only when they were approved and the runtime is
110
+ available. State what remains unconfigured, which views are rebuildable, and
111
+ which action would require separate authority.
112
+
113
+ Keep durable output free of credentials, session material, account exports,
114
+ and hidden ambient context. Record source provenance and the boundary of any
115
+ incomplete acquisition.
116
+
117
+ ## Evolve an existing setup
118
+
119
+ Re-run the boundary, inspection, interview, proposal, and approval steps when
120
+ the vault's recurring questions change. Prefer a focused convention or skill
121
+ revision to a migration. Preserve authored Markdown and Git history, and do not
122
+ mass-rewrite metadata to fit a new taxonomy unless a measured retrieval or
123
+ maintenance problem justifies that work.
@@ -42,6 +42,16 @@ minimum of two therefore requires two shared signals, not merely both endpoints
42
42
  of one tag match. Other candidate kinds count their natural unit: supporting
43
43
  notes, mention occurrences, or authored hygiene evidence.
44
44
 
45
+ Percolation Result V2 reports a missing relationship as an unordered pair of
46
+ endpoints with `predicate: { "kind": "required" }`. The output does not choose
47
+ which note owns the assertion, its direction, or its predicate. In particular,
48
+ it never inserts `related-to` as a fallback. Read both notes and their evidence,
49
+ then choose a source, target, and predicate only when the prose establishes that
50
+ claim. Historical unversioned V1 results may contain a suggested predicate;
51
+ parse them through the explicit V1 compatibility surface and do not treat that
52
+ suggestion as an authored fact or silently upgrade it to V2. V1 remains
53
+ available through the 0.19 release line and is not removed before 0.20.0.
54
+
45
55
  For a missing concept, use `suggestedId`. When `collidesWith` is non-null, the
46
56
  natural ID is already an ordinary note, so KB chooses an unoccupied
47
57
  `*-concept` ID. Read the occupied note before deciding whether to create the
@@ -88,11 +98,26 @@ kb relation add notes/write-path supports notes/durable-agent-memory \
88
98
  --root "$KB_ROOT"
89
99
  ```
90
100
 
91
- Use a specific lower-kebab-case predicate. A local target is an exact
92
- vault-root note ID without `.md`. A reviewed cross-vault target is its stable
93
- qualified identity, such as `kb://hraness/kb/document-id`; never use a checkout
94
- path as cross-vault identity. Ground the assertion in nearby prose or evidence;
95
- the frontmatter is an indexable statement, not a substitute for explanation.
101
+ Use a specific lower-kebab-case predicate. Recommended predicates for common
102
+ KB evidence and maintenance claims are:
103
+
104
+ - `synthesizes` when the source combines and maintains conclusions from the
105
+ target material;
106
+ - `evidenced-by` when the target directly supports a claim in the source;
107
+ - `informed-by` when the target influenced the source without serving as its
108
+ direct evidence;
109
+ - `supersedes` when the source deliberately replaces the target as the current
110
+ account;
111
+ - `contradicts` when the source records a supported incompatible claim.
112
+
113
+ This vocabulary is advisory. A vault may use any canonical custom predicate
114
+ whose meaning its prose establishes. Do not assign a recommended predicate by
115
+ directory, note type, shared tags, chronology, or similarity alone. A local
116
+ target is an exact vault-root note ID without `.md`. A reviewed cross-vault
117
+ target is its stable qualified identity, such as
118
+ `kb://hraness/kb/document-id`; never use a checkout path as cross-vault
119
+ identity. Ground the assertion in nearby prose or evidence; the frontmatter is
120
+ an indexable statement, not a substitute for explanation.
96
121
 
97
122
  List or remove relationships without editing reciprocal notes:
98
123
 
@@ -103,8 +128,15 @@ kb relation remove notes/write-path supports notes/durable-agent-memory \
103
128
  ```
104
129
 
105
130
  Never write inverse edges, generated backlinks, inferred transitive
106
- relationships, or semantic-search scores into Markdown. Those are derived
107
- views.
131
+ relationships, reciprocal edges, similarity-derived relationships, or
132
+ semantic-search scores into Markdown. External or unclassified material is
133
+ outside this vocabulary evaluation and remains unresolved. Those are derived
134
+ views or review work.
135
+
136
+ The interview-first setup and relationship-review pattern builds on Frank
137
+ Chen's public notes about [designing a personal knowledge base with an
138
+ agent](https://gist.github.com/fxchen/773397095d7a6bffda621e4237da0da9)
139
+ and [extending it with skills](https://gist.github.com/fxchen/09cb410b22c9c5256d80243ee925b57e).
108
140
 
109
141
  ## Query before concluding
110
142
 
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: replace-with-skill-name
3
+ description: Replace with the recurring KB request that should select this skill.
4
+ ---
5
+
6
+ # Replace with the skill title
7
+
8
+ ## Use when
9
+
10
+ State the exact recurring KB request that this skill owns.
11
+
12
+ ## Do not use when
13
+
14
+ Route generic query, capture, plan, percolation, refresh, and validation work
15
+ to the public `kb` skill. State any additional exclusions that prevent an
16
+ unsafe or ambiguous match.
17
+
18
+ ## Inputs and preconditions
19
+
20
+ List required inputs, existing state, commands, and authorization. Do not
21
+ install, probe an account, create a cache, or mutate state while resolving
22
+ these preconditions.
23
+
24
+ ## Surfaces and authority
25
+
26
+ List every filesystem, repository, application, account, network, and
27
+ integration surface this workflow may read or write. Discovery and an existing
28
+ session grant no authority. The setup scaffold writes filesystem targets only;
29
+ describe any later external action as a separate runtime request with its own
30
+ proposal, approval, capable tool, and result.
31
+
32
+ ## Approval
33
+
34
+ Name the exact write targets and effects. State when existing user
35
+ authorization applies and which proposal changes require renewed approval.
36
+
37
+ ## Workflow
38
+
39
+ Describe the smallest deterministic sequence that produces the approved
40
+ result. Keep every effect inside the approved boundary.
41
+
42
+ ## Idempotence, retries, and failure
43
+
44
+ Treat matching output as a no-op. Stop on divergent existing content, path
45
+ escape, symbolic links, partial writes, or an unapproved surface. Do not
46
+ silently retry or overwrite.
47
+
48
+ ## Durable outputs and provenance
49
+
50
+ Name the files or records that persist, the evidence they retain, and their
51
+ authority. Exclude credentials, tokens, cookies, session data, and unrelated
52
+ ambient context.
53
+
54
+ ## Verification
55
+
56
+ Name the narrow checks that demonstrate the approved result and the KB
57
+ maintenance required after durable edits.
package/src/authoring.ts CHANGED
@@ -35,7 +35,10 @@ import {
35
35
  type NoteLock,
36
36
  type NoteLockOptions,
37
37
  } from "./note-lock.js";
38
- import { isCanonicalNoteId } from "./graph.js";
38
+ import {
39
+ isCanonicalNoteId,
40
+ isCanonicalRelationPredicate,
41
+ } from "./graph.js";
39
42
  import {
40
43
  parseDocumentId,
41
44
  parseQualifiedDocumentUri,
@@ -43,7 +46,6 @@ import {
43
46
 
44
47
  const MAX_NOTE_BYTES = 16 * 1024 * 1024;
45
48
  const NOTE_REVISION_PATTERN = /^sha256:[0-9a-f]{64}$/u;
46
- const PREDICATE_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
47
49
  const MAX_PARENT_DIRECTORY_ENTRIES = 100_000;
48
50
  const MAX_RECOVERY_LOCATIONS_PER_NOTE = 8;
49
51
 
@@ -259,7 +261,7 @@ export function normalizeRelationPredicate(value: string): string {
259
261
  .replaceAll("_", "-")
260
262
  .replace(/\s+/gu, "-")
261
263
  .replace(/-{2,}/gu, "-");
262
- if (!PREDICATE_PATTERN.test(normalized)) {
264
+ if (!isCanonicalRelationPredicate(normalized)) {
263
265
  throw new TypeError(`not a valid relation predicate: ${JSON.stringify(value)}`);
264
266
  }
265
267
  return normalized;
package/src/cli.ts CHANGED
@@ -81,6 +81,7 @@ import {
81
81
  MAX_PERCOLATION_NOTES,
82
82
  MAX_SCOPED_PERCOLATION_MENTION_PAIRS,
83
83
  percolateVault,
84
+ type PercolationCliOutputV2,
84
85
  type PercolationResult,
85
86
  } from "./percolate.js";
86
87
  import {
@@ -2693,7 +2694,7 @@ function renderPercolation(result: PercolationResult, note: string | undefined):
2693
2694
  );
2694
2695
  } else if (candidate.kind === "missing-relation") {
2695
2696
  lines.push(
2696
- ` relation ${safe(candidate.source)} ${safe(candidate.suggestedPredicate)} ${safe(candidate.target)} (${candidate.support} shared signals)`,
2697
+ ` relation pair {${safe(candidate.source)}, ${safe(candidate.target)}} (predicate required; ${candidate.support} shared signals)`,
2697
2698
  );
2698
2699
  } else if (candidate.kind === "unlinked-mention") {
2699
2700
  lines.push(
@@ -2754,13 +2755,17 @@ async function runPercolate(
2754
2755
  limit: command.limit,
2755
2756
  },
2756
2757
  );
2758
+ const jsonOutput: PercolationCliOutputV2 = {
2759
+ root: snapshot.root,
2760
+ note: command.note ?? null,
2761
+ minSupport: command.minSupport,
2762
+ limit: command.limit,
2763
+ schemaVersion: result.schemaVersion,
2764
+ candidates: result.candidates,
2765
+ truncated: result.truncated,
2766
+ };
2757
2767
  output.stdout(command.json
2758
- ? terminalSafeJson({
2759
- root: snapshot.root,
2760
- note: command.note ?? null,
2761
- minSupport: command.minSupport,
2762
- ...result,
2763
- })
2768
+ ? terminalSafeJson(jsonOutput)
2764
2769
  : sanitizeTerminalText(renderPercolation(result, command.note)));
2765
2770
  return 0;
2766
2771
  }
package/src/graph.ts CHANGED
@@ -327,6 +327,13 @@ type ParsedMetadata = {
327
327
  const relationPredicatePattern = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
328
328
  const maxNoteIdLength = 2_048;
329
329
 
330
+ /** Whether a value is the exact lower-kebab predicate accepted by the graph. */
331
+ export function isCanonicalRelationPredicate(value: string): boolean {
332
+ return value !== ""
333
+ && value === value.normalize("NFC")
334
+ && relationPredicatePattern.test(value);
335
+ }
336
+
330
337
  /**
331
338
  * Whether a value is the exact, extensionless vault-root ID used on disk.
332
339
  *
@@ -476,7 +483,7 @@ function parsedRelations(
476
483
  }
477
484
 
478
485
  const predicate = pair.key.value.normalize("NFC");
479
- if (!relationPredicatePattern.test(predicate)) {
486
+ if (!isCanonicalRelationPredicate(predicate)) {
480
487
  relationIssues.push(malformedRelation(
481
488
  source,
482
489
  predicateLine,