create-pmos 0.47.0 → 0.48.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 (71) hide show
  1. package/package.json +1 -1
  2. package/payload/AGENTS-HUMAN.md +1 -1
  3. package/payload/AGENTS.md +1 -1
  4. package/payload/KIT-VERSION +1 -1
  5. package/payload/mods/pmos-cockpit/.claude-plugin/plugin.json +1 -1
  6. package/payload/mods/pmos-cockpit/README.md +4 -2
  7. package/payload/mods/pmos-cockpit/hooks/lib/commands.mjs +34 -6
  8. package/payload/mods/pmos-cockpit/hooks/lib/grants.mjs +22 -3
  9. package/payload/mods/pmos-cockpit/hooks/lib/guard.mjs +16 -3
  10. package/payload/mods/pmos-cockpit/hooks/register.tsx +37 -18
  11. package/payload/planning/evals/eval-calibration.md +1 -1
  12. package/payload/planning/okrs/health-budgets.md +1 -1
  13. package/payload/scripts/pmos-log.sh +18 -8
  14. package/payload/scripts/pmos-model.js +233 -2
  15. package/payload/scripts/status-facts.js +204 -0
  16. package/payload/scripts/workflow-state.js +52 -0
  17. package/payload/state/discoveries.md +1 -1
  18. package/workspace/README.md +2 -2
  19. package/workspace/bin/live-notes.js +133 -0
  20. package/workspace/design-parity.js +328 -21
  21. package/workspace/doc-category-bench.js +165 -0
  22. package/workspace/fixtures/doc-category-labelled.json +167 -0
  23. package/workspace/guide/initiatives-and-next-steps.md +15 -2
  24. package/workspace/guide/knowledge-graph.md +83 -1
  25. package/workspace/guide/layout.md +29 -2
  26. package/workspace/guide/proactive-engine.md +6 -2
  27. package/workspace/guide/validate-with-typesafe.md +16 -1
  28. package/workspace/lib/claims.js +51 -2
  29. package/workspace/lib/doc-category-corrections.js +113 -0
  30. package/workspace/lib/doc-category-writeback.js +110 -0
  31. package/workspace/lib/doc-category.js +225 -0
  32. package/workspace/lib/engine/pmos-model.js +233 -2
  33. package/workspace/lib/engine/status-facts.js +204 -0
  34. package/workspace/lib/engine/workflow-state.js +52 -0
  35. package/workspace/lib/jev-categorize.js +399 -0
  36. package/workspace/lib/jev-claims.js +59 -15
  37. package/workspace/lib/jev-route.js +129 -0
  38. package/workspace/lib/kg-cli.js +3 -1
  39. package/workspace/lib/kg.js +6 -1
  40. package/workspace/lib/learn.js +5 -3
  41. package/workspace/lib/live-notes.js +890 -0
  42. package/workspace/lib/typesafe-settings.js +10 -2
  43. package/workspace/package-lock.json +1 -1
  44. package/workspace/package.json +5 -4
  45. package/workspace/public/pm/app.js +148 -79
  46. package/workspace/public/pm/data.js +58 -0
  47. package/workspace/public/pm/fixture.js +40 -2
  48. package/workspace/public/pm/modes-live.js +216 -18
  49. package/workspace/public/pm/panel-cockpit.js +636 -0
  50. package/workspace/public/pm/panel-detail.js +210 -8
  51. package/workspace/public/pm/panel-initiatives.js +9 -9
  52. package/workspace/public/pm/panel-newsess.js +145 -86
  53. package/workspace/public/pm/panel-repos.js +34 -17
  54. package/workspace/public/pm/panel-tabs.js +145 -27
  55. package/workspace/public/pm/state.js +45 -4
  56. package/workspace/public/pm/tab-doc.js +244 -16
  57. package/workspace/public/pm/tab-term.js +11 -1
  58. package/workspace/public/pm/tokens.css +4 -3
  59. package/workspace/public/pm/view-addrepo.js +207 -0
  60. package/workspace/public/pm/view-files.js +197 -0
  61. package/workspace/public/pm/view-guide.js +141 -0
  62. package/workspace/public/pm/view-knowledge.js +225 -0
  63. package/workspace/public/pm/view-memory.js +122 -0
  64. package/workspace/public/pm/view-portfolio.js +153 -0
  65. package/workspace/public/pm/view-reports.js +190 -0
  66. package/workspace/public/pm/view-scheduled.js +161 -0
  67. package/workspace/public/pm/view-skills.js +216 -0
  68. package/workspace/public/pm/view-today.js +168 -0
  69. package/workspace/public/pm/view-validate.js +171 -0
  70. package/workspace/server.js +290 -7
  71. package/workspace/skills/live-notes.skill +58 -0
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ /* doc-category-bench.js — scores lib/doc-category.js against the labelled set and counts what the repository leaves undecided
3
+ * (jev-doc-categorizer Run 1). Local only: no network, no model, nothing written.
4
+ *
5
+ * node doc-category-bench.js print the report
6
+ * node doc-category-bench.js --json print it as JSON
7
+ *
8
+ * node doc-category-bench.js --jev Run 3's measured pass: show how many snippets of the labelled set
9
+ * would go to Jev, and send nothing
10
+ * node doc-category-bench.js --jev --confirm N send them, with the PM's own key, and report the agreement
11
+ *
12
+ * The measured pass is the PM's own press, never the build's or CI's. It uses the key, the consent and the "categorize with
13
+ * Jev" switch the PM set in the workspace for this repository (D82), and it refuses unless N is the count it shows now.
14
+ *
15
+ * The labelled set is workspace/fixtures/doc-category-labelled.json. Its labels were PROPOSED by the agent and are not yet the
16
+ * PM's, so every agreement figure here is provisional, and the report says so.
17
+ */
18
+ 'use strict';
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+ const { execFileSync } = require('child_process');
22
+ const { categorize, namedFromRecords, CATEGORIES, UNDETERMINED } = require('./lib/doc-category');
23
+ const { frontmatter } = require('./lib/related-docs');
24
+
25
+ const REPO = path.join(__dirname, '..');
26
+ const LABELS = path.join(__dirname, 'fixtures', 'doc-category-labelled.json');
27
+
28
+ function trackedMd(root) {
29
+ return execFileSync('git', ['ls-files', '*.md'], { cwd: root, encoding: 'utf8', maxBuffer: 1 << 26 }).split('\n').filter(Boolean);
30
+ }
31
+ function namedMap(root, files) {
32
+ const records = [];
33
+ for (const f of files) {
34
+ if (!/(^|\/)initiatives\//.test(f)) continue;
35
+ try { records.push({ rel: f, fm: frontmatter(fs.readFileSync(path.join(root, f), 'utf8')) || {} }); } catch { /* unreadable */ }
36
+ }
37
+ return namedFromRecords(records);
38
+ }
39
+ function one(root, rel, named) {
40
+ let text = ''; try { text = fs.readFileSync(path.join(root, rel), 'utf8'); } catch { return null; }
41
+ let fm = {}; try { fm = frontmatter(text) || {}; } catch { /* no frontmatter */ }
42
+ return { fm, c: categorize({ rel, fm, text, named }) };
43
+ }
44
+
45
+ function run(root = REPO) {
46
+ const files = trackedMd(root);
47
+ const named = namedMap(root, files);
48
+ const labelled = JSON.parse(fs.readFileSync(LABELS, 'utf8'));
49
+ const rows = []; const confusion = {};
50
+ let present = 0; let decided = 0; let right = 0;
51
+ for (const r of labelled.rows) {
52
+ const x = one(root, r.path, named);
53
+ if (!x) { rows.push({ path: r.path, expected: r.expected, got: null, missing: true }); continue; }
54
+ present++;
55
+ const got = x.c.category;
56
+ if (x.c.decided) { decided++; if (got === r.expected) right++; }
57
+ const key = r.expected + ' → ' + got;
58
+ confusion[key] = (confusion[key] || 0) + 1;
59
+ rows.push({ path: r.path, expected: r.expected, got, basis: x.c.basis, decided: x.c.decided, ok: got === r.expected });
60
+ }
61
+ const byCategory = {}; const refs = { total: 0, decided: 0, undetermined: 0 }; let undetermined = 0;
62
+ for (const f of files) {
63
+ const x = one(root, f, named); if (!x) continue;
64
+ byCategory[x.c.category] = (byCategory[x.c.category] || 0) + 1;
65
+ if (x.c.category === UNDETERMINED) undetermined++;
66
+ if (x.fm.type === 'Reference') { refs.total++; if (x.c.decided) refs.decided++; else refs.undetermined++; }
67
+ }
68
+ const untested = CATEGORIES.filter((c) => !labelled.rows.some((r) => r.expected === c));
69
+ return {
70
+ provisional: true, labelled_by: labelled.labelled_by, tenant_files: labelled.tenant_files,
71
+ files: files.length, labelled: labelled.rows.length, present, decided,
72
+ agreement_on_decided: decided ? right / decided : null, agreement_overall: present ? right / present : null,
73
+ by_category: byCategory, undetermined, reference: refs, untested_categories: untested, confusion, rows,
74
+ };
75
+ }
76
+
77
+ if (require.main === module && !process.argv.includes('--jev')) {
78
+ const r = run();
79
+ if (process.argv.includes('--json')) { console.log(JSON.stringify(r, null, 1)); process.exit(0); }
80
+ const pct = (n) => (n == null ? 'n/a' : (100 * n).toFixed(1) + '%');
81
+ console.log('doc-category-bench — PROVISIONAL: the labels were proposed by the agent, not confirmed by the PM.');
82
+ console.log(`files ${r.files} · labelled ${r.labelled} (present ${r.present}) · decided ${r.decided}`);
83
+ console.log(`agreement on decided ${pct(r.agreement_on_decided)} · overall (undetermined counts as wrong) ${pct(r.agreement_overall)}`);
84
+ console.log('by category:', JSON.stringify(r.by_category));
85
+ console.log(`Reference-typed: ${r.reference.total} · sharpened ${r.reference.decided} · left undetermined ${r.reference.undetermined}`);
86
+ console.log('untested categories (no label in the set):', r.untested_categories.join(', ') || 'none');
87
+ console.log('tenant files:', r.tenant_files);
88
+ console.log('disagreements and undetermined rows:');
89
+ for (const row of r.rows.filter((x) => !x.ok)) console.log(` ${row.path}: expected ${row.expected}, got ${row.got}${row.basis ? ' (' + row.basis + ')' : ''}`);
90
+ }
91
+ /* ── Run 3: the measured pass through Jev ─────────────────────────────────────────────────────────────────────────────── */
92
+ /* The labelled rows to measure. A row the PM corrected is marked, and the bridge never sends it. */
93
+ function labelledRows(root, corrected = {}) {
94
+ const labelled = JSON.parse(fs.readFileSync(LABELS, 'utf8'));
95
+ const rows = [];
96
+ for (const r of labelled.rows) {
97
+ let text = ''; try { text = fs.readFileSync(path.join(root, r.path), 'utf8'); } catch { continue; }
98
+ let fm = {}; try { fm = frontmatter(text) || {}; } catch { /* no frontmatter */ }
99
+ rows.push({ rel: r.path, fm, text, expected: r.expected, corrected: !!corrected[r.path] });
100
+ }
101
+ return rows;
102
+ }
103
+ /* What the labelled set can and cannot measure: a category with no label in the set is untested, whatever Jev answers. */
104
+ function labelledSet() {
105
+ const labelled = JSON.parse(fs.readFileSync(LABELS, 'utf8'));
106
+ return { labelled_by: labelled.labelled_by, tenant_files: labelled.tenant_files,
107
+ untested_categories: CATEGORIES.filter((c) => !labelled.rows.some((r) => r.expected === c)) };
108
+ }
109
+ /**
110
+ * The measured pass. `confirm` is `{ requests, fingerprint }` from the plan the PM saw: both must match the plan now, so the
111
+ * PM confirms these files and not merely this count. The key is the saved key, or TYPESAFE_API_KEY in `env`.
112
+ */
113
+ async function jevPass({ root = REPO, stateDir, confirm = null, ask, askOpts = {}, env = process.env } = {}) {
114
+ const settings = require('./lib/typesafe-settings');
115
+ const jc = require('./lib/jev-categorize');
116
+ const corrections = require('./lib/doc-category-corrections');
117
+ const sd = stateDir || require('./lib/state-root').defaultRoot();
118
+ // the workspace keys a repository by the root it registered; a symlinked checkout may be registered by either path
119
+ let real = root; try { real = fs.realpathSync(root); } catch { /* keep as given */ }
120
+ const repoRoot = [root, real].find((r) => { const f = settings.getRepo(sd, r); return f.consent || f.categorize; }) || root;
121
+ const flags = settings.getRepo(sd, repoRoot);
122
+ const cacheDir = corrections.repoDir(sd, repoRoot);
123
+ const rows = labelledRows(root, corrections.get(cacheDir));
124
+ const plan = jc.measurePlan({ rows, exclude: flags.exclude });
125
+ const set = labelledSet();
126
+ if (confirm === null) return { plan, set };
127
+ if (!confirm || !Number.isInteger(confirm.requests) || typeof confirm.fingerprint !== 'string' || !confirm.fingerprint) {
128
+ return { plan, set, out: { ok: false, error: 'Confirm with the count and the files you saw, as the plan prints them: --confirm ' + plan.requests + ':' + plan.fingerprint } };
129
+ }
130
+ const out = await jc.measure({ rows, cacheDir, key: settings.getKey(sd, env), flags, exclude: flags.exclude,
131
+ expectRequests: confirm.requests, expectFingerprint: confirm.fingerprint, ...(ask ? { ask } : {}), askOpts });
132
+ return { plan, set, out };
133
+ }
134
+
135
+ if (require.main === module && process.argv.includes('--jev')) {
136
+ const i = process.argv.indexOf('--confirm');
137
+ let confirm = null;
138
+ if (i > 0) { const m = /^(\d+):([0-9a-f]{40})$/.exec(String(process.argv[i + 1] || '')); confirm = m ? { requests: Number(m[1]), fingerprint: m[2] } : {}; }
139
+ const setLines = (set) => {
140
+ console.log('untested categories (no label in the set): ' + (set.untested_categories.join(', ') || 'none'));
141
+ console.log('tenant files: ' + (set.tenant_files || 'none'));
142
+ if (set.untested_categories.length || typeof set.tenant_files !== 'number' || !set.tenant_files) console.log('This set cannot show whether Jev separates the untested categories. Add labelled tenant files for them before reading the result as an answer.');
143
+ };
144
+ jevPass({ confirm }).then(({ plan, set, out }) => {
145
+ if (!out) {
146
+ console.log(`The measured pass would send ${plan.requests} snippet(s) of the ${plan.labelled} labelled files, about ${plan.characters} characters, to ${plan.host}. Nothing was sent.`);
147
+ console.log('It sends labelled files the local rules already decide too, because it measures Jev on them (D82 point 11).');
148
+ console.log(`${plan.withheld_count} withheld by the credential scan · ${plan.excluded} excluded · ${plan.corrected} corrected by you, not sent.`);
149
+ setLines(set);
150
+ console.log(`To send, run: node doc-category-bench.js --jev --confirm ${plan.requests}:${plan.fingerprint}`);
151
+ return;
152
+ }
153
+ if (!out.ok) { console.log('✗ ' + out.error); process.exitCode = 1; return; }
154
+ const pct = (n) => (n == null ? 'n/a' : (100 * n).toFixed(1) + '%');
155
+ console.log('Measured pass — PROVISIONAL: the labels were proposed by the agent, not confirmed by the PM. Advisory (D40).');
156
+ console.log(`sent ${out.sent} · failed ${out.failed} · answered ${out.answered} of ${out.labelled} · agreement ${pct(out.agreement)} · unsure ${out.unsure} · unreadable ${out.unreadable} · not answered ${out.not_answered}`);
157
+ console.log(`withheld by the credential scan ${out.withheld_count} · excluded ${out.excluded} · corrected by you, not sent ${out.corrected}`);
158
+ setLines(set);
159
+ for (const [c, r] of Object.entries(out.by_category)) console.log(` ${c}: ${r.right}/${r.labelled} right, ${r.unsure} unsure`);
160
+ if (out.paused) console.log('paused: ' + out.paused.reason);
161
+ console.log('disagreements:');
162
+ for (const d of out.disagreements) console.log(` ${d.doc}: expected ${d.expected}, Jev ${d.got}${d.leading ? ' (between ' + d.leading.join(' and ') + ')' : ''}`);
163
+ });
164
+ }
165
+ module.exports = { run, trackedMd, namedMap, labelledRows, labelledSet, jevPass };
@@ -0,0 +1,167 @@
1
+ {
2
+ "labelled_by": "PROPOSED by Claude from reading each file, 2026-10-04. NOT yet confirmed by the PM. Agreement against these labels is provisional until the PM confirms or corrects each row.",
3
+ "from": "this repository at the Run 1 branch point",
4
+ "tenant_files": "none yet: the PM has not supplied about 20 real meeting notes, reports and tickets, so meeting-notes and ticket are untested against real files",
5
+ "rows": [
6
+ {
7
+ "path": "planning/prd/jev-claim-checks-prd.md",
8
+ "expected": "prd"
9
+ },
10
+ {
11
+ "path": "planning/prd/workspace-cockpit-nav-prd.md",
12
+ "expected": "prd"
13
+ },
14
+ {
15
+ "path": "planning/prd/workspace-skill-authoring-prd.md",
16
+ "expected": "prd"
17
+ },
18
+ {
19
+ "path": "planning/evals/jev-claim-checks-eval-rubric.md",
20
+ "expected": "spec-artifact"
21
+ },
22
+ {
23
+ "path": "planning/evals/knowledge-graph-eval-rubric.md",
24
+ "expected": "spec-artifact"
25
+ },
26
+ {
27
+ "path": "planning/initiatives/jev-claim-checks.md",
28
+ "expected": "spec-artifact"
29
+ },
30
+ {
31
+ "path": "planning/initiatives/workspace-cockpit-nav.md",
32
+ "expected": "spec-artifact"
33
+ },
34
+ {
35
+ "path": "okf/products/pmos/adr/d80-jev-claim-pairs.md",
36
+ "expected": "spec-artifact"
37
+ },
38
+ {
39
+ "path": "okf/products/pmos/adr/d65-two-graph-adlc.md",
40
+ "expected": "spec-artifact"
41
+ },
42
+ {
43
+ "path": "okf/products/pmos/adr/d01-control-plane.md",
44
+ "expected": "spec-artifact"
45
+ },
46
+ {
47
+ "path": "DECISIONS.md",
48
+ "expected": "spec-artifact"
49
+ },
50
+ {
51
+ "path": "pm-decisions.md",
52
+ "expected": "spec-artifact"
53
+ },
54
+ {
55
+ "path": "planning/okrs/health-budgets.md",
56
+ "expected": "spec-artifact"
57
+ },
58
+ {
59
+ "path": "planning/decisions-proposed-pmos-cockpit-mod.md",
60
+ "expected": "spec-artifact"
61
+ },
62
+ {
63
+ "path": "planning/briefs/roadmap-time-model-spike-brief.md",
64
+ "expected": "spec-artifact"
65
+ },
66
+ {
67
+ "path": "planning/design-system-plan.md",
68
+ "expected": "spec-artifact"
69
+ },
70
+ {
71
+ "path": "planning/explainers/jev-claim-checks-surface-explainer.md",
72
+ "expected": "knowledge"
73
+ },
74
+ {
75
+ "path": "planning/explainers/knowledge-graph-surface-explainer.md",
76
+ "expected": "knowledge"
77
+ },
78
+ {
79
+ "path": "okf/core/concepts/frontmatter-format.md",
80
+ "expected": "knowledge"
81
+ },
82
+ {
83
+ "path": "okf/core/playbooks/working-in-pmos.md",
84
+ "expected": "knowledge"
85
+ },
86
+ {
87
+ "path": "workspace/guide/validate-with-typesafe.md",
88
+ "expected": "knowledge"
89
+ },
90
+ {
91
+ "path": "README.md",
92
+ "expected": "knowledge"
93
+ },
94
+ {
95
+ "path": "workspace/README.md",
96
+ "expected": "knowledge"
97
+ },
98
+ {
99
+ "path": "kit/mods/pmos-cockpit/README.md",
100
+ "expected": "knowledge"
101
+ },
102
+ {
103
+ "path": "CLAUDE.md",
104
+ "expected": "knowledge"
105
+ },
106
+ {
107
+ "path": "kit/AGENTS.md",
108
+ "expected": "knowledge"
109
+ },
110
+ {
111
+ "path": "kit/SECURITY.md",
112
+ "expected": "knowledge"
113
+ },
114
+ {
115
+ "path": "okf/products/pmos/references/metrics/north-star-metric.md",
116
+ "expected": "knowledge"
117
+ },
118
+ {
119
+ "path": "planning/research/agent-memory.md",
120
+ "expected": "knowledge"
121
+ },
122
+ {
123
+ "path": "discoveries.md",
124
+ "expected": "report"
125
+ },
126
+ {
127
+ "path": "planning/autonomy-log.md",
128
+ "expected": "report"
129
+ },
130
+ {
131
+ "path": "planning/evals/acceptance-gate-anti-atrophy-dogfood.md",
132
+ "expected": "report"
133
+ },
134
+ {
135
+ "path": "planning/evals/builder-profiles-dogfood.md",
136
+ "expected": "report"
137
+ },
138
+ {
139
+ "path": "planning/evals/calibration-golden-set.md",
140
+ "expected": "report"
141
+ },
142
+ {
143
+ "path": "planning/radar/jtbd-map.md",
144
+ "expected": "report"
145
+ },
146
+ {
147
+ "path": "okf/core/templates/prd-template.md",
148
+ "expected": "other"
149
+ },
150
+ {
151
+ "path": "planning/archive/phase-build-sequences.md",
152
+ "expected": "other"
153
+ },
154
+ {
155
+ "path": "planning/evals/fixtures/injection-payloads/01-html-comment.md",
156
+ "expected": "other"
157
+ },
158
+ {
159
+ "path": "okf/index.md",
160
+ "expected": "other"
161
+ },
162
+ {
163
+ "path": "okf/log.md",
164
+ "expected": "other"
165
+ }
166
+ ]
167
+ }
@@ -2,7 +2,7 @@
2
2
  type: Guide
3
3
  title: "Guide: initiatives and next steps"
4
4
  description: "What the initiative detail shows, top to bottom: status, lifecycle control, and the next step the workspace proposes."
5
- timestamp: 2026-10-03
5
+ timestamp: 2026-10-04
6
6
  ---
7
7
 
8
8
  # Guide: initiatives and next steps
@@ -15,7 +15,20 @@ Select an initiative in the list. The detail opens in the detail column.
15
15
  2. **Lifecycle control.** Hold, close, cancel or reopen. Beneath it, the history of every change.
16
16
  3. **Next steps to done.** Everything between now and acceptance, in order. See below.
17
17
  4. **Phases and links.** The workflow phases and the external links.
18
- 5. **Artifacts.** Documents, conversations and files.
18
+ 5. **What the documents say.** Up to three lines, and Jev's suggestions if you turned them on. See below.
19
+ 6. **Artifacts.** Documents, conversations and files.
20
+
21
+ ## What the documents say
22
+
23
+ These lines show facts about the documents that the phases do not show. Each line gives its source: a commit, a file, a requirement id or the text of the record. A line never changes a phase, a status or a count, and nothing is written.
24
+
25
+ - **Since approval.** The PRD, rubric or brief changed in a commit after you approved the contract or accepted the work. The line gives the number of commits and the latest commit. A small edit, such as a whitespace fix, also shows here. Open the commit to see what changed.
26
+ - **Coverage.** A requirement id in the PRD that the rubric does not mention, or an id in the rubric that the PRD does not have. A mention is not a grade. If the rubric mentions no requirement id, the line says that coverage cannot be found.
27
+ - **Record says.** The `status:` line in the initiative record names a stage that the phases contradict. Edit the record if the line is wrong. The phases do not change.
28
+
29
+ If a check cannot run, for example in a shallow clone, the line says "Cannot tell" and gives the reason. A missing line means that the check has nothing to compare.
30
+
31
+ If **read documents for status** is on for the repository, lines that start with **Documents suggest** can follow. They are Jev's answers about the documents of this initiative: a PRD, rubric or brief that may be a stub, or a note that may contradict a requirement. Each line says *very likely*, *likely* or *possible*, says that it is a suggestion and names the model. Open the document to decide. See [Guide: validate a repository](validate-with-typesafe.md).
19
32
 
20
33
  ## Next steps
21
34
 
@@ -2,7 +2,7 @@
2
2
  type: Guide
3
3
  title: "Guide: find knowledge without reading whole files"
4
4
  description: "How to use pmos kg to find one card, section or decision without reading whole files, and the limits of the map."
5
- timestamp: 2026-10-03
5
+ timestamp: 2026-10-04
6
6
  ---
7
7
 
8
8
  # Guide: find knowledge without reading whole files
@@ -54,6 +54,88 @@ An unknown file, heading or decision stops with a message that says what was not
54
54
  - A file with no incoming link is not an error. It means no other file links to it.
55
55
  - A **derived** card comes from the first paragraph of a file that has no `description`.
56
56
 
57
+ ## Categories
58
+
59
+ Each Markdown file also has a **category**. The category is the kind of document as you would name it: `prd`, `meeting-notes`, `report`, `ticket`, `knowledge`, `spec-artifact` or `other`. A ticket also has a kind: `design`, `engineering` or `other`. The category is kept beside the `type` in the frontmatter. It does not replace the `type`, and it does not change a file.
60
+
61
+ The workspace decides the category with local rules only. It uses no model and sends nothing. It uses the first rule that applies, in this order:
62
+
63
+ 1. A `category:` line the author wrote.
64
+ 2. A `type` that maps to a category.
65
+ 3. An initiative record that names the file.
66
+ 4. The file name or the folder.
67
+ 5. The headings.
68
+
69
+ When a later rule disagrees with the rule that decided, the file keeps the earlier answer. A `Reference` or `Research` file with no better evidence has no category. It shows as `undetermined`. That is not the same as `other`: `other` means the file is none of the kinds, and `undetermined` means no rule could tell.
70
+
71
+ The Knowledge view shows the category after each document name. Point at it to see which rule decided. Press a category above the list to show only those documents, and press it again to show all. The category is advisory. `pmos kg stats` counts the files in each category.
72
+
73
+ ### Ask Jev about undetermined files
74
+
75
+ Jev can give a category to a file that the local rules leave `undetermined`. This is off until you turn it on. Jev never sees a file that already has a category from a local rule or from your correction. The measured pass below is the one exception for the local rules.
76
+
77
+ Three things must all be on before anything is sent:
78
+
79
+ 1. A TypeSafe key, saved on the Validate page.
80
+ 2. Validation, switched on for this repository.
81
+ 3. **Categorize with Jev**, the switch in the Knowledge view.
82
+
83
+ If one of them is off, the Knowledge view tells you which one.
84
+
85
+ To start:
86
+
87
+ 1. Turn on **categorize with Jev**.
88
+ 2. Press **ask Jev about undetermined files**. The view shows how many requests it will send, about how many characters, and the host. Nothing is sent yet.
89
+ 3. Press **confirm and send** to send that number. If the files changed after you looked, even when the number is the same, the send stops and you look again.
90
+
91
+ After the first confirmed send, the workspace sends only new or changed undetermined files. It does this when it reads the documents of this repository, at most once a minute. It reads them when it starts and when you open the Knowledge view. If more than 25 files wait, it does not send them. It tells you, and you confirm the count again.
92
+
93
+ What is sent for each file: the title, the headings and the start of the text, at most 3,000 characters. The file path and the whole file are not sent. A file under an excluded path is not sent. A file whose start looks like a password or a key is not sent.
94
+
95
+ Jev's answer shows as the category with `(jev)` after it. Point at it to see how sure Jev was, in words. If Jev was not sure, the file stays `undetermined`, and the tooltip names the two categories Jev was between. A Jev category is advisory. Each answer is kept on your computer, outside the repository, and the same text is not sent twice. Nothing is written into the repository.
96
+
97
+ If the service rejects the key two times, cannot be reached three times in a row, or sends three answers in a row that the workspace cannot read, sending stops for this repository. An answer that cannot be read is not sent again. Press **resume** to start again.
98
+
99
+ ### Measure how well Jev categorizes
100
+
101
+ The measured pass sends the files of the labelled set to Jev and compares the answers with the labels. It runs only when you start it in a terminal. The workspace never starts it.
102
+
103
+ The measured pass also sends labelled files that a local rule already decides, because it measures Jev on them. It does not send a file that you corrected. The three switches, the excluded paths and the password and key check apply as for the Knowledge view.
104
+
105
+ 1. Run `node workspace/doc-category-bench.js --jev`. It shows how many files it would send, about how many characters, the host, and a `--confirm` value. It sends nothing.
106
+ 2. Read which categories the labelled set cannot test. When a category has no label in the set, the result says nothing about that category.
107
+ 3. To send, run the command again with `--confirm` and the value it showed, for example `--confirm 40:372a…`. The value holds the count and the files. If the files changed, nothing is sent and you look again.
108
+
109
+ It uses the key that you saved on the Validate page, or `TYPESAFE_API_KEY` in the terminal. It prints the agreement, each category, how many answers were unsure, how many files were not sent and why, and every disagreement. The labels in the set are not yet confirmed, so the result is provisional. Only one pass at a time runs for a repository. If the workspace is sending, the command stops and sends nothing.
110
+
111
+ ### Correct a category
112
+
113
+ When a category is wrong, set the correct one. Your correction comes before all five rules.
114
+
115
+ 1. In the Knowledge view, press **fix** at the end of the document row.
116
+ 2. Select the category. For a `ticket`, also select the ticket kind.
117
+ 3. Press **save correction**.
118
+
119
+ The category after the document name changes. Point at it: it says `decided by pm correction`. When a rule gives a different category, the text names that rule too.
120
+
121
+ The workspace keeps your corrections in its runtime state directory, never in the repository. Each repository has its own corrections. A correction does not change a file. To remove a correction, press **fix** and then **clear correction**. The rules then decide again.
122
+
123
+ ### Write the category into the file
124
+
125
+ You can also write the category into the document, as a `category:` line in its frontmatter. This is a separate step, and it is the only step here that changes a file.
126
+
127
+ 1. Press **fix** and select the category.
128
+ 2. Press **write it into the file**. The workspace shows the change. It does not write yet.
129
+ 3. Examine the change. Press **apply** to write it, or **cancel**.
130
+
131
+ The workspace changes one `category:` line in the frontmatter block at the top of the file. For a ticket, it also changes one `ticket_kind:` line. It adds the line when there is none. No other line of the file changes.
132
+
133
+ The workspace does not write when:
134
+
135
+ - The file has no frontmatter block at the top. It does not add a block.
136
+ - The frontmatter has two `category:` lines.
137
+ - The file changed after the workspace showed you the change. Press **write it into the file** again to see the new change.
138
+
57
139
  ## Where the map is kept
58
140
 
59
141
  The command reads the tracked `.md` files of the Git repository you run it in. It keeps the map in the runtime state directory of the workspace, never in the repository. It builds the map again when the Git HEAD changes or when you edit a tracked `.md` file that is not yet committed. It does not use the cache for any other change.
@@ -2,12 +2,38 @@
2
2
  type: Guide
3
3
  title: "Guide: layout"
4
4
  description: "The three workspace columns: navigation, detail and tabs, and what each one holds."
5
- timestamp: 2026-10-03
5
+ timestamp: 2026-10-04
6
6
  ---
7
7
 
8
8
  # Guide: layout
9
9
 
10
- The workspace has three columns. They are, from left to right, navigation, detail and tabs.
10
+ On a desktop screen the workspace has four columns. They are, from left to right, the repository rail, the list, the detail and the tabs. A phone, and the address option `?layout=legacy`, keep the older layout with three columns: navigation, detail and tabs. The rest of this page describes those three columns.
11
+
12
+ ## The repository rail, the list and the tools
13
+
14
+ The rail is 64 pixels wide and shows one tile for each repository. A dot on a tile means that repository has something that needs you. The selected repository has no dot, because the list beside it shows what needs you. The `+` tile adds a repository and the menu button opens the tools: knowledge, memory, skills, scheduled tasks, validate, the guide and the others.
15
+
16
+ A tool opens as a tab, not in place of the list. Choose the same tool again and the existing tab comes to the front.
17
+
18
+ Press ⌘K (Ctrl-K) to jump to anything: an initiative, a repository, an open tab, a session or a tool. Type to filter, use the arrow keys to choose, and press Enter. Esc closes it.
19
+
20
+ Press ⌘↵ (Ctrl-Enter) to enter Focus. The rail and the list go out of view, the active tab takes the width, and the detail stays as a narrow slice on the right. Press Esc or Navigate to return. Focus does not restart a terminal.
21
+
22
+ Today is a tool tab. It shows what needs you, with an action and a reason to dismiss each item, what is being prepared, and a Repository / All switch.
23
+
24
+ Each tool tab shows a board: Today, All repos, Knowledge, Memory, Skills, Scheduled tasks, Validate, the guide and Reports. Reports is in the menu, under Library, and lists only the run reports that exist. If a part of a board has no data behind it, the board does not show that part, or it says that the data is not read.
25
+
26
+ The `+` tile on the rail opens Add repository as a tab. The tab shows the scan of the folder before you add it.
27
+
28
+ The list has a switch for Initiatives and Files. Choose Files to see the files of the current repository. Type in the filter to find a file. Press a file to open it in a tab.
29
+
30
+ Under a terminal tab, the scratchpad holds a note that you can send to the terminal, copy or clear. The `+` session button opens a chooser for the new session. In a document tab, the Alignment button opens a drawer on the right. It shows the consistency findings for the document and lists only the documents that have a concrete tie to it.
31
+
32
+ The list has a switch for Work, Today and All repos, a filter, and the groups Needs you, In progress and Done. The badge on a row names the step where the initiative is, for example `review`, `accept` or `build`.
33
+
34
+ The detail shows the title, the summary, the chips, the blocker (when the initiative is blocked), the phases and the artifacts. Only the phase where the initiative is opens by itself, and the task where it is has a highlight. Press a phase to open or close it. Under each artifact are its link and sync controls.
35
+
36
+ Each tab shows a dot, its title and, under the title, its initiative and its session. Press × on a tab to close it. The `+ session` button is at the right end of the tabs.
11
37
 
12
38
  ## Navigation
13
39
 
@@ -32,6 +58,7 @@ Press a file anywhere in the workspace to open it in a tab. Any text file opens,
32
58
  - **Markdown** opens as a document. You can edit it and save it.
33
59
  - **JSON** opens pretty-printed. If the file is not valid JSON, the tab shows the text as written and says why.
34
60
  - **JSONL** opens as numbered records, one for each line. The tab marks a line that is not valid JSON.
61
+ - **HTML** opens in `view` as the page it is. Use `raw` to see its source. The page cannot run scripts and cannot load anything from the network. To run the page's own scripts, press `run scripts`. This grant is for this tab only. The page can then run the scripts written inside it, but it still cannot load anything from the network, cannot load a script from another location, and cannot read the workspace. Press `scripts running — stop` to stop the scripts. Closing the tab also removes the grant.
35
62
  - **Other text** opens as numbered source lines. Spreadsheets, PDFs and images open in their own views.
36
63
 
37
64
  A tab for a file that is not markdown is read-only. It has no edit, diff or save control, because the workspace saves only markdown.
@@ -2,7 +2,7 @@
2
2
  type: Guide
3
3
  title: "Guide: Today and the proactive engine"
4
4
  description: "What the Today item shows, how the morning brief is made, and how the workspace works out what is waiting for you."
5
- timestamp: 2026-10-03
5
+ timestamp: 2026-10-04
6
6
  ---
7
7
 
8
8
  # Guide: Today and the proactive engine
@@ -46,7 +46,7 @@ Today learns from you, and only from you. The evidence is your own records on th
46
46
 
47
47
  - **Weights.** Three adjustments are added to an item's place in the order: one for its trigger (at most 8 points), one for its lane (at most 4) and one for its trigger at this time of day (at most 3). Time of day is morning 05-12, afternoon 12-17, evening 17-22 and night, in your local time. A cell moves only after 5 events, and moves less than the raw average. The total is at most 15, so learning reorders items that are close and cannot turn the stated order upside down. An item shows its adjustment and the counts behind it.
48
48
  - **What it never does.** It never lowers or hides what blocks on you: the needs and returned triggers get no negative adjustment and are never narrowed. Items of the morning brief teach no weight, because their order is fixed. Pause learning makes every weight zero and stops the weekly review, the proposals and the narrowing; feedback is still recorded.
49
- - **The weekly review.** About every 7 days, only while the workspace server runs, the workspace takes one snapshot. It does not catch up after a gap: it takes one snapshot of the last 7 days. **run the weekly review now** does the same on demand and is refused while learning is paused. Quiet hours hold scans, not this review.
49
+ - **The weekly review.** About every 7 days, only while the workspace server runs, the workspace takes one snapshot. It does not catch up after a gap: it takes one snapshot of the last 7 days. **run the weekly review now** does the same on demand and is refused while learning is paused. Quiet hours hold scans, not this review. The review runs from the proactive tick, so while the engine is switched off there is no weekly review either; **run the weekly review now** still works.
50
50
  - **The rollup.** For the last 7 days: the hit rate (useful and acted, over useful, acted, not useful, wrong priority and dismissed), the used-as-is rate (accepted over accepted and sent back), corrections per prepared run (sends-back over every session started from a step, reviewed or not), and the items you reported as missed. Every rate shows its count. With fewer than 5 rated items, or 3 runs, it says there is not enough evidence and shows no rate.
51
51
  - **The watermelon check.** It looks only when the hit rate is 0.6 or more. It then names any of these: 2 or more items reported as missed, a used-as-is rate under 0.5 over 3 or more reviewed runs, or 0.5 or more corrections per prepared run over 3 or more runs. A good hit rate with one of these under it is not a good week.
52
52
  - **Lessons.** The review proposes lessons from four templates: a trigger that was useful under 40% or at least 80% of the time (5 or more ratings), items you reported as missed (2 or more), and a trigger that did badly in one part of the day only. A lesson is a proposal. It is approved, rejected or retired only when you press the button. A rejected lesson is not proposed again for 28 days. At most 10 lessons are approved at once.
@@ -93,6 +93,10 @@ A verdict never changes a status, a lifecycle record or an acceptance. It is rec
93
93
  | quiet hours | A start and an end time. No automatic scan runs between them. |
94
94
  | pause learning | Stops all learning: weights are zero, and there is no weekly review, no proposal and no narrowing. Feedback is still recorded. |
95
95
 
96
+ When you save a setting, Today shows the saved value immediately. A read that started before the save does not replace it.
97
+
98
+ Text that you type in a setting (the name, the stalled days, the quiet hours) or in the "something was missed" box stays in the box until you save it. A refresh of Today does not clear it, and the box keeps the focus.
99
+
96
100
  ## The commands
97
101
 
98
102
  - `pmos proactive today` lists the items.
@@ -2,7 +2,7 @@
2
2
  type: Guide
3
3
  title: "Guide: validate a repository"
4
4
  description: "How the validate item checks that a repository agrees with itself, and the optional second check with TypeSafe."
5
- timestamp: 2026-10-03
5
+ timestamp: 2026-10-04
6
6
  ---
7
7
 
8
8
  # Guide: validate a repository
@@ -61,6 +61,21 @@ Jev's answers are **suspected**, not proven. They appear in their own group, **s
61
61
 
62
62
  Two rejected keys, or three failed requests in a row, pause automatic checking for that repository. The page says why and shows **resume**. The workspace appends suspected pairs to `claims.jsonl`. Those lines hold a short snippet of the claim. A pair that Jev found fine is not written.
63
63
 
64
+ ## Read documents for status
65
+
66
+ A second switch, **read documents for status**, is next to the first one. It is off until you turn it on. It sends texts only when the four conditions above also hold.
67
+
68
+ When it is on, the workspace asks Jev two more questions about the documents that belong to an initiative:
69
+
70
+ - **Is it a stub?** Each PRD, rubric and brief that the initiative record names, against the initiative's title and intent.
71
+ - **Does a note contradict a requirement?** Each other document whose frontmatter names the initiative, for example a meeting note, against the requirements of the initiative's PRD.
72
+
73
+ A document belongs to an initiative only if the record names its path or its own frontmatter names the initiative. Similar words do not make a link.
74
+
75
+ The first check after you turn this switch on records the documents that exist and sends nothing for them. After that, the workspace sends a document only when it changes. If you turn the switch off, the workspace forgets that starting point. When you turn it on again, it starts again from the documents that exist then. Documents that changed while the switch was off are not sent.
76
+
77
+ The answers appear in the initiative detail under **What the documents say**, as lines that start with **Documents suggest**. Each line says that it is a suggestion and names the model. A suggestion never changes a phase, a status or a count, and the workspace writes nothing to the document.
78
+
64
79
  ## Check with TypeSafe
65
80
 
66
81
  ## What leaves your machine