create-pmos 0.515.0 → 0.517.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 (79) hide show
  1. package/package.json +41 -71
  2. package/payload/KIT-VERSION +2 -2
  3. package/payload/planning/evals/eval-calibration.md +1 -1
  4. package/payload/planning/okrs/health-budgets.md +1 -1
  5. package/payload/state/discoveries.md +1 -1
  6. package/payload/state/log.md +1 -1
  7. package/workspace/briefing-premium-calendar-test.js +6 -3
  8. package/workspace/briefing-premium-insights-test.js +2 -2
  9. package/workspace/changelog.json +40 -0
  10. package/workspace/ev-everywhere-test.js +3 -3
  11. package/workspace/fixtures/premium-viewer-fixtures.js +4 -2
  12. package/workspace/guide/agent-capabilities.md +73 -0
  13. package/workspace/guide/board.md +7 -63
  14. package/workspace/guide/breakdown.md +8 -108
  15. package/workspace/guide/briefing-premium.md +5 -526
  16. package/workspace/guide/console-calendar.md +7 -206
  17. package/workspace/guide/docs.md +10 -125
  18. package/workspace/guide/home.md +8 -5
  19. package/workspace/guide/index.md +79 -78
  20. package/workspace/guide/initiatives-and-next-steps.md +6 -19
  21. package/workspace/guide/layout.md +23 -230
  22. package/workspace/guide/live-notes.md +5 -7
  23. package/workspace/guide/my-work.md +8 -172
  24. package/workspace/guide/notes.md +14 -21
  25. package/workspace/guide/people.md +6 -39
  26. package/workspace/guide/report-design.md +2 -2
  27. package/workspace/guide/report-structure.md +1 -1
  28. package/workspace/guide/reports-needs-you.md +34 -0
  29. package/workspace/guide/reports-set-up.md +9 -10
  30. package/workspace/guide/reports.md +17 -1
  31. package/workspace/guide/settings.md +16 -69
  32. package/workspace/guide/today.md +12 -188
  33. package/workspace/lib/report-acts.js +189 -0
  34. package/workspace/lib/report-checks.js +3 -0
  35. package/workspace/lib/report-cli.js +112 -3
  36. package/workspace/lib/report-engine.js +779 -0
  37. package/workspace/lib/report-export.js +36 -1
  38. package/workspace/lib/report-pyramid.js +20 -0
  39. package/workspace/lib/routes-insights-premium.js +17 -3
  40. package/workspace/lib/routes-ready-reports.js +11 -2
  41. package/workspace/lib/routes-report-design.js +7 -2
  42. package/workspace/lib/routes-report-setups.js +38 -3
  43. package/workspace/package-lock.json +2 -2
  44. package/workspace/package.json +1 -1
  45. package/workspace/premium-vw-meet-test.js +9 -5
  46. package/workspace/public/pm/cozy-evui.js +1 -0
  47. package/workspace/public/pm/cozy-insights.css +34 -0
  48. package/workspace/public/pm/cozy-nav.js +4 -1
  49. package/workspace/public/pm/home-app.js +3 -1
  50. package/workspace/public/pm/premium-insights.js +112 -14
  51. package/workspace/public/pm/premium-vw-guide.css +36 -0
  52. package/workspace/public/pm/premium-vw-guide.js +137 -0
  53. package/workspace/public/pm/premium-vw-open.js +4 -1
  54. package/workspace/public/pm/premium-vw-page.js +2 -1
  55. package/workspace/public/premium-intelligence.html +1 -1
  56. package/workspace/run-tests.js +6 -0
  57. package/workspace/skills/report-biweekly.skill +7 -0
  58. package/workspace/skills/report-daily.skill +7 -0
  59. package/workspace/skills/report-monthly.skill +7 -0
  60. package/workspace/skills/report-special.skill +2 -0
  61. package/workspace/skills/report-template.skill +8 -1
  62. package/workspace/skills/report-weekly.skill +7 -0
  63. package/workspace/skills/report-write.skill +44 -0
  64. package/workspace/test-lists/report-engine.json +5 -0
  65. package/workspace/test-lists/reports-needs-you.json +5 -0
  66. package/workspace/guide/ask-the-agent.md +0 -46
  67. package/workspace/guide/briefing-cards.md +0 -52
  68. package/workspace/guide/briefing.md +0 -159
  69. package/workspace/guide/calendar-popup.md +0 -46
  70. package/workspace/guide/command-palette.md +0 -77
  71. package/workspace/guide/console3-sessions.md +0 -147
  72. package/workspace/guide/document-sheet.md +0 -89
  73. package/workspace/guide/initiative-boards.md +0 -123
  74. package/workspace/guide/initiatives-screen.md +0 -179
  75. package/workspace/guide/initiatives-timeline.md +0 -55
  76. package/workspace/guide/phone-companion.md +0 -89
  77. package/workspace/guide/reports-dashboards.md +0 -70
  78. package/workspace/guide/reports-page.md +0 -87
  79. package/workspace/guide/timeline.md +0 -70
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-pmos",
3
- "version": "0.515.0",
3
+ "version": "0.517.0",
4
4
  "description": "Scaffold the PMOS portable kit — run the PMOS product-management workflow (initiative → lane-fit spec → contract → build → three gates, with work-type lanes for features, research, maintenance, incidents, and content) entirely inside your own repo, with all state as git-versioned files. Includes `workflow-sweep`, which audits the state every board derives from and separates real defects from work you simply have not done. `create-pmos workspace` also installs + launches the local Terminal Workspace GUI. No database, no network, no telemetry.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -32,6 +32,46 @@
32
32
  "audit"
33
33
  ],
34
34
  "pmosChanges": [
35
+ {
36
+ "v": "0.517.0",
37
+ "at": "2026-11-04T00:17:56.633Z",
38
+ "f": 4,
39
+ "prs": [
40
+ {
41
+ "n": 1207,
42
+ "t": "User guide in PMOS (option B) and guide pages brought up to date",
43
+ "s": "User guide in PMOS (option B) and guide pages brought up to date",
44
+ "k": "new"
45
+ },
46
+ {
47
+ "n": 1210,
48
+ "t": "The report engine: brief, read, find, write, one deck, no draft without a finding",
49
+ "s": "The report engine: brief, read, find, write, one deck, no draft without a finding",
50
+ "k": "new"
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ "v": "0.516.0",
56
+ "at": "2026-11-04T00:00:07.601Z",
57
+ "f": 4,
58
+ "prs": [
59
+ {
60
+ "n": 1209,
61
+ "t": "Runbook of what Claude does behind the scenes, in the guide",
62
+ "s": "Runbook of what Claude does behind the scenes, in the guide",
63
+ "k": "x",
64
+ "h": "See what Claude does behind the scenes",
65
+ "d": "Claude's background jobs were explained one page at a time, and nothing listed them all together. One guide page lists every job Claude runs by itself: when it runs, what it reads, where you see the result, how to stop it, and what Claude fixes without asking."
66
+ },
67
+ {
68
+ "n": 1208,
69
+ "t": "Reports that need you come first, one ✓ each (redesign R)",
70
+ "s": "Reports that need you come first, one ✓ each (redesign R)",
71
+ "k": "new"
72
+ }
73
+ ]
74
+ },
35
75
  {
36
76
  "v": "0.515.0",
37
77
  "at": "2026-11-03T23:11:51.264Z",
@@ -392,76 +432,6 @@
392
432
  "d": "A blocked step could interrupt you with a question. Now the initiative's workflow decides the next step, and a blocked one shows up only as a ✦ proposal."
393
433
  }
394
434
  ]
395
- },
396
- {
397
- "v": "0.497.0",
398
- "at": "2026-11-03T02:09:19.399Z",
399
- "f": 4,
400
- "prs": [
401
- {
402
- "n": 1174,
403
- "t": "Count only a real Jira handoff record, not keys in body text",
404
- "s": "Count only a real Jira handoff record, not keys in body text",
405
- "k": "fix",
406
- "h": "Jira counts are honest",
407
- "d": "A Jira key mentioned in some text counted as a handoff. Now only a real handoff counts."
408
- },
409
- {
410
- "n": 1175,
411
- "t": "The Viewer shows what a chat turn changed, with no refresh",
412
- "s": "The Viewer shows what a chat turn changed, with no refresh",
413
- "k": "fix",
414
- "h": "See what a chat changed",
415
- "d": "After a chat changed something, the Viewer still showed the old version until you refreshed. Now it updates on its own."
416
- }
417
- ]
418
- },
419
- {
420
- "v": "0.496.0",
421
- "at": "2026-11-03T00:29:32.573Z",
422
- "f": 4,
423
- "prs": [
424
- {
425
- "n": 1172,
426
- "t": "Initiative chats find the initiative's workflow through pmos, never a lane",
427
- "s": "Initiative chats find the initiative's workflow through pmos, never a lane",
428
- "k": "fix",
429
- "h": "Initiative chats find the right workflow",
430
- "d": "An initiative's chat could miss the workflow it should follow. Now it always finds it, including the ones in your own library."
431
- },
432
- {
433
- "n": 1170,
434
- "t": "Keep a rejected ✦ suggestion rejected while its facts hold",
435
- "s": "Keep a rejected ✦ suggestion rejected while its facts hold",
436
- "k": "fix",
437
- "h": "A no stays a no",
438
- "d": "A ✦ suggestion you turned down could come back the next day. Now it stays rejected while nothing about it changes."
439
- },
440
- {
441
- "n": 1171,
442
- "t": "Tasks keep their mapped stage after a workflow switch on Home and Board",
443
- "s": "Tasks keep their mapped stage after a workflow switch on Home and Board",
444
- "k": "fix",
445
- "h": "Tasks keep their stage",
446
- "d": "Switching an initiative's workflow could move its tasks to the wrong stage. Now they keep the stage they were mapped to."
447
- },
448
- {
449
- "n": 1173,
450
- "t": "Calmer Board top bar",
451
- "s": "Calmer Board top bar",
452
- "k": "new",
453
- "h": "A calmer Board top bar",
454
- "d": "The Board's top bar was crowded. Now it is lighter, with fewer controls in your way."
455
- },
456
- {
457
- "n": 1165,
458
- "t": "Pages show something at once while they read",
459
- "s": "Pages show something at once while they read",
460
- "k": "new",
461
- "h": "Pages show something at once",
462
- "d": "A page stayed blank while it read its data. Now it shows its shape right away and fills in as data arrives."
463
- }
464
- ]
465
435
  }
466
436
  ]
467
437
  }
@@ -1,3 +1,3 @@
1
- kernel-source: pmos@49a5661d
2
- assembled: 2026-11-03
1
+ kernel-source: pmos@2580bd8d
2
+ assembled: 2026-11-04
3
3
  mode: vendor
@@ -2,7 +2,7 @@
2
2
  type: Reference
3
3
  title: "Eval calibration log"
4
4
  description: "Append-only record of every PM override of an evaluator verdict."
5
- generated: {by: process:create-pmos, at: "2026-11-03T23:11:47Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-04T00:17:54Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -2,7 +2,7 @@
2
2
  type: Reference
3
3
  title: "Health budgets"
4
4
  description: "Closed registry of health-budget anchors (D59), edited only by the PM."
5
- generated: {by: process:create-pmos, at: "2026-11-03T23:11:47Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-04T00:17:54Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -2,7 +2,7 @@
2
2
  type: Reference
3
3
  title: "Discoveries and friction log"
4
4
  description: "Append-only record of what runs discovered and where the process rubbed."
5
- generated: {by: process:create-pmos, at: "2026-11-03T23:11:47Z"}
5
+ generated: {by: process:create-pmos, at: "2026-11-04T00:17:54Z"}
6
6
  status: stable
7
7
  ---
8
8
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  Newest first, ISO dates.
4
4
 
5
- ## 2026-11-03
5
+ ## 2026-11-04
6
6
 
7
7
  - Adopted OKF v0.2 (D73).
@@ -36,19 +36,22 @@ const json = (r, b, status = 200) => r.fulfill({ status, contentType: 'applicati
36
36
  srv = spawn(process.execPath, [path.join(__dirname, 'server.js')], { cwd: __dirname, stdio: 'ignore', env: T.env({ PMOS_WS_PORT: String(T.PORT) }) });
37
37
  await T.waitForServer(BASE);
38
38
  browser = await chromium.launch({ executablePath: exe });
39
- const W = F.world();
39
+ /* One clock for the page and the stand-ins: today at 11:00, so "Rail review" (30 minutes on) and the meeting 40 minutes back are today
40
+ * at any hour the suite runs. Unpinned, after 23:30 the review fell on tomorrow and C2 failed. */
41
+ const NOW = new Date(); NOW.setHours(11, 0, 0, 0);
42
+ const W = F.world(NOW);
40
43
  const tap = (p, sel) => p.$eval('#czViewer ' + sel, (b) => b.click());
41
44
  const text = (p) => p.evaluate(() => (document.querySelector('#czViewer') || {}).innerText || '');
42
45
  const weekReads = (S) => S.gets.filter((g) => g.startsWith('/api/calendar-views')).length;
43
46
  const ALL = [];
44
- const open = async (url, o) => { const X = await F.open(browser, BASE, url, { noLive: true, ...o }); ALL.push(X); return X; };
47
+ const open = async (url, o) => { const X = await F.open(browser, BASE, url, { noLive: true, now: NOW, ...o }); ALL.push(X); return X; };
45
48
 
46
49
  /* C1 the strip (on a Saturday or Sunday no day of the Mon–Fri strip is today, so none is pressed) */
47
50
  const A = await open('/premium-viewer.html?open=calendar');
48
51
  const p = A.page;
49
52
  // Viewer kit (XvACal): the calendar opens on the day, with today's summary first; the week and month are in ⋯
50
53
  ok('C1 the calendar opens in the Viewer card on the day', await until(() => p.evaluate(() => document.querySelectorAll('#czViewer .vzc-dy').length === 5 && document.querySelectorAll('#czViewer .vzc-de').length > 0), 15000));
51
- const weekday = ![0, 6].includes(new Date().getDay());
54
+ const weekday = ![0, 6].includes(NOW.getDay());
52
55
  await until(() => p.evaluate(() => [...document.querySelectorAll('#czViewer .vzc-dy')].every((d) => d.getBoundingClientRect().height >= 44)), 8000); // the Meetings stylesheet loads after the day is drawn
53
56
  const strip = await p.evaluate(() => [...document.querySelectorAll('#czViewer .vzc-dy')].map((d) => ({ dow: d.querySelector('span').textContent, on: d.getAttribute('aria-pressed'), h: Math.round(d.getBoundingClientRect().height) })));
54
57
  ok('C1 the strip has Monday to Friday and today is pressed on a weekday', strip.map((d) => d.dow).join() === 'MON,TUE,WED,THU,FRI' && strip.filter((d) => d.on === 'true').length === (weekday ? 1 : 0), JSON.stringify(strip));
@@ -390,9 +390,9 @@ const BMR = { ok: true, state: 'ready', model: { tiles: [
390
390
  const R = await open(), q = R.page;
391
391
  await q.click('#moreB'); await q.click('#moreMenu [data-more=\"library\"]');
392
392
  /* re-pointed (premium-uncovered-features, IsLibrary): the bar hands New report to Home, Found in your work is cards, the reports are Report · Next · Status */
393
- const lb = await q.evaluate(() => ({ side: !document.querySelector('#libSide').hidden, nr: document.querySelector('#newRep').getAttribute('href'), found: document.querySelector('#listRows .ins-fdh b').textContent, fcards: [...document.querySelectorAll('#listRows .ins-fcard')].map((c) => c.dataset.f + ':' + [...c.querySelectorAll('.ins-btn[data-fx]')].map((b) => b.textContent).join('/')).join(), heads: [...document.querySelectorAll('#repAsks .ins-rlh span')].map((s) => s.textContent).join('|'), rows: [...document.querySelectorAll('#repNeeds .ins-rl:not(.ins-rlh), #listRows .ins-rl:not(.ins-rlh)')].map((r) => r.querySelector('.nm b').textContent + '|' + r.querySelector('.nx').textContent + '|' + r.querySelector('.st').textContent).join(' / '), setups: document.querySelectorAll('#repNeeds [data-setup], #listRows [data-setup]').length, asks: document.querySelectorAll('#repNeeds [data-ask], #listRows [data-ask]').length, cards: [...document.querySelectorAll('#listRows .ins-dcard')].map((c) => c.dataset.d + (c.querySelector('.ins-pinned') ? '*' : '')).join(), cap: document.querySelector('#repCap').textContent, old: !!document.querySelector('#listSeg, #sugB') }));
393
+ const lb = await q.evaluate(() => ({ side: !document.querySelector('#libSide').hidden, nr: document.querySelector('#newRep').getAttribute('href'), found: document.querySelector('#listRows .ins-fdh b').textContent, fcards: [...document.querySelectorAll('#listRows .ins-fcard')].map((c) => c.dataset.f + ':' + [...c.querySelectorAll('.ins-btn[data-fx]')].map((b) => b.textContent).join('/')).join(), heads: [...document.querySelectorAll('#repAsks .ins-rlh span')].map((s) => s.textContent).join('|'), rows: [...document.querySelectorAll('#repNeeds .ins-rl:not(.ins-rlh), #listRows .ins-rl:not(.ins-rlh)')].map((r) => r.querySelector('.nm b').textContent + '|' + r.querySelector('.nx').textContent + '|' + r.querySelector('.st').textContent).join(' / '), needs: [...document.querySelectorAll('#repNeeds .ins-nrow .nm b')].map((b) => b.textContent).join('|'), setups: document.querySelectorAll('#repNeeds [data-setup], #listRows [data-setup]').length, asks: new Set([...document.querySelectorAll('#repNeeds [data-ask], #listRows [data-ask]')].map((e) => e.dataset.ask)).size, cards: [...document.querySelectorAll('#listRows .ins-dcard')].map((c) => c.dataset.d + (c.querySelector('.ins-pinned') ? '*' : '')).join(), cap: document.querySelector('#repCap').textContent, old: !!document.querySelector('#listSeg, #sugB') }));
394
394
  ok('L1 Reports and dashboards opens as a side panel from ⋯; New report in Home hands off there, and Found in your work holds the finding as a card', lb.side && /^\/premium\.html\?ws=w1&ask=insights&q=Make%20a%20new%20report/.test(lb.nr) && lb.found === 'Found in your work · 1' && lb.fcards === 'f-1:Set it up/Not a report' && lb.cap === '9' && !lb.old, JSON.stringify(lb));
395
- ok('L1 the reports table is Report, Next and Status (what needs you first, redesign A); a draft says "Draft ready for" its date; a request says Proposal or Working', lb.heads === 'Report|Next|Status' && /Draft ready for Oct 14/.test(lb.rows) && /Partner update\|First draft [^|]+\|Runs every other monday/i.test(lb.rows) && /Churn for finance\|—\|Proposal/.test(lb.rows) && lb.setups === 1 && lb.asks === 2, JSON.stringify(lb.rows));
395
+ ok('L1 the reports table is Report, Next and Status (what needs you first, redesign A); a draft says "Draft ready for" its date; a request says Working; a ready proposal waits in Needs you (redesign R)', lb.heads === 'Report|Next|Status' && /Draft ready for Oct 14/.test(lb.rows) && /Partner update\|First draft [^|]+\|Runs every other monday/i.test(lb.rows) && /(^|\|)Churn for finance(\||$)/.test(lb.needs) && lb.setups === 1 && lb.asks === 2, JSON.stringify([lb.rows, lb.needs]));
396
396
  ok('L1 dashboards are cards; only the pinned one carries the pin', lb.cards === 'all*,pd-1,p:Growth,p:Reliability', lb.cards);
397
397
  const rs = []; await q.route('**/api/report-setups/*', (r) => { rs.push([new URL(r.request().url()).pathname.replace('/api/report-setups/', ''), JSON.parse(r.request().postData() || '{}')]); r.fulfill({ contentType: 'application/json', body: '{"ok":true,"drafted":{"slot":"2026-10-23","path":"planning/reports/x/2026-10-23.md"}}' }); });
398
398
  const lastRs = () => rs[rs.length - 1] || [null, {}];
@@ -1,4 +1,44 @@
1
1
  [
2
+ {
3
+ "v": "0.517.0",
4
+ "at": "2026-11-04T00:17:56.633Z",
5
+ "f": 4,
6
+ "prs": [
7
+ {
8
+ "n": 1207,
9
+ "t": "User guide in PMOS (option B) and guide pages brought up to date",
10
+ "s": "User guide in PMOS (option B) and guide pages brought up to date",
11
+ "k": "new"
12
+ },
13
+ {
14
+ "n": 1210,
15
+ "t": "The report engine: brief, read, find, write, one deck, no draft without a finding",
16
+ "s": "The report engine: brief, read, find, write, one deck, no draft without a finding",
17
+ "k": "new"
18
+ }
19
+ ]
20
+ },
21
+ {
22
+ "v": "0.516.0",
23
+ "at": "2026-11-04T00:00:07.601Z",
24
+ "f": 4,
25
+ "prs": [
26
+ {
27
+ "n": 1209,
28
+ "t": "Runbook of what Claude does behind the scenes, in the guide",
29
+ "s": "Runbook of what Claude does behind the scenes, in the guide",
30
+ "k": "x",
31
+ "h": "See what Claude does behind the scenes",
32
+ "d": "Claude's background jobs were explained one page at a time, and nothing listed them all together. One guide page lists every job Claude runs by itself: when it runs, what it reads, where you see the result, how to stop it, and what Claude fixes without asking."
33
+ },
34
+ {
35
+ "n": 1208,
36
+ "t": "Reports that need you come first, one ✓ each (redesign R)",
37
+ "s": "Reports that need you come first, one ✓ each (redesign R)",
38
+ "k": "new"
39
+ }
40
+ ]
41
+ },
2
42
  {
3
43
  "v": "0.515.0",
4
44
  "at": "2026-11-03T23:11:51.264Z",
@@ -84,8 +84,8 @@ const put = (root, rel, text) => { fs.mkdirSync(path.dirname(path.join(root, rel
84
84
  const { ctx, pg, errors, posts } = await open();
85
85
  await menu(pg);
86
86
  const m = await pg.evaluate(() => ({ links: [...document.querySelectorAll('#czMenu a')].map((a) => a.textContent.trim()), tray: [...document.querySelectorAll('#czMenu .ev-tray button')].map((b) => b.getAttribute('aria-label').replace(/\..*$/, '')), rows: document.querySelectorAll('#czMenu .ev-mi, #czMenu [data-cz-more], #czMenu [data-cz-news], #czMenu [data-cz-sources], #czMenu [data-ev-theme]').length }));
87
- // feedback batch 16 item 5 (canvas FmA1Menu): the three places, then Search and Settings as icons, and nothing else
88
- ok('U1 the menu holds Home, Board, Intelligence, then Search and Settings as two icons, and no New for you, Sources, More or Theme', m.links.join() === 'Home,Board,Intelligence' && m.tray.join() === 'Search (⌘K),Settings' && m.rows === 0, JSON.stringify(m));
87
+ // feedback batch 16 item 5 (canvas FmA1Menu): the three places, then Search and Settings as icons, and nothing else; guide-in-app adds Guide between them
88
+ ok('U1 the menu holds Home, Board, Intelligence, then Search, Guide and Settings as three icons, and no New for you, Sources, More or Theme', m.links.join() === 'Home,Board,Intelligence' && m.tray.join() === 'Search (⌘K),Guide,Settings' && m.rows === 0, JSON.stringify(m));
89
89
  await snap(pg, 'menu-1440-light');
90
90
  await pg.keyboard.press('Escape');
91
91
  ok('U2 Escape closes the menu', await until(() => pg.isHidden('#czMenu')));
@@ -180,7 +180,7 @@ const put = (root, rel, text) => { fs.mkdirSync(path.dirname(path.join(root, rel
180
180
  await pg.goto(`${BASE}/premium-insights.html?ws=${encodeURIComponent(ws)}`); await pg.waitForSelector('#czFab');
181
181
  ok('D1 the choice is kept for the next page', await pg.evaluate(() => document.documentElement.dataset.theme === 'dark'));
182
182
  await menu(pg);
183
- ok('U1 no page has More in its menu', await pg.evaluate(() => !document.querySelector('#czMenu [data-cz-more]') && document.querySelectorAll('#czMenu .ev-tray button').length === 2));
183
+ ok('U1 no page has More in its menu', await pg.evaluate(() => !document.querySelector('#czMenu [data-cz-more]') && document.querySelectorAll('#czMenu .ev-tray button').length === 3));
184
184
  await snap(pg, 'menu-1440-dark');
185
185
  await pg.keyboard.press('Escape');
186
186
  await pg.keyboard.press('Control+k'); await pg.waitForSelector('#evSearch:not([hidden])'); await pg.keyboard.type('billing');
@@ -62,6 +62,7 @@ const REPORT = '---\ntype: Report\ntitle: "Password login and sign-up"\n---\n\n#
62
62
 
63
63
  function install(page, o = {}) {
64
64
  const W = world(o.now || new Date());
65
+ const shift = o.now ? o.now.getTime() - Date.now() : 0; // a pinned clock (o.now): the stand-ins answer in the page's time
65
66
  const S = { posts: [], gets: [], scene: o.scene || 'notes', W };
66
67
  const json = (r, b, status = 200) => r.fulfill({ status, contentType: 'application/json', body: JSON.stringify(b) });
67
68
  const body = (r) => { try { return JSON.parse(r.request().postData() || '{}'); } catch { return {}; } };
@@ -118,8 +119,8 @@ function install(page, o = {}) {
118
119
  const u = new URL(r.request().url()), ev = u.searchParams.get('event'), note = u.searchParams.get('note');
119
120
  const live = ev === 'ev-live' || note === 'n2';
120
121
  /* a note with no calendar event has no event, brief or topics */
121
- if (!ev && note && note !== 'n1' && note !== 'n2') return json(r, { ok: true, now_ms: Date.now(), event: null, note: { id: note, state: (S.store[note] || {}).state || 'ended' }, brief: null, material: [], topics: [], runs: [], captured: {}, tail: [] });
122
- const base = { ok: true, now_ms: Date.now(), event: live ? { id: 'ev-live', title: 'Design crit', at: W.LIVE_NOTE.meeting.start, end: W.LIVE_NOTE.meeting.end, attendees: ['Ana', 'Wawan'] } : ev === 'ev-rail' ? { id: 'ev-rail', title: 'Rail review', at: iso(W.RAIL), attendees: ['Sam', 'Wawan'] } : { id: 'ev-sync', title: 'Viewer sync', at: W.NOTE.meeting.start, end: W.NOTE.meeting.end, attendees: ['Ana', 'Dita', 'Wawan'] },
122
+ if (!ev && note && note !== 'n1' && note !== 'n2') return json(r, { ok: true, now_ms: Date.now() + shift, event: null, note: { id: note, state: (S.store[note] || {}).state || 'ended' }, brief: null, material: [], topics: [], runs: [], captured: {}, tail: [] });
123
+ const base = { ok: true, now_ms: Date.now() + shift, event: live ? { id: 'ev-live', title: 'Design crit', at: W.LIVE_NOTE.meeting.start, end: W.LIVE_NOTE.meeting.end, attendees: ['Ana', 'Wawan'] } : ev === 'ev-rail' ? { id: 'ev-rail', title: 'Rail review', at: iso(W.RAIL), attendees: ['Sam', 'Wawan'] } : { id: 'ev-sync', title: 'Viewer sync', at: W.NOTE.meeting.start, end: W.NOTE.meeting.end, attendees: ['Ana', 'Dita', 'Wawan'] },
123
124
  note: live ? { id: 'n2', state: 'recording' } : ev === 'ev-rail' ? null : { id: 'n1', state: 'ended' },
124
125
  brief: { gist: ['Agree the rail before the Commit.'], purpose: 'Agree the rail before the Commit.', matters: [{ tag: 'Late', tone: 'bad', text: 'The SSO spike', meta: 'due 14 Oct' }, { tag: 'Changed', tone: '', text: 'The report panel design', meta: 'Oct 21' }], last: { id: 'n0', at: '2026-10-15T10:00:00Z', decisions: [{ text: 'a' }], actions: [{ text: 'b' }, { text: 'c' }] }, prep: 'Read the rail PRD.', initiative: { id: 'viewer', title: 'Viewer', ws: 'w1' } },
125
126
  material: [{ kind: 'pmos-deck', title: 'Release deck', ref: 'decks/release.md', from: 'you' }, { kind: 'pmos-doc', title: 'Rail PRD', ref: 'planning/prd/rail.md', from: 'you' }, { kind: 'link', title: 'Figma: report panel', url: 'https://x.example/f', topic: 'The report panel' }],
@@ -189,6 +190,7 @@ async function open(browser, base, url, o = {}) {
189
190
  const ctx = await browser.newContext({ viewport: { width: o.w || 1280, height: o.h || 900 }, acceptDownloads: true });
190
191
  const page = await ctx.newPage(), errors = [];
191
192
  page.on('pageerror', (e) => errors.push(String((e && e.message) || e)));
193
+ if (o.now) await page.clock.setSystemTime(o.now); // the page's Date starts at o.now and runs on; timers are real
192
194
  const S = await install(page, o);
193
195
  await page.addInitScript(RECORDER);
194
196
  if (o.init) await page.addInitScript(o.init);
@@ -0,0 +1,73 @@
1
+ ---
2
+ type: Guide
3
+ title: "What Claude does behind the scenes"
4
+ description: "The runbook of the workspace agent: each job Claude runs by itself, when it runs, what it reads, where its result shows, how to stop it, what it fixes by itself, the rules every job follows, and how to see what ran."
5
+ timestamp: 2026-11-03
6
+ ---
7
+
8
+ # What Claude does behind the scenes
9
+
10
+ Claude works in the background while the workspace runs. It reads your records and the tools you connected, it drafts, and it checks. It does not decide for you. A result waits for your ✓, most often under the blue ✦ of an initiative or as one ✦ in Home's chat. A background job never sends, posts, pushes or merges anything.
11
+
12
+ This page lists every job, so you know what runs and why. Each row links to the page with the full detail.
13
+
14
+ ## The rules every job follows
15
+
16
+ - **Propose-only.** A background job files proposals. Nothing lands on an initiative, a task or a metric until you press ✓. ✕ drops a proposal, and Undo brings back what was there.
17
+ - **Every claim has a source.** An AI job files through one shared guard. The guard checks that each quote is really at the file and line it cites. A claim with no source that checks out is dropped. A proposal with a key that would write, apply, send or run a command is dropped.
18
+ - **Few at a time.** A run shows at most 3 proposals. In a quiet week it shows nothing.
19
+ - **Tested first.** A new version of a job shows nothing until its replay passes: its own known cases, and the guard's own cases (a made-up quote, a missing source, a path outside the repository, a write key). Each of those must be dropped.
20
+ - **Your login, your connections.** A job runs as a background Claude session with your own login, model, profile and connectors. The workspace holds no password or token. `PMOS_HEADLESS=off` sends every job back to a terminal pane.
21
+ - **Your hours.** Scheduled jobs run inside your working hours and never inside your quiet hours.
22
+ - **A spending limit.** Claude's checks spend at most the monthly credit you set in Settings › Claude's checks ($5, $10, $20 or $50). At the limit Claude pauses. It never spends beyond the limit.
23
+ - **Every run is logged.** Each job writes its own ledger in the runtime folder on this computer. Only you see it, and it never goes into a repository.
24
+
25
+ ## The jobs
26
+
27
+ | Job | When it runs | What it reads | Where you see it | How to stop it |
28
+ |---|---|---|---|---|
29
+ | [Initiative Driver](initiative-driver.md) | An initiative is created, moved or sent back. The unblock sweep runs every 30 minutes in working hours. At most 3 runs at once. | The initiative record, its tasks and its Jira tickets | The Agent strip of the initiative, and Needs you | Board settings › Agent: Off. `PMOS_DRIVER=off` |
30
+ | [Found elsewhere](claude-proposes.md) | You add an initiative | Drive, Docs, Sheets, Slides, Jira, the calendar, meeting notes, Gmail, Slack and Confluence | The initiative's ✦ | `PMOS_PROPOSE=off` |
31
+ | [New dates, done and tidy names](claude-proposes.md) | Each morning, and when a date passes | The tasks of the initiative, and the evidence that work happened | The initiative's ✦ | `PMOS_PROPOSE=off` |
32
+ | [Grill](claude-proposes.md) | Before an initiative leaves a stage, when a forecast turns at risk, when scope or dates move a lot, and once a month on running work with late work. Also when you write "grill this" in the initiative's chat. | The initiative, your stored research, your meeting notes and the decisions that stand | "Claude grilled it" under the initiative's ✦ | Settings › Claude's checks: Off. `PMOS_GRILL=off` |
33
+ | [You decided this before](ask-the-past.md) | You add an initiative that repeats an earlier decision | `DECISIONS.md`, the decision records, the PM journal, `planning/out-of-scope/` and the initiative records | The initiative's ✦ | `pmos ai off past-repeat` |
34
+ | [Expected outcomes](outcomes.md) | Once a day. At most 3 drafts a day for each product. | The PRD's success criteria, or the anchored key result | "Expected outcome" under the initiative's ✦. Today when a check is due. | `pmos ai off outcomes`. `PMOS_OUTCOMES=off` |
35
+ | [Metric drafts](metric-drafts.md) | A product with no North Star, the first 14 days of a quarter, a program with no goal, and an initiative that gets a PRD | The last 8 weeks of real readings | The page of that product, program or initiative | `PMOS_METRIC_DRAFT=off` |
36
+ | [Horizon scan](horizon-scan.md) | Daily by default, at most once a day. Scan now: at most 3 a day. | The public web for your kept watch list, and your repository | Report documents and proposals you approve | Cadence: Off. `PMOS_SCAN=off` |
37
+ | [What you might have missed](what-you-missed.md) | Each Monday, for the week before. It uses no model. | Records only: tasks, dates, initiatives and Jira status | One ✦ in Home's chat, at most 3 items | `pmos ai off drift`. `PMOS_DRIFT=off` |
38
+ | [Your impact](your-impact.md) | Claude reads once a day. Home shows the week after it ends. | Slack, mail, Jira, your meeting notes, your documents and your key results | Adler's sprout on Home, and your impact log | Settings › General › Your impact. `PMOS_IMPACT=off` |
39
+ | [Morning brief and day check](proactive-engine.md) | The morning brief at 06:45, once you schedule it. The day check every 60 minutes by default (30, 60 or off). | Calendar, Wispr Flow, Slack, Jira and Confluence are on by default. Mail, GitHub, Drive, Figma and websites are off by default. Mail: subjects and senders only. | Today | Each source is a setting. `pmos proactive settings` |
40
+ | [Day tasks](proactive-engine.md) | You press Prepare my day. At most 5 sessions at once. | The sources of the brief, read-only | Today: a draft waits for Approve or Revise | Do not press Prepare my day |
41
+ | [Next prompt and Sharper](next-prompt.md) | After Claude replies, and when you stop typing a rough prompt | The reply and your message | Cards above the chat box. Nothing is sent. | Settings › Claude. `pmos ai off next-prompt`, `pmos ai off sharpen-prompt` |
42
+ | [Rehearse a plan](rehearse.md) | You ask Claude to move a date or cut a task or an initiative | Task links, initiative records, goals and program charters | Your session, before Claude makes the change | `pmos ai off rehearse` |
43
+ | [Data refresh](data-freshness.md) | In working hours: the calendar every 30 minutes, and Jira, My work and your tools every hour. Tracker items on Friday 15:30. | Each tool with your own connection, read-only | Each page shows how old its data is | Settings › Data refresh |
44
+
45
+ Ask about the past runs only when you ask a question in an initiative's chat. It answers from the records, with the file and line of each claim, and says **No record found** when no record answers.
46
+
47
+ ## What Claude fixes by itself
48
+
49
+ Some problems are safe to fix with no question. Claude fixes these by itself and tells you only when it cannot.
50
+
51
+ - **A product folder on the wrong branch.** A document repository whose folder is not on its default branch looks empty. The workspace puts it back: it saves the records, checks that the merge has no conflict, merges, and pushes with no force. It never deletes or rewrites a branch. It never touches a code repository. When it cannot do this safely, Today shows one "Needs repair" card in plain words, with **Ask Claude to sort it out**. It tries again after 30 minutes, or after 10 minutes when it only waited for the network. `PMOS_AUTO_REPAIR=0` stops it.
52
+ - **Folders of finished work.** About every 6 hours the workspace removes a linked worktree only when its branch is merged, it holds no unsaved file, nothing used it for 14 days, and no session uses it. The branch is kept. `PMOS_AUTO_CLEAN=0` stops it.
53
+ - **A report source that does not answer.** A scheduled report waits up to 4 hours for a source that failed its check. Today shows "Check <source> for <report>" with **Check again**. Then the report is drafted without that source, and it says so. It never guesses a number.
54
+ - **A failed run.** A metric draft that failed tries again the next day. A Driver run that failed or timed out writes its reason in the ledger.
55
+ - **A source that was not reached.** It is shown as not reached, never as read. Today says which sources were not read.
56
+
57
+ Sync by itself is on by default. `PMOS_AUTO_SYNC=0` stops the sync, the repair and the clean-up.
58
+
59
+ ## What a background job never does
60
+
61
+ - It sends, posts, replies, pushes and merges nothing. A message to a person is a draft that you send. A Jira change is a drafted comment in your outbox.
62
+ - It does not create an initiative. The Horizon scan proposes one, and you approve it.
63
+ - It does not record a verdict on an outcome. The verdict is always yours.
64
+
65
+ When you ask an agent session to do a piece of work, it can finish it, including acts that were yours alone. Each line it writes names the agent, so you see who did it. See [PM-only acts](pm-only-acts.md).
66
+
67
+ ## See what ran, and turn it off
68
+
69
+ - `pmos ai status`: whether each AI job is on, whether its replay passed, and what its last run filed.
70
+ - `pmos ai log [<job>]`: the last audit lines. Each dropped proposal shows why.
71
+ - `pmos ai off [<job>]` and `pmos ai on [<job>]`: turn every AI job, or one job, off or on. `PMOS_AI=off` in the environment wins over the setting.
72
+
73
+ The AI jobs are `past-repeat`, `decision-memory`, `outcomes`, `drift`, `rehearse`, `next-prompt` and `sharpen-prompt`. A background run cannot change the switch.
@@ -1,75 +1,19 @@
1
1
  ---
2
2
  type: Guide
3
- title: "Board: the items of every initiative"
4
- description: "How to read and use the Board destination, filter it, add an item, move a card, release a batch of work items, and print the same Board with pmos board."
5
- timestamp: 2026-11-02
3
+ title: "pmos board: the items of every initiative"
4
+ description: "How pmos board prints the items of every initiative in four columns from a terminal, and where the workspace shows initiatives and their tasks."
5
+ timestamp: 2026-11-03
6
6
  ---
7
7
 
8
- # Board: the items of every initiative
8
+ # pmos board: the items of every initiative
9
9
 
10
- The Board shows the items of all your work initiatives in one place. It has four columns: Todo, Doing, Review and Done. A card is one item. The Board is a view of the same items that the Breakdown of each initiative shows, so a card is always in the column that its row has in the Tree.
10
+ The **Board** place of the workspace shows initiatives, not items: every initiative of the products you pick, by stage, with programs, a timeline and a list. [Programs on the Board](programs.md) explains it. An initiative's tasks show under it in Home's list and in the initiative's page in the Viewer.
11
11
 
12
- The Board looks like the Agenda. The title at the top counts the items, for example "43 items in code". The filters and **Add item** sit on the right of the title. Each column heading has a status dot and a count. A column shows its first 3 cards. Press **Show 14 more** under a column to see all of its cards. An owner icon on a card shows who owns it: a robot for an agent, or "You".
13
-
14
- A document initiative has no items, so it has no card and no place in the filter.
15
-
16
- ## Open the Board
17
-
18
- Press **Board** in the navigation, or press `g` then `b`. In the older layout, choose Board in the command palette. The Board opens in a tab.
19
-
20
- ## Filters
21
-
22
- Three filters decide which cards show. Press a button at the top, or choose an initiative from the list.
23
-
24
- - **Active** is the default. It shows an item that changed in the last days, an open item of an initiative that is ranked on the Roadmap, and every item that is yours. The number of days is `stall_days` in `planning/plan-rules.json`.
25
- - **Mine** shows only the items that you own.
26
- - **An initiative.** Choose one from the list to see all its items. Choose **All initiatives** to go back to Active.
27
-
28
- Done shows the last 14 days under every filter, however long ago the item last changed. An older Done item is counted in the column ("3 older in the Tree") and stays in the Tree of its initiative.
29
-
30
- ## Add an item
31
-
32
- Press **Add item**, the one main button of the Board. Type a title, choose the initiative and the stage, and press **Add** or Enter. The item goes into the ledger of that initiative, the same way as in the Breakdown.
33
-
34
- ## Move a card
35
-
36
- - **On a wide screen,** drag a card to another column. A drop on Done is held for 8 seconds, so you can press **Undo**.
37
- - **On a phone,** press the card to open its sheet and press a state button. A card moves in 2 taps. From another column it takes 3: first press the column name, then the card, then the state.
38
- - **From the menu.** Press the three dots on a card, then choose Move to a state. Every card shows its three dots.
39
-
40
- When you move a card that an agent owns, the card reads "moved by you". The agent's own next move can change it again.
41
-
42
- A card that reads "Done · your call · not merged" is Done because you said so. The work in the repository is not merged yet.
43
-
44
- ## Release
45
-
46
- When all the work items of a batch passed their checks, the Board shows a **Release** card above the columns. One press on **Release** grants the whole batch. It is one grant for the batch, and the grant names the initiative and the batch. The factory opens pull requests and never merges them.
47
-
48
- Only you can press Release. An agent cannot. When the grant writer of the workspace is not available, the button is disabled and the card says "Release arrives in Run 2."
49
-
50
- The same card also shows in Today when a batch is ready.
51
-
52
- ## Today
53
-
54
- Today shows three things from the Board:
55
-
56
- - an item in Review that waits for you;
57
- - a batch that is ready for Release;
58
- - an item that an agent marked Done with no evidence. Open it and add evidence, such as `commit:<sha>` or `pr:<number>`.
59
-
60
- ## Signals
61
-
62
- | signal | meaning |
63
- |---|---|
64
- | Blocked | the item has a reason that it cannot go on |
65
- | no evidence | an agent marked the item Done and gave no evidence |
66
- | late | the due date passed and the item is not Done |
67
- | moved by you | you moved a card that an agent owns |
68
- | Proposed | an item an agent added before D98 that was never kept (since D98 an agent's item is live at once) |
12
+ The command below prints the items themselves, from a terminal.
69
13
 
70
14
  ## From a terminal
71
15
 
72
- `pmos board` prints the same Board that the page shows. It reads the repository, so the workspace server does not need to run.
16
+ `pmos board` prints the items of every initiative as columns: Todo, Doing, Review and Done. It reads the repository, so the workspace server does not need to run.
73
17
 
74
18
  ```
75
19
  pmos board the Active filter