loki-mode 11.74.2 → 11.75.2

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 (167) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +2 -3
  3. package/VERSION +1 -1
  4. package/autonomy/completion-council.sh +10 -10
  5. package/autonomy/council-v2.sh +4 -4
  6. package/autonomy/grill.sh +1 -1
  7. package/autonomy/lib/ablation.py +22 -2
  8. package/autonomy/lib/browser-open.sh +1 -1
  9. package/autonomy/lib/chat.sh +1 -1
  10. package/autonomy/lib/cockpit-render.sh +1 -1
  11. package/autonomy/lib/done-recognition.sh +4 -4
  12. package/autonomy/lib/efficiency_cost.py +1 -1
  13. package/autonomy/lib/engine10-push.sh +2 -2
  14. package/autonomy/lib/prd-enrich.sh +1 -1
  15. package/autonomy/lib/proof-check.sh +1 -1
  16. package/autonomy/lib/proof-generator.py +3 -3
  17. package/autonomy/lib/proof-pr.sh +1 -1
  18. package/autonomy/lib/skill-link-heal.sh +1 -1
  19. package/autonomy/lib/voter-agents.sh +1 -1
  20. package/autonomy/loki +26 -37
  21. package/autonomy/prd-checklist.sh +1 -1
  22. package/autonomy/receipt_jwt.py +1 -1
  23. package/autonomy/run.sh +28 -28
  24. package/autonomy/trigger-schedule.py +6 -414
  25. package/autonomy/tui.sh +1 -1
  26. package/autonomy/verify.sh +4 -4
  27. package/completions/loki.bash +0 -5
  28. package/dashboard/__init__.py +1 -1
  29. package/docs/ARCHITECTURE.md +1 -2
  30. package/docs/CLI-REFERENCE.md +1 -1
  31. package/docs/COMPONENTS.md +1 -1
  32. package/docs/INSTALLATION.md +1 -1
  33. package/docs/ROUTING-EVIDENCE.md +1 -2
  34. package/docs/V10-RESEARCH.md +1 -1
  35. package/docs/dev/architecture-reference.md +3 -7
  36. package/docs/dev/project-structure.md +1 -4
  37. package/docs/dev/release-checklist.md +13 -31
  38. package/docs/research-2026-07/OBSERVABILITY-TOOL-SPEC.md +1 -1
  39. package/docs/v11/MARKET-SLICES.md +1 -1
  40. package/docs/v11/REGISTRIES.md +1 -1
  41. package/docs/v11/ROUTER-1.md +2 -2
  42. package/loki-ts/dist/loki.js +2 -2
  43. package/mcp/__init__.py +1 -1
  44. package/package.json +2 -2
  45. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  46. package/skills/extending.md +2 -3
  47. package/skills/factory-operations.md +11 -18
  48. package/skills/release-cadence.md +2 -2
  49. package/web-app/dist/assets/{AdminPage-jkjilfbl.js → AdminPage-CTwi8SUX.js} +1 -1
  50. package/web-app/dist/assets/{Avatar-bd5JWkSJ.js → Avatar-DVtGtLkJ.js} +1 -1
  51. package/web-app/dist/assets/{Badge-DVRit2Xw.js → Badge-rwKzz0Pe.js} +1 -1
  52. package/web-app/dist/assets/{Button-BNAB-pVZ.js → Button-nIsPDfsQ.js} +1 -1
  53. package/web-app/dist/assets/{CockpitPage-DpG29h_w.js → CockpitPage-BCeDpoWa.js} +1 -1
  54. package/web-app/dist/assets/{ComparePage-Dasg5V41.js → ComparePage-CYIYanVq.js} +1 -1
  55. package/web-app/dist/assets/{ErrorBoundary-DJojse6b.js → ErrorBoundary-Bkz6HqWp.js} +1 -1
  56. package/web-app/dist/assets/{EvidenceReceiptPanel-Blxw7_u1.js → EvidenceReceiptPanel-DZT2Np4F.js} +1 -1
  57. package/web-app/dist/assets/{GitHubIssuesPanel-BBvSFj80.js → GitHubIssuesPanel-Bzla91Lu.js} +1 -1
  58. package/web-app/dist/assets/{GitHubPRsPanel-BCIKeSBg.js → GitHubPRsPanel-FjT-Xn5t.js} +1 -1
  59. package/web-app/dist/assets/{HomePage-C7d__oNG.js → HomePage-pXgmRGLt.js} +2 -2
  60. package/web-app/dist/assets/{LoginPage-BXljL3yY.js → LoginPage-CnmpE28B.js} +1 -1
  61. package/web-app/dist/assets/{MagicPage-Xjkts_yE.js → MagicPage-CuSeGsLq.js} +1 -1
  62. package/web-app/dist/assets/{MetricsPage-kQvVp-j2.js → MetricsPage-Bg3PkBOU.js} +1 -1
  63. package/web-app/dist/assets/{NotFoundPage-D-4ZlEaO.js → NotFoundPage-uzBtZNV-.js} +1 -1
  64. package/web-app/dist/assets/{ProjectPage-DfzR5RXP.js → ProjectPage-Dacki8Xr.js} +3 -3
  65. package/web-app/dist/assets/{ProjectsPage-DFDsWzkV.js → ProjectsPage-BRGjksXG.js} +1 -1
  66. package/web-app/dist/assets/{SettingsPage-CLPIoYT3.js → SettingsPage-BbNf3fEJ.js} +1 -1
  67. package/web-app/dist/assets/{ShowcasePage-PZKkyGeY.js → ShowcasePage-XX4830sX.js} +1 -1
  68. package/web-app/dist/assets/{SystemSettingsPage-BsBlcnzo.js → SystemSettingsPage-DOhQeXa6.js} +1 -1
  69. package/web-app/dist/assets/{TeamsPage-BSjgNhoU.js → TeamsPage-2reIRUp_.js} +1 -1
  70. package/web-app/dist/assets/{TemplatesPage-W2KeAzbg.js → TemplatesPage-BUsLEWHW.js} +1 -1
  71. package/web-app/dist/assets/{TerminalOutput-BjroTiCC.js → TerminalOutput-BrBDcgzC.js} +1 -1
  72. package/web-app/dist/assets/{activity-BXZ5YYes.js → activity-B6AZpgmb.js} +1 -1
  73. package/web-app/dist/assets/{bell-D1urp5pa.js → bell-CB792A7S.js} +1 -1
  74. package/web-app/dist/assets/{bot-Chedf2bF.js → bot-uQZwOFAn.js} +1 -1
  75. package/web-app/dist/assets/{check-DhaCuOCV.js → check-DrtG0lIZ.js} +1 -1
  76. package/web-app/dist/assets/{chevron-left-D7BpQyA6.js → chevron-left-CrsJSAqQ.js} +1 -1
  77. package/web-app/dist/assets/{circle-alert-DnGvQ_AQ.js → circle-alert-BUCly4p3.js} +1 -1
  78. package/web-app/dist/assets/{clock-CqfxWhHM.js → clock-B2IT9SnE.js} +1 -1
  79. package/web-app/dist/assets/{cloud-BKxp5AWB.js → cloud-CN6Ux7Q7.js} +1 -1
  80. package/web-app/dist/assets/{code-xml-BDQ6GBtt.js → code-xml-BEm8PWnK.js} +1 -1
  81. package/web-app/dist/assets/{database-BmpEx1y_.js → database-cHe5Fgu8.js} +1 -1
  82. package/web-app/dist/assets/{dollar-sign-DYNY9R_C.js → dollar-sign-BVmP4YrE.js} +1 -1
  83. package/web-app/dist/assets/{file-code-corner-BJi0IBFd.js → file-code-corner-D-m-NrwO.js} +1 -1
  84. package/web-app/dist/assets/{file-plus-Dqyb2bcQ.js → file-plus-6mCjIzAB.js} +1 -1
  85. package/web-app/dist/assets/{globe-DPh4RWfM.js → globe-vcWOujwU.js} +1 -1
  86. package/web-app/dist/assets/{hammer-B3xnuoA1.js → hammer-D4nZFpO2.js} +1 -1
  87. package/web-app/dist/assets/{index-BpX8DcTr.js → index-u8toJ43r.js} +3 -3
  88. package/web-app/dist/assets/{layers-BRCmyCW8.js → layers-CNhYLop8.js} +1 -1
  89. package/web-app/dist/assets/{loader-circle-n07Pky0M.js → loader-circle-Vl7XIMV6.js} +1 -1
  90. package/web-app/dist/assets/{lock-BWqOuQmS.js → lock-SW_KwAvf.js} +1 -1
  91. package/web-app/dist/assets/{package-BJlB_Z-Z.js → package-QPK-7Ej1.js} +1 -1
  92. package/web-app/dist/assets/{plus-oH17BZu2.js → plus-DUgAlgCB.js} +1 -1
  93. package/web-app/dist/assets/{refresh-cw-CPQ476LL.js → refresh-cw-LfUksPHq.js} +1 -1
  94. package/web-app/dist/assets/{rotate-ccw-7hLvOcnS.js → rotate-ccw-CMbuouVq.js} +1 -1
  95. package/web-app/dist/assets/{scroll-text-BCmLauQn.js → scroll-text-C_FxBmNQ.js} +1 -1
  96. package/web-app/dist/assets/{server-DfTfvW84.js → server-7UJe9Jqt.js} +1 -1
  97. package/web-app/dist/assets/{shield-alert-CaeGRq19.js → shield-alert-BMuu6fYB.js} +1 -1
  98. package/web-app/dist/assets/{thumbs-up-Dz-l2GPC.js → thumbs-up-Bhs0d2Gp.js} +1 -1
  99. package/web-app/dist/assets/{trash-2-B-OsDmSo.js → trash-2-BZKxv49w.js} +1 -1
  100. package/web-app/dist/assets/{trending-down-CXTFOxzq.js → trending-down-DKeCMZek.js} +1 -1
  101. package/web-app/dist/assets/{trending-up-FQEdqr3v.js → trending-up-43_9fShg.js} +1 -1
  102. package/web-app/dist/assets/{upload-CacWSNTg.js → upload-pV3irPEW.js} +1 -1
  103. package/web-app/dist/assets/{usePolling-cIjZ9qd2.js → usePolling-CoZQM-WL.js} +1 -1
  104. package/web-app/dist/assets/{user-DAouWFHi.js → user-CMl7dXvC.js} +1 -1
  105. package/web-app/dist/index.html +1 -1
  106. package/autonomy/company-seats.json +0 -82
  107. package/docs/COMPETITIVE-INTEL-2026-09.md +0 -444
  108. package/docs/FOUNDER-DECISIONS-TRUST-SEMANTICS-2026-08-01.md +0 -145
  109. package/docs/FOUNDER-STATUS-AND-DECISIONS-2026-07-01.md +0 -132
  110. package/docs/LOKI-10-BUILD-PROMPT.md +0 -350
  111. package/docs/STRATEGY-2026-2028.md +0 -124
  112. package/docs/V10-VISION.md +0 -161
  113. package/docs/v10/ADOPTION-PLAN.md +0 -375
  114. package/docs/v10/ARCHITECT-CUTS.md +0 -744
  115. package/docs/v10/BACKLOG.md +0 -231
  116. package/docs/v10/BOARD.md +0 -1403
  117. package/docs/v10/CONTROL-PLANE.md +0 -120
  118. package/docs/v10/CONTROL.md +0 -36
  119. package/docs/v10/CP-ASK-PLAN.md +0 -85
  120. package/docs/v10/CP-ENTERPRISE-UI.md +0 -537
  121. package/docs/v10/D51-PHASE-B.md +0 -120
  122. package/docs/v10/D61-SPEED.md +0 -105
  123. package/docs/v10/D63-CARDS.md +0 -354
  124. package/docs/v10/DECISIONS.md +0 -915
  125. package/docs/v10/E2E-D65.md +0 -123
  126. package/docs/v10/ENGINE-LAWS.md +0 -163
  127. package/docs/v10/ENGINE-MEASURE.md +0 -69
  128. package/docs/v10/ENGINE.md +0 -743
  129. package/docs/v10/FAILURE-CLASSES.md +0 -2026
  130. package/docs/v10/FC21B-FC22-PLAN.md +0 -107
  131. package/docs/v10/FIRST-RUN-GATE.md +0 -39
  132. package/docs/v10/FOUNDER-QUEUE.md +0 -29
  133. package/docs/v10/GAP-RESEARCH-1003.md +0 -32
  134. package/docs/v10/GUARDS.md +0 -883
  135. package/docs/v10/L0-WAVE1.md +0 -81
  136. package/docs/v10/LEGACY-REMOVAL.md +0 -408
  137. package/docs/v10/MEDIUM-ANALYSIS.md +0 -346
  138. package/docs/v10/METRICS.md +0 -645
  139. package/docs/v10/MODERNIZE.md +0 -437
  140. package/docs/v10/OPENCODE-PARITY-PLAN.md +0 -84
  141. package/docs/v10/OPERATING-MODEL.md +0 -60
  142. package/docs/v10/PLAN-V12.md +0 -896
  143. package/docs/v10/PROGRESS.md +0 -2735
  144. package/docs/v10/RELEASE-11.md +0 -77
  145. package/docs/v10/RETRO-2026.md +0 -650
  146. package/docs/v10/ROADMAP-D63.md +0 -35
  147. package/docs/v10/SCALE.md +0 -140
  148. package/docs/v10/SCORECARD-PLAN.md +0 -250
  149. package/docs/v10/SWARM-PROMPT.md +0 -98
  150. package/docs/v10/SWARM.md +0 -293
  151. package/docs/v10/cp-redesign/PARITY.md +0 -188
  152. package/docs/v10/cp-redesign/legacy/INDEX.md +0 -1167
  153. package/docs/v10/roadmap-10/01-measurement.md +0 -113
  154. package/docs/v10/roadmap-10/02-cost.md +0 -75
  155. package/docs/v10/roadmap-10/03-speed.md +0 -65
  156. package/docs/v10/roadmap-10/04-first-run.md +0 -61
  157. package/docs/v10/roadmap-10/05-deploy.md +0 -61
  158. package/docs/v10/roadmap-10/06-stability.md +0 -64
  159. package/docs/v10/roadmap-10/07-quality.md +0 -57
  160. package/docs/v10/roadmap-10/08-proof.md +0 -48
  161. package/docs/v10/roadmap-10/09-safety.md +0 -74
  162. package/docs/v10/roadmap-10/README.md +0 -1464
  163. package/skills/sdlc-fleet.md +0 -170
  164. package/tools/cockpit/SPEC.md +0 -275
  165. package/tools/cockpit/index.html +0 -146
  166. package/tools/cockpit/roi-basis.json +0 -33
  167. package/tools/cockpit/server.py +0 -946
@@ -1,170 +0,0 @@
1
- # SDLC Fleet Pattern (skill module)
2
-
3
- <!-- TOC:START (generated by scripts/skill-toc.sh; do not edit) -->
4
- ## Contents
5
-
6
- - [When to invoke this pattern](#when-to-invoke-this-pattern)
7
- - [The 6 roles](#the-6-roles)
8
- - [1. Architect (1 agent, Plan subagent_type, model: opus)](#1-architect-1-agent-plan-subagent_type-model-opus)
9
- - [2. Product Owner (the integrator, NOT a separate agent)](#2-product-owner-the-integrator-not-a-separate-agent)
10
- - [3. Dev Fleet (3-5 principal engineers in parallel, model: opus)](#3-dev-fleet-3-5-principal-engineers-in-parallel-model-opus)
11
- - [4. SDET (1-2 agents, model: opus)](#4-sdet-1-2-agents-model-opus)
12
- - [5. Council Reviewers (3 agents, parallel, model: 2 opus + 1 sonnet)](#5-council-reviewers-3-agents-parallel-model-2-opus--1-sonnet)
13
- - [6. Real-User QA (1 agent OR the integrator directly)](#6-real-user-qa-1-agent-or-the-integrator-directly)
14
- - [Parallel-execution rules](#parallel-execution-rules)
15
- - [Honest acknowledgements pattern](#honest-acknowledgements-pattern)
16
- - [Reference run: v7.6.0 LSP integration](#reference-run-v760-lsp-integration)
17
- - [Per-release checklist (always)](#per-release-checklist-always)
18
- <!-- TOC:END -->
19
-
20
- **Established:** v7.7.4 (2026-05-24)
21
- **Origin:** user mandate "agent teams with senior most developers, Loki architects, sdet team and council of reviewers exist and coordinate and work in parallel"
22
- **Proven by:** v7.6.0 fleet ship (architect + 3 principal engineers + SDET + 3-reviewer council + real-user QA) demonstrated the pattern works end-to-end.
23
-
24
- This skill describes the STANDING pattern for shipping any non-trivial change in Loki Mode. The integrator (Claude Code session) is responsible for orchestrating the roles below. Each role is a Loki Agent call.
25
-
26
- ## When to invoke this pattern
27
-
28
- Apply this pattern when shipping ANY of:
29
-
30
- - A new feature touching > 3 files
31
- - A bug fix touching agent runtime, council, memory, or auto-spawn surfaces
32
- - A MINOR or MAJOR release
33
- - A change with cross-route parity implications (bash + Bun + TS)
34
- - A change the user has marked "critical" or "production-blocking"
35
-
36
- Skip this pattern (acceptable shortcuts) when:
37
-
38
- - Single-line typo fix in user-facing strings
39
- - Pure docs edit (no code change)
40
- - A revert of a previously-shipped change with no new logic
41
- - An emergency hotfix where waiting on parallel agents would exceed the production-impact window
42
-
43
- ## The 6 roles
44
-
45
- ### 1. Architect (1 agent, Plan subagent_type, model: opus)
46
-
47
- **Job:** Design the change end-to-end before any code is written. Produces a written plan saved as `docs/<TOPIC>-PLAN.md`.
48
-
49
- **Inputs:** the original user directive verbatim + relevant source files + any prior council findings.
50
-
51
- **Outputs:** a markdown plan with: scope, acceptance criteria, implementation steps, file-level diffs sketch, testing plan, risks + mitigations, NOT-tested honest disclosure.
52
-
53
- **Output is BINDING** for the dev fleet -- don't change scope without re-architecting.
54
-
55
- ### 2. Product Owner (the integrator, NOT a separate agent)
56
-
57
- **Job:** Lock scope before implementation. Use `AskUserQuestion` to surface ambiguity to the user. NEVER guess at scope.
58
-
59
- **Output:** explicit user answer that locks the acceptance criteria.
60
-
61
- ### 3. Dev Fleet (3-5 principal engineers in parallel, model: opus)
62
-
63
- **Job:** Implement independent slices of the architect's plan IN PARALLEL. Each engineer gets a single self-contained task with explicit file references and binding constraints.
64
-
65
- **Pattern:** spawn N agents via `Agent` tool with `run_in_background: true` in ONE message (parallel). Each agent gets:
66
-
67
- - The architect's plan section relevant to their slice
68
- - A SINGLE deliverable (one fix, one feature, one file)
69
- - Binding constraints (no version bumps, no commits, no emojis, no em dashes, NO destructive operations)
70
- - Explicit "report back in N words" cap
71
-
72
- The integrator does NOT delegate synthesis -- they integrate the parallel outputs themselves.
73
-
74
- ### 4. SDET (1-2 agents, model: opus)
75
-
76
- **Job:** Write tests + capture screenshots. For each shipped feature:
77
-
78
- - One or more bash / Playwright tests asserting acceptance criteria
79
- - For UI surfaces: screenshot capture with `chrome --headless --screenshot` or Playwright
80
- - For backends: curl-based smoke tests
81
-
82
- **Output:** test files + screenshot artifacts under `artifacts/<release>-screens/`.
83
-
84
- ### 5. Council Reviewers (3 agents, parallel, model: 2 opus + 1 sonnet)
85
-
86
- **Job:** Independent code review. Binding gate: unanimous APPROVE required to ship.
87
-
88
- **Pattern:** spawn 3 agents in parallel via `Agent` tool. Each gets:
89
-
90
- - The full file diff at HEAD
91
- - Their specialized focus (e.g. "frontend correctness", "backend / integration risk", "release readiness")
92
- - Strict output format: `VOTE: APPROVE | CONCERN | REJECT` + findings list + reasoning
93
-
94
- On any CONCERN or REJECT:
95
-
96
- 1. Integrator reads source + validates concern
97
- 2. If valid: dispatch fix agent + RE-RUN entire council on post-fix state
98
- 3. If invalid: refute with evidence + re-spawn ONLY the dissenting reviewer with the refutation
99
- 4. Loop until 3-of-3 APPROVE
100
- 5. "2-of-3 is good enough" is NEVER acceptable
101
-
102
- ### 6. Real-User QA (1 agent OR the integrator directly)
103
-
104
- **Job:** Install the just-shipped release fresh from npm/bun, run a user-realistic scenario end-to-end, capture screenshots, report any breakage.
105
-
106
- **Pattern:** after `gh release` confirms, run:
107
-
108
- ```bash
109
- bun install -g loki-mode@<NEW_VERSION>
110
- loki --version # confirm new version on PATH
111
- # Then exercise the new feature in a user-realistic way:
112
- loki <new-command> ... # the change we just shipped
113
- ```
114
-
115
- Capture:
116
- - Exit codes
117
- - Output structure
118
- - Any unexpected errors / warnings
119
- - Browser screenshots if UI surface
120
-
121
- ## Parallel-execution rules
122
-
123
- When spawning multiple agents in the SAME message:
124
-
125
- - Use `Agent` tool with `run_in_background: true`
126
- - Send all N tool calls in a SINGLE message (parallel scheduling)
127
- - Each agent gets a SELF-CONTAINED prompt (no shared context)
128
- - Each agent gets a SHORT response cap (under 250 words)
129
- - The integrator INTEGRATES the parallel outputs -- never delegates synthesis
130
-
131
- Anti-pattern: spawning agents sequentially when work is independent. Always parallel.
132
-
133
- ## Honest acknowledgements pattern
134
-
135
- Every CHANGELOG entry that ships work via this pattern MUST include:
136
-
137
- ```markdown
138
- ### NOT tested in this release
139
-
140
- - <each test that was skipped + reason>
141
- - <any feature shipped without end-to-end real-user repro>
142
- - <any divergence from architect plan + workaround>
143
- ```
144
-
145
- Failing to disclose is fabrication. CLAUDE.md MEMORY.md "Be real, no fabrication, no lying" applies.
146
-
147
- ## Reference run: v7.6.0 LSP integration
148
-
149
- Demonstrated this pattern works:
150
-
151
- 1. **Architect** (Plan agent): designed Merge-3 in `docs/MERGE3-PLAN.md`
152
- 2. **Product Owner** (integrator + AskUserQuestion): user chose merge scope
153
- 3. **Dev Fleet** (3 principal engineers in parallel): Engineer A fixed memory PYTHONPATH; Engineer B added USAGE.md auto-gen across bash + TS; Engineer C added Memory drill-down UI
154
- 4. **SDET** (Explore + Playwright): captured 20+ UI screenshots, ran 24-scenario CLI permutation test
155
- 5. **Council** (2 Opus + 1 Sonnet): 2 rounds; round 1 had 2 CONCERN-major; fixes applied; round 2 unanimous APPROVE
156
- 6. **Real-user QA**: fresh `bun install -g loki-mode@7.7.0` + ran on a different stack (Python Flask) than dev test + verified USAGE.md auto-generated + Memory drill-down rendered in a real browser
157
-
158
- Result: 4 releases shipped that day with all 8 GitHub workflows SUCCESS on each.
159
-
160
- ## Per-release checklist (always)
161
-
162
- The binding release procedure is the **Release Workflow** section of `CLAUDE.md`,
163
- which is the authoritative and maintained copy: version bump across every listed
164
- file, dashboard build, tests, pre-publish validation, commit and push, and
165
- distribution verification across all channels.
166
-
167
- This previously pointed at an artifacts/ROADMAP file which has never
168
- existed in this repository -- so an agent following it for the "binding" steps
169
- found nothing and had to guess. The steps live in one place now, and that place
170
- is kept current because every release edits it.
@@ -1,275 +0,0 @@
1
- # CEO cockpit: specification
2
-
3
- Status: spec only (owner: platform-lead to build; chief-of-staff to accept).
4
- Source of the ask: docs/v10/RETRO-2026.md section 6 item 6 (CEO console) and
5
- item 7 (ROI ledger).
6
-
7
- New-file justification (CLAUDE.md "extend, never duplicate"): no existing file
8
- owns company operations for the founder. `dashboard/server.py` is the
9
- user-facing per-run product dashboard and must stay free of company state;
10
- `scripts/v10-pulse.sh`, `tools/cost-history.py` and `scripts/usage-governor.py`
11
- already own pulse, run cost and usage, so the cockpit only invokes them and
12
- renders their output. It re-implements none of their logic.
13
-
14
- ## 1. Goals and non-goals
15
- Goals:
16
- - One page where the CEO sees, within 5 seconds of opening, what the company
17
- is doing, what shipped, what is blocked and what it costs against value.
18
- - One write path: a founder command box that appends a row to
19
- docs/v10/FOUNDER-QUEUE.md for the chief-of-staff to act on.
20
- Non-goals:
21
- - No direct control. Stop-all, dispatch and release actions are queue rows
22
- ("STOP ALL", "pause release") that the chief-of-staff executes by recorded
23
- PID or through release-reliability-lead. The cockpit never signals a
24
- process, edits BOARD.md, runs git writes or calls npm publish.
25
- - No hosted mode, no auth provider, no telemetry.
26
-
27
- ## 2. Hard constraints
28
- 1. Server: Python 3 standard library only (`http.server`,
29
- `ThreadingHTTPServer`, `json`, `subprocess`, `fcntl`, `secrets`). No pip
30
- dependency.
31
- 2. Client: one static file `tools/cockpit/index.html` with inline CSS and JS.
32
- No build step, no CDN, no framework. Works offline.
33
- 3. Bind 127.0.0.1 only. The `--host` flag accepts only `127.0.0.1` or `::1`;
34
- any other value exits 64 with a message. Never `0.0.0.0`.
35
- 4. Read-only except `POST /api/queue`, which only appends to FOUNDER-QUEUE.md.
36
- 5. Testable headless: `--once --json` prints the full snapshot and exits; no
37
- browser is ever opened (honour LOKI_NO_BROWSER; no `webbrowser` import).
38
- 6. Every shell-out has a timeout (default 20 s; pulse 60 s) and a cache, so a
39
- hung `gh` or `npm` never blocks the page. A failed source renders
40
- UNKNOWN with the error line, never a blank or a 0.
41
- 7. No emojis, no em or en dashes in code, UI text or output.
42
-
43
- ## 3. Files
44
- - `tools/cockpit/server.py`: server, collectors, snapshot builder, CLI.
45
- - `tools/cockpit/index.html`: the page.
46
- - `tools/cockpit/roi-basis.json`: the salary basis and ROI assumptions (section
47
- 5.6). Tracked, edited by hand or by the chief-of-staff, versioned in git.
48
- - `tests/test-cockpit.sh`: headless test, registered in
49
- `tests/run-all-tests.sh` and the shard map (retro 3.3.21).
50
- - Runtime only (untracked, under `.loki/`): `.loki/company/status/<slug>.json`
51
- (written by each seat), `.loki/cockpit/cache/*.json`, `.loki/cockpit/token`.
52
-
53
- ## 4. CLI
54
- ```
55
- python3 tools/cockpit/server.py [--port 8787] [--host 127.0.0.1]
56
- [--repo-root PATH] [--once] [--json]
57
- [--panel NAME]
58
- ```
59
- - `--once --json`: build one snapshot, print it, exit 0 (exit 2 if any panel
60
- is UNKNOWN, mirroring the pulse contract 0 clean, 1 violation, 2 unknown;
61
- exit 1 if the pulse reports a VIOLATION).
62
- - `--panel NAME`: restrict `--once` to one panel (pulse, releases, board,
63
- agents, okrs, roi, queue).
64
- - Env overrides (for tests and fixtures): `COCKPIT_NPM_CMD`, `COCKPIT_GH_CMD`,
65
- `COCKPIT_PULSE_CMD`, `BOARD_MD`, `FOUNDER_QUEUE_MD`, `RETRO_MD`,
66
- `USAGE_READINGS_TSV`, `COST_HISTORY_FILE`, `COCKPIT_STATUS_DIR`,
67
- `COCKPIT_NOW` (ISO8601 UTC, for deterministic ages).
68
- - On start the server prints `cockpit: http://127.0.0.1:<port>/` and its PID,
69
- and writes the PID to `.loki/cockpit/server.pid` so it is stopped by
70
- recorded PID only.
71
-
72
- ## 5. Panels and data sources
73
- Each panel in the snapshot has the shape
74
- `{status: OK|VIOLATION|UNKNOWN|UNMEASURED, as_of, source_cmd, data, error}`.
75
- `source_cmd` is the exact command or file read, shown on the page under each
76
- panel (evidence rule, retro 3.1.1).
77
-
78
- ### 5.1 Pulse
79
- - Source: `bash scripts/v10-pulse.sh` (override `COCKPIT_PULSE_CMD`), run with
80
- `PULSE_REPO_ROOT` set to the repo root. Cached 90 s; refreshed in a
81
- background thread so a request never waits on it.
82
- - Parse: every `Key: value` line into `metrics`; every line under
83
- `=== VIOLATIONS ===` starting `VIOLATION:` into `violations`; the
84
- `UNKNOWN metrics:` and `STALE metrics` lines into lists. Exit code 0, 1 or 2
85
- maps to OK, VIOLATION, UNKNOWN.
86
- - Render: violations first in a red band, top one largest; then the metric
87
- table; STALE values shown with their age.
88
-
89
- ### 5.2 Releases
90
- - npm: `npm view loki-mode time dist-tags --json` (override
91
- `COCKPIT_NPM_CMD`). Show `dist-tags.latest`, `dist-tags.next`, the last 20
92
- versions with publish time, releases in the last hour and 24 h, and minutes
93
- since the last publish.
94
- - Release runs: `gh run list --workflow release.yml --limit 20 --json
95
- databaseId,status,conclusion,headSha,createdAt,displayTitle,url` (override
96
- `COCKPIT_GH_CMD`). Show each run with conclusion and link.
97
- - Local: `VERSION` file and `git -C <root> describe --tags --abbrev=0`.
98
- - Derived flags: VERSION vs next vs latest divergence (retro 3.2.27); a
99
- release run with conclusion failure on the newest VERSION SHA is a
100
- VIOLATION. A cached packument is not proof: the panel labels npm data
101
- "registry view" and never claims a tarball is fetchable (retro 3.2.7).
102
-
103
- ### 5.3 BOARD flow
104
- - Source: `docs/v10/BOARD.md` (override `BOARD_MD`). Parse table rows with
105
- columns `ID | Owner | Branch @ SHA | File set | Tier | Status | Notes`.
106
- Status cell is `<token>@YYYY-MM-DDTHH:MMZ`; tokens: ready, building, review,
107
- review-blocked, approved, merged, released, blocked, rejected, parked.
108
- - Render: count per token (flow strip ready, building, review, approved,
109
- merged, released), the active rows (building, review, review-blocked,
110
- approved, blocked) with age in minutes against their tier budget (LOW 15,
111
- MEDIUM 30, HIGH 60 per OPERATING-MODEL.md), and an "unparsed rows" list.
112
- Ready count below 30 is flagged (D91).
113
-
114
- ### 5.4 Agents
115
- - Source: `.loki/company/status/<slug>.json` for the 10 slugs in
116
- `.claude/agents/` (list derived from that directory, never hard-coded).
117
- Schema: `{seat, model, doing, slice, since, next, blocked_on, updated}`.
118
- - Render one card per seat: model, what it is doing, slice ID linking to the
119
- BOARD row, minutes since `updated`. A seat with no file is UNKNOWN; a file
120
- older than 60 min is STALE; `blocked_on` non-empty is highlighted.
121
- - Also show the seat's owned root causes, parsed from the "Root causes
122
- owned" section of its agent file.
123
-
124
- ### 5.5 OKRs
125
- - Source: `docs/v10/RETRO-2026.md` section 6 (override `RETRO_MD`): the 20
126
- numbered items, each parsed into title (first sentence), owner (text after
127
- `Owner:` up to the next period) and metric (text after `Metric:`).
128
- - Current values: `.loki/company/okrs.json`, written by the owning seats,
129
- shape `{"<item number>": {value, target, status, source_cmd, as_of}}`.
130
- - Render the 20 rows ranked as in the retro. An item with no current value
131
- shows UNMEASURED, never 0 and never green. A value without `source_cmd` is
132
- shown as UNCITED and counts against verification-scientist.
133
-
134
- ### 5.6 ROI
135
- Two sides, always labelled with their measurement state.
136
-
137
- Agent cost (left side):
138
- - Plan cost: `roi-basis.json` field `plan_usd_per_month` (default 200, the
139
- founder's stated spend, retro RC9 evidence), prorated per day.
140
- - Usage share: `docs/v10/usage-readings.tsv` (columns `utc_time
141
- window_percent weekly_percent`) and `python3 scripts/usage-governor.py
142
- --json`. These are plan-usage percentages, not tokens or dollars; the panel
143
- says so and shows weekly percent used.
144
- - Metered run cost: `python3 tools/cost-history.py report --json` (file
145
- override `COST_HISTORY_FILE`). Shows measured runs, unmeasured runs (usd
146
- null) as a separate count, and total measured USD. A missing history file
147
- is UNMEASURED.
148
- - Budget line: the $50 per day budget from FOUNDER-QUEUE row 3, as a
149
- configurable `daily_budget_usd`.
150
- - Cost is labelled ESTIMATE when derived from plan proration, MEASURED only
151
- when it comes from cost-history measured rows.
152
-
153
- Human-equivalent value (right side):
154
- - Salary basis in `roi-basis.json`, versioned, every figure with source URL
155
- and snapshot date:
156
- ```json
157
- {
158
- "source_url": "https://www.levels.fyi/companies/anthropic/salaries/software-engineer",
159
- "snapshot_date": "2026-09-24",
160
- "annual_total_comp_usd": {
161
- "entry": 483000, "senior": 621000, "lead": 865000,
162
- "staff": 1410000, "median": 883000
163
- },
164
- "research_scientist_median_usd": {"value": null, "status": "UNVERIFIED"},
165
- "research_engineer_usd": {"value": null, "status": "NOT FOUND"},
166
- "overhead_multiplier": {"value": 1.25, "status": "ASSUMPTION"},
167
- "work_hours_per_year": {"value": 2000, "status": "ASSUMPTION"},
168
- "seat_tier": {"chief-of-staff": "lead", "cto": "staff", "...": "..."},
169
- "hours_per_outcome": {"verified_slice": {"value": null, "status": "ASSUMPTION, unset"}},
170
- "plan_usd_per_month": 200,
171
- "daily_budget_usd": 50
172
- }
173
- ```
174
- The figures match RETRO-2026.md 3.8.10 and were re-fetched from the URL on
175
- 2026-10-23. The basis is flagged STALE when `snapshot_date` is older than
176
- 90 days.
177
- - Value formula, shown on the page: hourly rate = annual total comp x
178
- overhead multiplier / work hours per year; human-equivalent value = sum over
179
- released slices (BOARD released tokens in the window) of hours per outcome
180
- x hourly rate for the owning seat's tier.
181
- - Value is UNMEASURED while `hours_per_outcome` is unset. The page then shows
182
- only "standing 10-seat payroll equivalent" (sum of tier comp x overhead for
183
- 10 seats, labelled ASSUMPTION) next to agent cost, and never prints an ROI
184
- multiple.
185
- - ROI multiple is shown only when both sides are non-null, with the label of
186
- the weaker side (ESTIMATE or ASSUMPTION). Per verified outcome cost comes
187
- from the outcome scoreboard (`.loki/company/scoreboard/*.json`) when it
188
- exists, else UNMEASURED.
189
- - Every assumption is editable only in `roi-basis.json`; the page shows its
190
- path and git SHA, never an inline editor.
191
-
192
- ### 5.7 Founder command box
193
- - UI: one textarea (max 2000 characters), one "Why only you" optional field,
194
- one submit button. After submit, the page shows the appended row number
195
- and the line written.
196
- - `POST /api/queue`, body JSON `{item, why}`; returns `{row, line}`.
197
- - Append rules:
198
- 1. Take an exclusive `fcntl.flock` on `FOUNDER-QUEUE.md.lock` (sidecar,
199
- under `.loki/cockpit/`), with a 5 s timeout returning 503.
200
- 2. Read the file; allocate the next number as max existing `#` + 1.
201
- 3. Sanitize: strip control characters, replace newlines with spaces and
202
- `|` with `/`, trim, reject empty (400) or over the cap (413).
203
- 4. Write one row in the existing header shape
204
- `| # | Date | Item | Why only you | Loop does meanwhile |` with Date as
205
- today UTC `YYYY-MM-DD`, Item prefixed `[cockpit]`, Why from the field or
206
- `founder command`, Loop cell `chief-of-staff to triage`, plus trailing
207
- status cell `open`.
208
- 5. Append only (`open(path, "a")`), then fsync, then re-read and verify the
209
- file did not shrink and the new row is the last line (shrink guard,
210
- retro 3.3.17). On failure return 500 and leave the file unchanged.
211
- - The cockpit never commits the change; the chief-of-staff triages and
212
- commits.
213
-
214
- ## 6. HTTP API
215
- | Method | Path | Returns |
216
- |---|---|---|
217
- | GET | `/` | index.html |
218
- | GET | `/api/snapshot` | all panels |
219
- | GET | `/api/panel/<name>` | one panel |
220
- | GET | `/healthz` | `{"ok": true, "pid": N}` |
221
- | POST | `/api/queue` | append result |
222
- Every other method or path returns 405 or 404.
223
-
224
- Security:
225
- - Reject any request whose `Host` header is not `127.0.0.1:<port>`,
226
- `localhost:<port>` or `[::1]:<port>` (DNS rebinding).
227
- - `POST /api/queue` requires header `X-Cockpit-Token` equal to a per-process
228
- random token (`secrets.token_urlsafe(32)`), written to
229
- `.loki/cockpit/token` with mode 600 and injected into the served page; and
230
- an `Origin` equal to the served origin. Missing or wrong: 403.
231
- - Request body capped at 8 KB. Responses set `Cache-Control: no-store`,
232
- `X-Content-Type-Options: nosniff` and a CSP of `default-src 'self';
233
- script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'`.
234
- - Subprocesses run with an argument list (never `shell=True`) and an env built
235
- deny-by-default (PATH, HOME, USER, LOGNAME, LANG, gh and npm config paths
236
- only), per security-lead rule 3.9.2.
237
- - No file path from a request is ever opened; all paths come from flags or
238
- env.
239
-
240
- ## 7. Page behaviour
241
- - Polls `/api/snapshot` every 15 s; panels update in place without layout
242
- shift (fixed card heights, skeleton rows); a "last refreshed" time and the
243
- age of each source are always visible.
244
- - Order: pulse violations band, agents, BOARD flow, releases, OKRs, ROI,
245
- command box.
246
- - Light and dark from `prefers-color-scheme`; readable at 1280 px and 390 px.
247
- - Every number has a hover or caption with its `source_cmd` and `as_of`.
248
-
249
- ## 8. Headless test (`tests/test-cockpit.sh`)
250
- Uses `loki_run_tmp_create` and `loki_run_tmp_cleanup`, stops the server by its
251
- recorded PID only, sets `LOKI_NO_BROWSER=1`. Fixtures under the run tmp dir:
252
- - A BOARD.md with one row per token plus one unparsed row; assert counts.
253
- - A FOUNDER-QUEUE.md copy; POST an item containing `|`, a newline and 2001
254
- characters; assert 413, then a valid item, assert row number = max + 1, the
255
- pipe replaced, the file only grew, and two concurrent POSTs get distinct
256
- numbers.
257
- - Stub `COCKPIT_NPM_CMD` and `COCKPIT_GH_CMD` scripts emitting fixed JSON,
258
- and one that sleeps past the timeout; assert UNKNOWN, not a hang.
259
- - Missing cost-history and empty status dir: assert ROI cost UNMEASURED and
260
- agents UNKNOWN, and that no panel prints `0` for an unmeasured value.
261
- - `--host 0.0.0.0` exits 64. POST without token: 403. Bad Host: 403.
262
- - `--once --json` output parses and its exit code matches the pulse stub's
263
- exit code mapping.
264
- - Positive control for every absence assertion (retro 3.1.6): the same probe
265
- run on a fixture that does contain the value must find it.
266
-
267
- ## 9. Acceptance (Wall checks)
268
- 1. `python3 tools/cockpit/server.py --once --json | python3 -m json.tool`
269
- exits 0 or 2 on a clean checkout, with all 7 panels present.
270
- 2. `bash tests/test-cockpit.sh` passes, and fails when the append sanitizer
271
- or the Host check is removed (mutation).
272
- 3. `lsof -nP -iTCP:<port> -sTCP:LISTEN` shows 127.0.0.1 only.
273
- 4. No file under the repo changes after an hour of page polling except
274
- FOUNDER-QUEUE.md on submit (`git status --porcelain` diff).
275
- 5. Screenshot at 1280 px and 390 px reviewed by developer-experience-lead.
@@ -1,146 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Loki Cockpit</title>
7
- <style>
8
- :root{--bg:#f4f5f8;--card:#fff;--ink:#14161c;--mute:#5b6270;--line:#d9dde6;--ok:#17653a;--bad:#a4161a;--warn:#8a5a00;--unk:#4a4f6a;--badbg:#fde8e8;--accent:#2b4ed8}
9
- @media (prefers-color-scheme:dark){:root{--bg:#0f1115;--card:#171a21;--ink:#e8eaf0;--mute:#9aa3b5;--line:#2a2f3a;--ok:#5fd08f;--bad:#ff8083;--warn:#f0b955;--unk:#9fa6c8;--badbg:#3a1618;--accent:#8aa2ff}}
10
- *{box-sizing:border-box}
11
- body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.45 system-ui,-apple-system,Segoe UI,sans-serif}
12
- header{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:baseline;padding:12px 16px;border-bottom:1px solid var(--line)}
13
- header h1{font-size:16px;margin:0}
14
- #refreshed{color:var(--mute);font-size:12px}
15
- main{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr));gap:12px;padding:12px 16px}
16
- section{background:var(--card);border:1px solid var(--line);border-radius:8px;padding:12px;min-height:160px;overflow:hidden}
17
- section.wide{grid-column:1/-1}
18
- h2{font-size:13px;margin:0 0 8px;text-transform:uppercase;letter-spacing:.04em;display:flex;gap:8px;align-items:center}
19
- .badge{font-size:11px;padding:1px 6px;border-radius:10px;border:1px solid currentColor}
20
- .OK{color:var(--ok)}.VIOLATION{color:var(--bad)}.UNKNOWN,.UNMEASURED,.UNCITED{color:var(--unk)}.STALE{color:var(--warn)}
21
- .src{margin-top:8px;color:var(--mute);font:11px ui-monospace,Menlo,monospace;word-break:break-all}
22
- .err{color:var(--warn);font-size:12px;margin:4px 0}
23
- .band{background:var(--badbg);color:var(--bad);border:1px solid var(--bad);border-radius:6px;padding:8px;margin-bottom:8px}
24
- .band .top{font-size:16px;font-weight:600}
25
- table{width:100%;border-collapse:collapse;font-size:12px}
26
- td,th{text-align:left;padding:3px 6px 3px 0;border-bottom:1px solid var(--line);vertical-align:top;word-break:break-word}
27
- .flow{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
28
- .flow div{border:1px solid var(--line);border-radius:6px;padding:4px 8px;min-width:78px}
29
- .flow b{display:block;font-size:18px}
30
- .cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:8px}
31
- .card{border:1px solid var(--line);border-radius:6px;padding:8px;font-size:12px}
32
- .card.blocked{border-color:var(--bad)}
33
- .mute{color:var(--mute)}
34
- textarea,input[type=text]{width:100%;background:var(--bg);color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:8px;font:inherit}
35
- button{background:var(--accent);color:#fff;border:0;border-radius:6px;padding:8px 14px;font:inherit;cursor:pointer}
36
- button:disabled{opacity:.5}
37
- #qres{margin-top:8px;font-size:12px;min-height:18px;word-break:break-word}
38
- </style>
39
- </head>
40
- <body>
41
- <header><h1>Loki Cockpit</h1><span id="refreshed">loading</span><span class="mute" id="fail"></span></header>
42
- <main>
43
- <section class="wide" id="p-pulse"><h2>Pulse</h2><div class="body">loading</div></section>
44
- <section class="wide" id="p-agents"><h2>Agents</h2><div class="body">loading</div></section>
45
- <section id="p-board"><h2>BOARD flow</h2><div class="body">loading</div></section>
46
- <section id="p-releases"><h2>Releases</h2><div class="body">loading</div></section>
47
- <section class="wide" id="p-okrs"><h2>OKRs</h2><div class="body">loading</div></section>
48
- <section class="wide" id="p-roi"><h2>ROI</h2><div class="body">loading</div></section>
49
- <section class="wide" id="p-queue"><h2>Founder command box</h2><div class="body">loading</div>
50
- <div>
51
- <textarea id="item" rows="3" maxlength="2000" placeholder="Command or decision for the chief of staff (max 2000 characters)"></textarea>
52
- <input type="text" id="why" maxlength="500" placeholder="Why only you (optional)">
53
- <p><button id="send">Append to FOUNDER-QUEUE</button> <span class="mute" id="count">0/2000</span></p>
54
- <div id="qres"></div>
55
- </div>
56
- </section>
57
- </main>
58
- <script>
59
- (function(){
60
- "use strict";
61
- var TOKEN="__COCKPIT_TOKEN__";
62
- function h(tag,attrs){var e=document.createElement(tag);if(attrs){for(var k in attrs){if(k==="class")e.className=attrs[k];else if(k==="title")e.title=attrs[k];else e.setAttribute(k,attrs[k]);}}
63
- for(var i=2;i<arguments.length;i++){var c=arguments[i];if(c===null||c===undefined)continue;e.appendChild(typeof c==="object"?c:document.createTextNode(String(c)));}return e;}
64
- function show(v){return v===null||v===undefined?"UNKNOWN":String(v);}
65
- function badge(s){return h("span",{"class":"badge "+s},s);}
66
- function src(p){return h("div",{"class":"src",title:"as of "+p.as_of},"source: "+p.source_cmd+" as of "+p.as_of+(p.cache_age_s!==undefined?" cached "+p.cache_age_s+"s":""));}
67
- function err(p){return p.error?h("div",{"class":"err"},p.error):null;}
68
- function table(rows,head){var t=h("table");if(head){var tr=h("tr");head.forEach(function(x){tr.appendChild(h("th",null,x));});t.appendChild(tr);}
69
- rows.forEach(function(r){var tr=h("tr");r.forEach(function(c){tr.appendChild(h("td",null,c));});t.appendChild(tr);});return t;}
70
- function fill(id,p,build){var s=document.getElementById("p-"+id);var b=s.querySelector(".body");var h2=s.querySelector("h2");
71
- while(h2.childNodes.length>1)h2.removeChild(h2.lastChild);h2.appendChild(badge(p.status));
72
- var nb=h("div",{"class":"body"});try{build(nb,p.data||{},p);}catch(e){nb.appendChild(h("div",{"class":"err"},"render error: "+e));}
73
- nb.appendChild(err(p));nb.appendChild(src(p));s.replaceChild(nb,b);}
74
-
75
- var R={};
76
- R.pulse=function(b,d){
77
- var v=d.violations||[];
78
- if(v.length){var band=h("div",{"class":"band"});band.appendChild(h("div",{"class":"top"},v[0]));
79
- v.slice(1).forEach(function(x){band.appendChild(h("div",null,x));});b.appendChild(band);}
80
- else if(d.exit_code===0)b.appendChild(h("div",{"class":"OK"},"No violations."));
81
- var m=d.metrics||{};b.appendChild(table(Object.keys(m).map(function(k){return [k,m[k]];})));
82
- if((d.unknown_metrics||[]).length)b.appendChild(h("p",{"class":"mute"},"UNKNOWN metrics: "+d.unknown_metrics.join(", ")));
83
- (d.stale||[]).forEach(function(x){b.appendChild(h("p",{"class":"STALE"},x));});};
84
- R.agents=function(b,d){var c=h("div",{"class":"cards"});
85
- (d.seats||[]).forEach(function(s){var card=h("div",{"class":"card"+(s.blocked?" blocked":"")});
86
- card.appendChild(h("div",null,h("b",null,s.slug)," ",badge(s.state)));
87
- if(s.state==="UNKNOWN"){card.appendChild(h("div",{"class":"mute"},s.error||"no status file"));}
88
- else{card.appendChild(h("div",null,"model: "+show(s.model)));card.appendChild(h("div",null,"doing: "+show(s.doing)));
89
- card.appendChild(h("div",null,"slice: "+show(s.slice)));card.appendChild(h("div",null,"updated: "+show(s.updated_min_ago)+" min ago"));
90
- if(s.blocked_on)card.appendChild(h("div",{"class":"VIOLATION"},"blocked on: "+s.blocked_on));}
91
- var tk=s.tick||{};card.appendChild(h("div",null,"last tick: "+show(tk.last_tick)+" ("+show(tk.outcome)+")"));
92
- card.appendChild(h("div",null,"next due: "+show(tk.next_due)+(tk.state==="STALE"?" STALE (no tick in 2x "+tk.interval_min+" min)":"")));
93
- (s.root_causes||[]).forEach(function(r){card.appendChild(h("div",{"class":"mute"},r));});c.appendChild(card);});
94
- b.appendChild(c);};
95
- R.board=function(b,d){var f=h("div",{"class":"flow"});var cs=d.counts||{};
96
- ["ready","building","review","approved","merged","released"].forEach(function(t){f.appendChild(h("div",null,h("b",null,show(cs[t])),t));});b.appendChild(f);
97
- if(d.ready_below_30)b.appendChild(h("div",{"class":"err"},"ready queue below "+d.ready_target+" (D91)"));
98
- b.appendChild(table((d.active||[]).map(function(r){return [r.id,r.owner,r.tier,r.token,show(r.age_min)+" / "+show(r.budget_min)+" min"+(r.over_budget?" OVER":"")];}),["ID","Owner","Tier","Status","Age / budget"]));
99
- if((d.unparsed||[]).length)b.appendChild(h("p",{"class":"mute"},"Unparsed rows: "+d.unparsed.join(", ")));};
100
- R.releases=function(b,d){
101
- b.appendChild(table([["npm latest",show(d.latest)],["npm next",show(d.next)],["VERSION",show(d.version_file)],["last tag",show(d.last_tag)],
102
- ["minutes since last publish",show(d.last_publish_minutes_ago)],["releases last hour",show(d.releases_last_hour)],["releases last 24h",show(d.releases_last_24h)]]));
103
- b.appendChild(h("p",{"class":"mute"},d.npm_label));
104
- (d.flags||[]).forEach(function(x){b.appendChild(h("div",{"class":"VIOLATION"},x));});
105
- b.appendChild(table((d.runs||[]).slice(0,8).map(function(r){var a=h("a",{href:r.url||"#",rel:"noreferrer",target:"_blank"},String(r.databaseId));return [a,show(r.conclusion||r.status),(r.headSha||"").slice(0,8)];}),["Run","Result","SHA"]));
106
- b.appendChild(table((d.versions||[]).slice(0,10).map(function(v){return [v.version,v.published];}),["Version","Published"]));};
107
- R.okrs=function(b,d){b.appendChild(table((d.items||[]).map(function(i){
108
- var cur=i.current?(show(i.current.value)+(i.current.target!==undefined?" / "+i.current.target:"")):"";
109
- return [i.n,i.title,show(i.owner),h("span",{"class":i.state},i.state),cur];}),["#","Item","Owner","State","Value / target"]));};
110
- R.roi=function(b,d){var c=d.cost||{},v=d.value||{},r=d.roi||{},m=c.metered||{},u=c.usage||{};
111
- b.appendChild(h("h3",null,"Agent cost ("+c.label+")"));
112
- b.appendChild(table([["plan USD per month",show(c.plan_usd_per_month)],["plan USD per day (ESTIMATE)",show(c.plan_usd_per_day)],["daily budget USD",show(c.daily_budget_usd)],
113
- ["weekly plan-usage percent",show(u.weekly_percent)],["5h window percent",show(u.window_percent)],
114
- ["metered run cost",m.state==="MEASURED"?("USD "+m.total_usd+" over "+m.measured_runs+" runs ("+m.unmeasured_runs+" unmeasured)"):("UNMEASURED: "+show(m.reason))]]));
115
- b.appendChild(h("p",{"class":"mute"},c.label_note+". Usage numbers are plan percentages, not tokens or dollars."));
116
- b.appendChild(h("h3",null,"Human-equivalent value ("+show(v.state||"standing payroll only")+")"));
117
- var pr=v.standing_payroll_equivalent;
118
- b.appendChild(table([["standing payroll equivalent per day",pr?("USD "+pr.per_day_usd+" for "+pr.seats+" seats, "+pr.label):"UNKNOWN"],
119
- ["human-equivalent value",v.human_equivalent_usd===null||v.human_equivalent_usd===undefined?"UNMEASURED":"USD "+v.human_equivalent_usd],["ROI multiple",r.multiple===null?"not printed ("+r.note+")":r.multiple+"x ("+r.weaker_side_label+")"],
120
- ["cost per verified outcome",(d.scoreboard||{}).cost_per_verified_outcome_usd===null?"UNMEASURED":"USD "+d.scoreboard.cost_per_verified_outcome_usd]]));
121
- b.appendChild(h("p",{"class":"mute"},"Formula: "+v.formula));
122
- var bs=d.basis||{};b.appendChild(h("p",{"class":"mute"},"Basis: "+bs.path+" at "+show(bs.git_sha)+", snapshot "+show(bs.snapshot_date)+(bs.stale?" (STALE: "+bs.stale_note+")":"")+", source "+show(bs.source_url)));
123
- (d.notes||[]).forEach(function(x){b.appendChild(h("div",{"class":"err"},x));});};
124
- R.queue=function(b,d){b.appendChild(h("p",null,"Rows: "+show(d.rows_total)+", last number "+show(d.max_number)+", from cockpit "+show(d.cockpit_rows)));
125
- b.appendChild(table((d.last||[]).map(function(r){return [r.n,r.date,r.item];}),["#","Date","Item"]));};
126
-
127
- function render(snap){var ps=snap.panels||{};Object.keys(R).forEach(function(k){if(ps[k])fill(k,ps[k],R[k]);});
128
- document.getElementById("refreshed").textContent="last refreshed "+new Date().toLocaleTimeString()+" (generated "+snap.generated_at+")";
129
- document.getElementById("fail").textContent="";}
130
- function poll(){fetch("/api/snapshot",{cache:"no-store"}).then(function(r){return r.json();}).then(render)
131
- .catch(function(e){document.getElementById("fail").textContent="refresh failed: "+e;});}
132
- poll();setInterval(poll,15000);
133
-
134
- var item=document.getElementById("item");
135
- item.addEventListener("input",function(){document.getElementById("count").textContent=item.value.length+"/2000";});
136
- document.getElementById("send").addEventListener("click",function(){
137
- var btn=this,res=document.getElementById("qres");btn.disabled=true;res.textContent="sending";
138
- fetch("/api/queue",{method:"POST",headers:{"Content-Type":"application/json","X-Cockpit-Token":TOKEN},
139
- body:JSON.stringify({item:item.value,why:document.getElementById("why").value})})
140
- .then(function(r){return r.json().then(function(j){return {ok:r.ok,j:j};});})
141
- .then(function(x){res.textContent=x.ok?("Appended row "+x.j.row+": "+x.j.line):("Rejected: "+x.j.error);if(x.ok){item.value="";poll();}})
142
- .catch(function(e){res.textContent="Failed: "+e;}).then(function(){btn.disabled=false;});});
143
- })();
144
- </script>
145
- </body>
146
- </html>
@@ -1,33 +0,0 @@
1
- {
2
- "source_url": "https://www.levels.fyi/companies/anthropic/salaries/software-engineer",
3
- "snapshot_date": "2026-09-24",
4
- "refetched_on": "2026-10-23",
5
- "annual_total_comp_usd": {
6
- "entry": 483000,
7
- "senior": 621000,
8
- "lead": 865000,
9
- "staff": 1410000,
10
- "median": 883000
11
- },
12
- "research_scientist_median_usd": {"value": null, "status": "UNVERIFIED"},
13
- "research_engineer_usd": {"value": null, "status": "NOT FOUND"},
14
- "overhead_multiplier": {"value": 1.25, "status": "ASSUMPTION"},
15
- "work_hours_per_year": {"value": 2000, "status": "ASSUMPTION"},
16
- "default_tier": "senior",
17
- "seat_tier_status": "ASSUMPTION",
18
- "seat_tier": {
19
- "chief-of-staff": "lead",
20
- "cto": "staff",
21
- "developer-experience-lead": "lead",
22
- "platform-lead": "lead",
23
- "product-growth-lead": "lead",
24
- "release-reliability-lead": "lead",
25
- "research-harness-scientist": "lead",
26
- "research-outcomes-scientist": "lead",
27
- "security-lead": "lead",
28
- "verification-scientist": "lead"
29
- },
30
- "hours_per_outcome": {"verified_slice": {"value": null, "status": "ASSUMPTION, unset"}},
31
- "plan_usd_per_month": 200,
32
- "daily_budget_usd": 50
33
- }