honestweek 0.0.0-stage → 0.2.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 (157) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/.claude-plugin/plugin.json +9 -0
  3. package/LICENSE +21 -0
  4. package/README.md +661 -2
  5. package/SKILL.md +129 -0
  6. package/bin/honestweek.mjs +240 -0
  7. package/honestweek.config.example.json +76 -0
  8. package/lib/archive.mjs +63 -0
  9. package/lib/atomic-json.mjs +42 -0
  10. package/lib/badges.mjs +43 -0
  11. package/lib/bounded-jsonl.mjs +39 -0
  12. package/lib/build.mjs +680 -0
  13. package/lib/carry-receipts.mjs +102 -0
  14. package/lib/carry-recovery.mjs +19 -0
  15. package/lib/claude-adapter.mjs +602 -0
  16. package/lib/client.mjs +397 -0
  17. package/lib/codex-records.mjs +167 -0
  18. package/lib/config.mjs +511 -0
  19. package/lib/curation-similarity.mjs +20 -0
  20. package/lib/demo/content.mjs +262 -0
  21. package/lib/demo/extra.mjs +1061 -0
  22. package/lib/demo/repo.mjs +385 -0
  23. package/lib/demo/week.mjs +2558 -0
  24. package/lib/digest-carry.mjs +538 -0
  25. package/lib/digest-curation.mjs +548 -0
  26. package/lib/digest-evidence.mjs +348 -0
  27. package/lib/digest-lifecycle.mjs +142 -0
  28. package/lib/digest-schema.mjs +58 -0
  29. package/lib/digest-source-bound.mjs +46 -0
  30. package/lib/digest-store.mjs +485 -0
  31. package/lib/digest.mjs +437 -0
  32. package/lib/discover.mjs +193 -0
  33. package/lib/emit/_shared.mjs +122 -0
  34. package/lib/emit/changelog.mjs +62 -0
  35. package/lib/emit/client.mjs +311 -0
  36. package/lib/emit/digest.mjs +53 -0
  37. package/lib/emit/goals-page.mjs +416 -0
  38. package/lib/emit/index.mjs +155 -0
  39. package/lib/emit/page.mjs +423 -0
  40. package/lib/emit/post.mjs +22 -0
  41. package/lib/emit/report.mjs +51 -0
  42. package/lib/git.mjs +568 -0
  43. package/lib/goals.mjs +539 -0
  44. package/lib/handoffs.mjs +151 -0
  45. package/lib/harvest.mjs +162 -0
  46. package/lib/history.mjs +110 -0
  47. package/lib/init.mjs +576 -0
  48. package/lib/invocation.mjs +102 -0
  49. package/lib/loopback-host.mjs +16 -0
  50. package/lib/mine/corpus.mjs +641 -0
  51. package/lib/mine/detect.mjs +681 -0
  52. package/lib/mine/draft.mjs +262 -0
  53. package/lib/mine/ledger.mjs +189 -0
  54. package/lib/mine/rank.mjs +236 -0
  55. package/lib/mine.mjs +381 -0
  56. package/lib/preview.mjs +504 -0
  57. package/lib/private-words.mjs +31 -0
  58. package/lib/problems/catalog.json +5884 -0
  59. package/lib/problems/checks.mjs +1454 -0
  60. package/lib/problems/classify.mjs +910 -0
  61. package/lib/problems/context.mjs +448 -0
  62. package/lib/problems/drafts.mjs +57 -0
  63. package/lib/problems/fix-tests.mjs +270 -0
  64. package/lib/problems/index.mjs +332 -0
  65. package/lib/problems/scope.mjs +401 -0
  66. package/lib/prompt-adapters.mjs +229 -0
  67. package/lib/prompt-curation.mjs +71 -0
  68. package/lib/prompt-identity.mjs +18 -0
  69. package/lib/prompt-lane.mjs +84 -0
  70. package/lib/prompt-lock.mjs +23 -0
  71. package/lib/prompt-privacy.mjs +451 -0
  72. package/lib/prompt-store.mjs +111 -0
  73. package/lib/prompts.mjs +100 -0
  74. package/lib/reader.mjs +189 -0
  75. package/lib/readers/client.json +9 -0
  76. package/lib/readers/default.json +5 -0
  77. package/lib/redact.mjs +577 -0
  78. package/lib/redaction-patterns.mjs +993 -0
  79. package/lib/replay/assemble.mjs +523 -0
  80. package/lib/replay/classify.mjs +464 -0
  81. package/lib/replay/claude.mjs +937 -0
  82. package/lib/replay/codex-program.mjs +459 -0
  83. package/lib/replay/codex.mjs +908 -0
  84. package/lib/replay/evidence.mjs +78 -0
  85. package/lib/replay/goals.mjs +287 -0
  86. package/lib/replay/ids.mjs +54 -0
  87. package/lib/replay/index.mjs +690 -0
  88. package/lib/replay/jsonl.mjs +102 -0
  89. package/lib/replay/launch.mjs +164 -0
  90. package/lib/replay/lookup.mjs +374 -0
  91. package/lib/replay/metrics.mjs +51 -0
  92. package/lib/replay/outcomes.mjs +233 -0
  93. package/lib/replay/parse-common.mjs +281 -0
  94. package/lib/replay/sources.mjs +205 -0
  95. package/lib/replay/timeline.mjs +331 -0
  96. package/lib/replay/views.mjs +340 -0
  97. package/lib/repo-identity.mjs +101 -0
  98. package/lib/resolve-week.mjs +178 -0
  99. package/lib/site/adapter.mjs +168 -0
  100. package/lib/site/archive.mjs +48 -0
  101. package/lib/site/derive.mjs +443 -0
  102. package/lib/site/detect.mjs +138 -0
  103. package/lib/site/emit-site.mjs +94 -0
  104. package/lib/site/fact-fence.mjs +148 -0
  105. package/lib/site/inspect.mjs +102 -0
  106. package/lib/site/load-adapter.mjs +30 -0
  107. package/lib/site/sessions.mjs +274 -0
  108. package/lib/site/transform.mjs +114 -0
  109. package/lib/site/values.mjs +153 -0
  110. package/lib/site/week-grid.mjs +49 -0
  111. package/lib/validate.mjs +258 -0
  112. package/lib/view/assets/common.css +789 -0
  113. package/lib/view/assets/common.js +1007 -0
  114. package/lib/view/assets/evidence.js +64 -0
  115. package/lib/view/assets/facts.js +100 -0
  116. package/lib/view/assets/form.js +211 -0
  117. package/lib/view/assets/goal.html +92 -0
  118. package/lib/view/assets/goal.js +638 -0
  119. package/lib/view/assets/insights.js +188 -0
  120. package/lib/view/assets/key.js +355 -0
  121. package/lib/view/assets/prefs.js +250 -0
  122. package/lib/view/assets/private-text.js +41 -0
  123. package/lib/view/assets/problems.css +191 -0
  124. package/lib/view/assets/problems.html +75 -0
  125. package/lib/view/assets/problems.js +1069 -0
  126. package/lib/view/assets/replay-model.js +704 -0
  127. package/lib/view/assets/replay.css +306 -0
  128. package/lib/view/assets/replay.html +122 -0
  129. package/lib/view/assets/replay.js +2079 -0
  130. package/lib/view/assets/search.html +48 -0
  131. package/lib/view/assets/search.js +615 -0
  132. package/lib/view/assets/sessions.js +144 -0
  133. package/lib/view/assets/settings.html +99 -0
  134. package/lib/view/assets/settings.js +183 -0
  135. package/lib/view/assets/setup.html +96 -0
  136. package/lib/view/assets/setup.js +131 -0
  137. package/lib/view/assets/strip.js +465 -0
  138. package/lib/view/codex-judge.mjs +411 -0
  139. package/lib/view/data.mjs +1339 -0
  140. package/lib/view/facts.mjs +306 -0
  141. package/lib/view/insights.mjs +309 -0
  142. package/lib/view/leaks.mjs +252 -0
  143. package/lib/view/problems-route.mjs +425 -0
  144. package/lib/view/progressive.mjs +134 -0
  145. package/lib/view/replay-export.mjs +252 -0
  146. package/lib/view/selftest/clickthrough.html +32 -0
  147. package/lib/view/selftest/clickthrough.js +2678 -0
  148. package/lib/view/server.mjs +336 -0
  149. package/lib/view/settings.mjs +369 -0
  150. package/lib/view/setup.mjs +286 -0
  151. package/lib/view/window.mjs +204 -0
  152. package/lib/view/word-index.mjs +192 -0
  153. package/lib/view.mjs +572 -0
  154. package/lib/voice-fence.mjs +213 -0
  155. package/lib/windows-root.mjs +17 -0
  156. package/lib/worktrees.mjs +260 -0
  157. package/package.json +44 -4
package/README.md CHANGED
@@ -1,3 +1,662 @@
1
- # Temporary Holding Version
1
+ # honestweek
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![CI](https://github.com/BryceEWatson/honestweek/actions/workflows/ci.yml/badge.svg)](https://github.com/BryceEWatson/honestweek/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+
6
+ See where your Claude Code and Codex sessions went wrong, open the exact steps behind each problem, and check every count yourself. Local and rule-based; nothing is sent to an AI unless you ask.
7
+
8
+ <picture>
9
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/replay-dark.png">
10
+ <img src="docs/images/replay-light.png" alt="Replay of a three-hour session from the made-up demo week: one row for the main agent and one for each of its seven sub-agents, a Problems row with two rings, and the selected step, where the agent says all tests pass right after a test run failed.">
11
+ </picture>
12
+
13
+ Replay of the longest session in the made-up demo week (`npx honestweek view --demo`, with Show private text on): a main agent and seven sub-agents building a feature over three hours. The rings on the Problems row mark the two things worth a look, and the selected one is the agent saying "All tests pass" right after a run that failed.
14
+
15
+ <details>
16
+ <summary>More screenshots: Problems, a problem up close, sessions, Find, Goals, Setup, a weekly page and a client report</summary>
17
+
18
+ **Problems** shows the known ways agents go wrong that turned up in your week, worst first, each with a fix to copy.
19
+
20
+ <picture>
21
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/problems-dark.png">
22
+ <img src="docs/images/problems-light.png" alt="The Problems page for the demo week: two problems to fix, six smaller and nine to check, the first one listing the two sessions it happened in with a Copy for Claude Code button.">
23
+ </picture>
24
+
25
+ **One problem up close** says what happened step by step, how each part is known, and what to add so it doesn't happen again.
26
+
27
+ <picture>
28
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/problem-focus-dark.png">
29
+ <img src="docs/images/problem-focus-light.png" alt="One problem opened: the six times it happened down the left, What happened for the selected one in four numbered steps (the failed run, nothing after it, the success claim, what the agent said), and below it a hook to copy into Claude Code.">
30
+ </picture>
31
+
32
+ **Sessions** lists your week newest day first. A run a program started says what started it and links to that step.
33
+
34
+ <picture>
35
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/sessions-dark.png">
36
+ <img src="docs/images/sessions-light.png" alt="Replay's sessions list for the demo week, Saturday first: each session with its time, length, tool, prompts and problems, and a review run marked as started by another session's step.">
37
+ </picture>
38
+
39
+ **Find** takes a pull request, a commit, a file, a branch or a few words and shows the sessions and goals behind it.
40
+
41
+ <picture>
42
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/find-dark.png">
43
+ <img src="docs/images/find-light.png" alt="Find, looking up the file src/parse.mjs: the six sessions that touched it, each with how that's known, and the two goals they worked toward.">
44
+ </picture>
45
+
46
+ **Goals** puts one goal's sessions on a single timeline you can play.
47
+
48
+ <picture>
49
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/goals-dark.png">
50
+ <img src="docs/images/goals-light.png" alt="Goals: the release goal's four sessions on one timeline, with a panel explaining why each session belongs to the goal.">
51
+ </picture>
52
+
53
+ **Setup** opens the first time you run `view` in a folder with no config: it lists the repositories it found nearby and asks what to keep private.
54
+
55
+ <picture>
56
+ <source media="(prefers-color-scheme: dark)" srcset="docs/images/setup-dark.png">
57
+ <img src="docs/images/setup-light.png" alt="Setup on first run: two git repositories found nearby, each with a role menu, then the email, the timezone, how far back to look, and the words to keep private.">
58
+ </picture>
59
+
60
+ **A weekly page** ([page mode](#standalone-site-page-mode)) is the summary you publish yourself, every change with its status and a git receipt. This one was built from the demo week.
61
+
62
+ <img src="docs/images/weekly-page.png" alt="A weekly page built from the demo week: commits per day, a one-line headline, and the week's changes, three shipped and one in progress.">
63
+
64
+ **A client report** ([client mode](#a-report-for-a-client-client-mode)) is a printable page of the work done for one client, its counts checked against git. This one was built from the demo week too.
65
+
66
+ <img src="docs/images/client-report.png" alt="A client report built from the demo week: the title, who it's for and by, the period, a headline, counts of merged pull requests and commits, and two highlights.">
67
+
68
+ </details>
69
+
70
+ honestweek works with the session logs that Claude Code and Codex already keep on your computer. It does three things with them, all on your own machine:
71
+
72
+ - **See where it went wrong.** `honestweek view` opens on a Problems page: the known ways AI coding agents go wrong that showed up in your sessions, claims the agent couldn't back first ("done" with no check after the last edit, or success the output doesn't show). Each one links to the step in your replay, says how it's known, shows whether it happened less than in the week before, and offers a fix you can copy into your own instructions or hooks.
73
+ - **Find and replay your work.** Its Find page, one click away, takes a pull request number, a commit, a file, a branch or a few words and shows the sessions behind it, then lets you replay any session step by step. Every link and count says how it's known: recorded in a log or by git, computed from records, inferred by a named rule, or missing.
74
+ - **Write an honest weekly summary.** A short pipeline turns a finished week into a summary you review and publish yourself. It checks every commit the summary cites against your real git history first, and it stops rather than write a claim it can't back.
75
+
76
+ It's for developers who do much of their work through an AI coding agent and want to find, check or show that work later. Nothing leaves your machine: there's no account, no telemetry and no network call, unless you turn on Include /insights and press Run /insights or Run with Codex, which send your sessions to Claude or OpenAI on your own plan. The names and client words you list stay hidden on the page unless you turn on its Show private text switch, on your own screen, and keys, tokens and passwords stay hidden either way.
77
+
78
+ To see it with nothing to set up, run `npx honestweek view --demo`: a made-up week opens in your browser.
79
+
80
+ ## Try it
81
+
82
+ You need Node 18 or later and git. honestweek is on npm, so `npx` runs it with no install step:
83
+
84
+ ```bash
85
+ npx honestweek view --demo # a made-up week in your browser; it sets nothing up
86
+ npx honestweek view # set up in your browser, then your own last 7 days
87
+ ```
88
+
89
+ The first time you run `view` in a folder with no `honestweek.config.json`, the page that opens is Setup. It shows the git repositories it found nearby, each with its role in plain words, and lets you add one by its folder path. It fills in your email from git and your timezone, asks which names and client or project words to keep private, and takes an optional goal list. It asks how far back to look (the last week unless you pick more), shows you the config it'll write, and when you press Save it writes it and goes straight on to your week's Problems page, without restarting anything. A week always loads whole: the newest day shows first, in seconds, with the header's dates saying "so far" and one short line saying what's still being read, and the rest arrives behind it. If the whole week won't fit in memory, it loads the newest days that do and says so. Later, the Settings page in the header changes how far back, the repositories and their roles, your emails, the private words and the goal list, the same way. For scripts and CI, `init` asks the same questions in a terminal (`init --yes` takes the defaults).
90
+
91
+ The demo opens a page with four parts: Find (type one of the examples it offers, or a few words), Goals (each goal in a goal list, a small JSON file of your goals, with its sessions on one timeline you can play), Replay (one session step by step, each step with the log line behind it), and Problems (known ways AI coding agents go wrong, and which of them showed up in the week), which is the page it opens on. Press Ctrl+C in the terminal to stop it.
92
+
93
+ If you'd rather have a plain `honestweek` command, install it with `npm install -g honestweek` and write `honestweek` where it says `npx honestweek`. From a clone of this repository, write `node bin/honestweek.mjs` there instead. To run unreleased code (what's on `main` and not in an npm version yet), write `npx github:BryceEWatson/honestweek`. `honestweek` with no command lists its first steps. The messages you meet first (that list, Setup, `init`, `view` and its pages) name each next step the way you ran honestweek.
94
+
95
+ Run `view` (or `init`) from your project folder, or from a new folder next to your projects. Either one lists the git repositories there and folds each extra working copy of one repository (a git worktree) into it, so one repository shows up once. Before it writes anything you can remove repositories or change a role (on the Setup page with a Remove button and a role menu; in `init` by number, `keep 1-5 9`, `drop 3 7-9` or `role 2 display`; the roles are explained under [Config reference](#config-reference)). It then asks for people's names and client or project words to keep private, and reads back what it'll store. When you give some, it also adds `honestweek.config.json` to `.gitignore`, since the file then lists them. You can skip both, but until you list some, names in your logs show as written, and `view` says so in the terminal and on every page, with an example of where to list them. For candidates, run `discover` and then `harvest`: it writes the capitalised words that survived redaction in last week's sessions, most frequent first, to `honestweek.harvest.json`.
96
+
97
+ What's further down:
98
+
99
+ - [Install](#install) as a Claude Code plugin, a plain skill, or the standalone command.
100
+ - [Finding and replaying your work in the browser](#finding-and-replaying-your-work-in-the-browser-view): every option of `view`, the goal list, and what it keeps private.
101
+ - [The flow](#the-flow-an-honest-weekly-summary): the weekly summary from `init` to `build`, then [mining solved problems](#mining-solved-problems-worth-publishing-mine), [a standalone site](#standalone-site-page-mode) and [a report for a client](#a-report-for-a-client-client-mode).
102
+ - [Config reference](#config-reference), [Sidecars](#sidecars) (the files it writes) and the [privacy model](#what-it-does-not-do--privacy-model).
103
+
104
+ ## Why
105
+
106
+ Your commits show what shipped. Your sessions show what you *figured out*: the dead ends you ruled out and the work that's designed but not yet proven. honestweek surfaces that honestly, with a receipt (a pointer to its source commit or session) on every line. Distilled work items also carry a status badge (`shipped` / `in progress` / `designed, not proven`); automatic session-derived digest items state why they surfaced without claiming work status.
107
+
108
+ ## Requirements
109
+
110
+ - **Node ≥ 18**
111
+ - The system **`git` CLI**, version 2.24 or later, on your `PATH`
112
+ - **Zero runtime dependencies**: Node built-ins plus `git` only
113
+ - Runs **entirely locally**. No telemetry, and honestweek itself makes no network call. The two optional buttons under Include /insights run your own `claude` or `codex`, which do send sessions to Claude or OpenAI, only when you press them. The optional `preview` and `view` servers bind to loopback (`127.0.0.1`) only.
114
+
115
+ ## Install
116
+
117
+ honestweek runs locally and has no dependencies to install. Pick whichever path you prefer. The plugin and the skill give you `/honestweek`, which runs the weekly summary inside Claude Code. For the browser page (`view`), use the standalone command.
118
+
119
+ ### As a Claude Code plugin (recommended for the weekly summary)
120
+
121
+ Add this repo as a plugin marketplace, then install from inside Claude Code:
122
+
123
+ ```
124
+ /plugin marketplace add BryceEWatson/honestweek
125
+ /plugin install honestweek@honestweek
126
+ ```
127
+
128
+ …or from your terminal:
129
+
130
+ ```bash
131
+ claude plugin marketplace add BryceEWatson/honestweek
132
+ claude plugin install honestweek@honestweek
133
+ ```
134
+
135
+ You get `/honestweek` inside Claude Code, with versioned updates via `/plugin marketplace update`.
136
+
137
+ ### As a plain skill
138
+
139
+ Clone into your personal skills directory:
140
+
141
+ ```bash
142
+ git clone https://github.com/BryceEWatson/honestweek ~/.claude/skills/honestweek
143
+ ```
144
+
145
+ Either way, when you run `/honestweek` the skill invokes its bundled CLI by a **skill-anchored absolute path** (`${CLAUDE_SKILL_DIR}/bin/honestweek.mjs`), so the commands work from *your own* project directory.
146
+
147
+ ### As a standalone CLI
148
+
149
+ Run it from npm with `npx`. No install, no clone (zero dependencies, so it's quick):
150
+
151
+ ```bash
152
+ npx honestweek --help
153
+ npx honestweek init
154
+ ```
155
+
156
+ Or install it as a `honestweek` command:
157
+
158
+ ```bash
159
+ npm install -g honestweek
160
+ honestweek --help
161
+ ```
162
+
163
+ Or from a clone of the repo:
164
+
165
+ ```bash
166
+ # run these from the repo root
167
+ node bin/honestweek.mjs --help
168
+ ```
169
+
170
+ To run unreleased code, meaning what's on `main` and not in an npm version yet, run it straight from GitHub:
171
+
172
+ ```bash
173
+ npx github:BryceEWatson/honestweek --help
174
+ npm install -g github:BryceEWatson/honestweek # or install that code as the honestweek command
175
+ ```
176
+
177
+ The CLI surface is eleven subcommands: `init`, `discover`, `prompts`, `digest`, `validate`, `build`, `harvest`, `preview`, `mine`, `history`, and `view`. Every one answers `--help` without touching your files. The `mine` command (`node bin/honestweek.mjs mine --help`) is the separate "solved problems worth publishing" pass described under [Mining solved problems](#mining-solved-problems-worth-publishing-mine). The `digest` command (`node bin/honestweek.mjs digest --help`) prepares one receipt-bearing review across prompts, ideas, techniques, decisions, reversals, and next steps for `page` or `site` output. The `prompts` command (`node bin/honestweek.mjs prompts --help`) remains the private prompt inbox and prompt-only compatibility path. The `harvest` command (`node bin/honestweek.mjs harvest`) proposes redaction-denylist candidates from the draft to a gitignored sidecar (only the count is printed; the raw nouns stay local for you to review). The `preview` command (`node bin/honestweek.mjs preview`) renders the built output as HTML and serves it on a local-only (`127.0.0.1`) server for you to read in your browser. The `view` command (`node bin/honestweek.mjs view --demo` to try it) opens a local page for finding and replaying the sessions behind your work, described under [Finding and replaying your work in the browser](#finding-and-replaying-your-work-in-the-browser-view).
178
+
179
+ ## Finding and replaying your work in the browser (`view`)
180
+
181
+ `honestweek view` opens a page on your own machine, starting on Problems, where you can see where your sessions went wrong, find the sessions and goals behind a pull request, a commit, a file, a branch or some words, see which sessions worked toward each goal, and replay any session step by step. It reads your config and the last 7 days of your Claude Code and Codex logs, serves the page on `127.0.0.1`, and opens your browser. Nothing is published, and nothing it reads is written to disk, apart from the redacted answers Run with Codex keeps beside your config when you use it.
182
+
183
+ ```bash
184
+ node bin/honestweek.mjs view # the last 7 days of your logs
185
+ node bin/honestweek.mjs view --days 30 # look further back
186
+ node bin/honestweek.mjs view --from 2024-06-10 --to 2024-06-16 --goals goals.json
187
+ node bin/honestweek.mjs view --demo # a made-up week, before you set anything up
188
+ ```
189
+
190
+ With no `honestweek.config.json` in the folder, it opens the Setup page instead, on the same local server with the same key, and the terminal says so in one line. Setup writes the config with the same code `init` uses, never over one that's already there, and then the page goes on to your week's Problems page. Your answers, private words included, go only to this local server, never into an address or the terminal. With `--config` naming a file that isn't there, it stops and says so. The commands it names, there and on the page, are written the way you ran honestweek, except that a page names a script or package file by a placeholder (`node <your honestweek folder>/bin/honestweek.mjs`), since its steps can happen in another folder. While it reads the logs, the page says what it's reading and for how long. When your config lists no private words, the terminal and every page say that names and client words show as written, and where to add them. Ctrl+C stops it.
191
+
192
+ What's on the page:
193
+
194
+ - *Find.* Type a pull request (`#67` or its address), a commit, a file or a branch, and it lists the sessions and goals behind it. Type words, and it lists the goals and sessions whose titles match, the branches that contain them, and the prompts that share the most words, each with a link to replay from that prompt. A line says what these lookups cover: your configured repositories, in the dates shown at the top of every page.
195
+ - *Search everywhere.* The same words, searched across the prompts of every session in those dates, including display-only repositories and folders outside your config. Each result says which of those three it comes from.
196
+ - *Goals.* Each goal in your goal list, with the sessions working toward it on one timeline you can play, pause and scrub. A citation in the goal list that no session backs is listed as missing, with the reason.
197
+ - *Replay.* Any session, step by step. Replay opens on a list of the week's sessions by day, a few per day with "Show more", to pick one from, and every replay links back to it. Each step opens a panel with what happened and who did it ("You", the main agent, or a named sub-agent; what a `codex exec` run was told is the agent's), the original log line checked against its fingerprint, a command's output, and how its time is known.
198
+ - *Problems.* The page `view` opens on. 42 known ways AI coding agents go wrong or waste time and tokens, and which of them showed up in your sessions. Claims the agent couldn't back come first. The main list holds only findings worked out from the log itself; ones that rest on a rule's guess or a missing record sit in their own open "Possible" section below it. Each problem shows its count against the window just before it (say "2 times · 4 before"), each count with how it's known, and opens to a fix you can copy (a hook or an instruction line, never applied for you), a suggested prompt that should trigger the problem so you can watch the fix catch it, and each finding linked to its step in the replay. The replay and goal timelines can mark the same findings. To see it on the made-up week, run `node bin/honestweek.mjs view --demo`. I list every source behind these problems, once each, in [docs/sources.md](docs/sources.md).
199
+ - *Include /insights.* An optional toggle under "What was checked" on Problems, off by default and saved as `"insights": true` in the config, that adds what Claude Code's own `/insights` command wrote about these sessions as a separate group labelled AI-written, never counted with honestweek's findings; a Run /insights button starts `claude -p /insights` on your machine after asking, since it uses your Claude plan and sends your sessions to Claude.
200
+ - *Facts and Run with Codex.* Replay and Problems have a closed "Facts" fold with the plain facts `/insights` keeps about a session, worked out from your logs for Claude Code and Codex alike, each saying how it's known or "not recorded". With Include /insights on, "Run with Codex" has your own `codex` write the AI-written half for your Codex sessions, kept beside your config and shown as its own group. It asks first, since it uses your Codex plan and sends your Codex sessions to OpenAI, and Codex can read files you can read while it judges.
201
+ - *Light or dark.* A switch in every page's header, remembered in this browser only. With no choice made, the pages follow your system setting.
202
+ - *One evidence key.* Every link, count and step says how it's known: **recorded** (a log line or git says so), **derived** (computed from recorded facts), **inferred** (a named rule's best reading, and the rule is named), **missing** (the log doesn't say), or **ambiguous** (the records fit more than one way). A goal you assigned a session to yourself, by citing it in your goal list, is labelled as yours.
203
+
204
+ Options: `--days <n>`, or `--from` with `--to`, picks the dates; `--timezone <zone>` reads them in another timezone; `--goals <file>` names your goal list; `--config <file>` reads another config; `--port <n>` picks the port (a free one otherwise); `--no-open` only prints the address; `--self-test` adds a page that clicks through every page in your browser and reports each step as pass, fail or skip, and prints that page's address too; a step's note can quote what the page showed, so read it before you share it. `--demo` uses only its own made-up logs, config, goal list and week, so it refuses `--config`, `--goals`, `--days`, `--from`, `--to` and `--timezone`.
205
+
206
+ ### The goal list
207
+
208
+ A goal list is a JSON file of your goals and the changes made to them. Each goal has an `id` and a `title`, and can carry a `state` and notes (`source`, `observations`, `results`, `decisions`) that cite pull requests, commits, or sessions (`session:` followed by the session's id). `events` logs each change to the list, with the time it was accepted:
209
+
210
+ ```json
211
+ {
212
+ "goals": [{ "id": "g-widget", "title": "Ship the widget parser", "state": "active",
213
+ "source": { "pr": "https://github.com/example/your-project/pull/7" } }],
214
+ "events": [{ "eventId": "ev-0001", "goalId": "g-widget", "type": "goal.create", "at": "2024-06-11T21:41:30Z" }]
215
+ }
216
+ ```
217
+
218
+ Name it with `--goals <file>`, or once with `goalsFile` in the config. It's a different file from the goals page's `honestweek.objectives.json` that `build` reads, and passing that one by mistake gets a message saying so. Without a goal list, search and replay still work. [docs/work-history-engine.md](docs/work-history-engine.md#goal-membership) explains how a session joins a goal and how each join is known.
219
+
220
+ ### What `view` keeps private
221
+
222
+ - *It answers only your own page.* The server binds to `127.0.0.1`, refuses a request that names another host and any data request that comes from another website (its page files hold no data), and answers a data request only with this run's key. The key is made fresh each run and never sits in an address or a command line: the address it opens or prints carries a one-time code that the page trades for the key. Each code works once and only for a while: 15 minutes for a printed address, two for the one it opens your browser with, so an old address in your terminal's scrollback won't open the page. Pressing Enter in the terminal prints a fresh one.
223
+ - *The two run buttons.* The server, not just the page, refuses Run /insights and Run with Codex while Include /insights is off. Each program gets only the environment variables it needs to start and sign in, so other tools' tokens in your environment don't reach it.
224
+ - *Redacted unless you ask.* The page shows redacted text. Its **Show private text** switch shows names, client words and folders on your own screen; keys, tokens and passwords stay hidden either way. The switch starts off every run and changes only text, never which sessions link to which or which goals they join. That version is built in memory the first time you turn it on, and it's never written to disk.
225
+ - *Display-only and outside sessions.* With the switch off, a session from a display-only repository or a folder outside your config never shows a private word, and it never joins a lookup or a goal. Git is never run against a display-only repository.
226
+ - *Nothing on disk.* The page's address holds only made-up ids, never what you typed or a goal's name, because the browser keeps addresses in its history. What it reads stays in memory. What it writes is the config (when you save Setup or Settings, or flip Include /insights), the example config beside it when it's missing, `.gitignore` lines for honestweek's private files, Run with Codex's redacted answers in `honestweek.codex-judgments/`, and a small redirect file in your temporary folder that opens the browser and is deleted once it's used, after two minutes, or when you stop. `--demo` builds its made-up week in a temporary folder and deletes it when you stop. When it starts, it also removes its own leftover demo folders older than a day whose run has stopped.
227
+
228
+ ## Replaying how the work happened (the engine underneath)
229
+
230
+ The weekly summary below says what landed. The work-history engine in `lib/replay/` rebuilds how it got there from the same local logs: prompts, the sub-agents an agent started, each command and its recorded result, tests, interruptions, what git says happened to each commit, and which pull requests a default-branch commit names. You can replay it to any moment and drill from a week down to the log line behind a step, and every step says whether a record shows it, it was computed from records, a named rule inferred it, or the evidence is missing. It never invents working time or reasons. It doesn't change any existing output, and `honestweek view` (above) is its page. A developer tool also prints each level, from a clone of this repository (the tool isn't in the published package):
231
+
232
+ ```bash
233
+ node tools/replay-inspect.mjs --config honestweek.config.json --from 2024-06-10 --to 2024-06-16 walk
234
+ ```
235
+
236
+ [docs/work-history-engine.md](docs/work-history-engine.md) has the event model, the measured source coverage, and what it can't reconstruct yet.
237
+
238
+ ### Finding the sessions behind a pull request, a commit, a file, or a goal (in development)
239
+
240
+ The same engine reads the history backwards too, through two more commands in that developer tool:
241
+
242
+ - `lookup` takes a pull request (`#64`, `your-repo#64`, or its link), a commit id, a file path, or a branch name, and lists the sessions whose records point at it, strongest evidence first. Each pointer says how it's known: a record shows it, or a named rule read it (for example, a `gh pr view 64` command). A file path is tried under each checkout of a repository, the configured folder and its worktrees, but never under a session's own working folder. An absolute path searches only the repository that holds it; a relative one searches each configured repository and lists the results per repository.
243
+ - `goals` takes a goal record: a JSON list of goals plus the log of changes made to it (a separate input from the goals page's registry above). For each goal it lists the sessions that did its work and every reason each one counts: the record cites the session or one of its pull requests or commits, a tool call wrote one of the goal's entries while the record accepted it, a command acted on a cited pull request, or a prompt named the goal. Whatever the record cites that no session matches is listed with the reason.
244
+
245
+ You can try both without any logs of your own. `--demo` runs them on the made-up sessions, git repository, and goal record the tests use, built in a temporary folder that's deleted afterwards:
246
+
247
+ ```bash
248
+ node tools/replay-inspect.mjs --demo goals
249
+ node tools/replay-inspect.mjs --demo lookup '#7'
250
+ node tools/replay-inspect.mjs --config honestweek.config.json --from 2024-06-10 --to 2024-06-16 --goals goals.json goals
251
+ ```
252
+
253
+ Both only read. Nothing is published, sessions outside your configured repos and in display-role ones are never searched, and display-role repos are never read by git. For a page on your own machine, the engine can also build a history that shows your private text (names, folders, addresses, ids) while keeping secrets hidden. It's built in memory and meant for your screen only: `honestweek view` asks for it only when you turn on Show private text, and the engine refuses to turn the whole history into JSON. The join types, their rules, and what lookup can't find are in [docs/work-history-engine.md](docs/work-history-engine.md#goals-and-lookup-reading-the-history-backwards).
254
+
255
+ ## The flow: an honest weekly summary
256
+
257
+ This turns a completed week of your AI coding **sessions** (each one conversation log) into an honest, git-verified, private-by-default work summary, including the figured-out-but-not-yet-shipped work your commits can't show.
258
+
259
+ It's shipped as a Claude Code skill (instructions Claude follows when you type `/honestweek`) that runs small Node scripts with no dependencies, all on your machine. It reads your AI coding session transcripts, distils a completed week into an honest shareable summary, **re-derives every git-checkable claim against your real commits (or aborts)**, and produces a draft *you* review and publish yourself. It never auto-publishes.
260
+
261
+ End-to-end happy path, in order. Each step names the artifact it produces.
262
+
263
+ > Installed as the skill/plugin? Just run `/honestweek`: Claude drives these steps for you and resolves the CLI path automatically. The raw `node bin/honestweek.mjs …` commands below are for running the CLI directly **from a clone of the repo** (cwd = the repo root).
264
+
265
+ 1. **`init`** → writes `honestweek.config.json`, inferred from your git state (your `git config user.email` plus the nearby git repos it finds), for you to review. If it finds no repositories, it writes nothing and says where to run it instead. It also drops `honestweek.config.example.json` if one isn't present. Two confirmations gate the write; accepting the defaults yields a valid config. Between them it asks for the names and client words to keep private, which go under `redaction` (either can be skipped; when you give some, the config also goes into `.gitignore`), and before the second it shows a short summary of what the file will say.
266
+ ```bash
267
+ node bin/honestweek.mjs init
268
+ ```
269
+ Those questions need someone to answer them. Answers piped in on stdin work, one per line. In a script, in CI, or from an agent's shell where stdin ends before the last answer, `init` exits `2` rather than writing a config you never approved, and tells you to accept the inferred defaults instead:
270
+ ```bash
271
+ node bin/honestweek.mjs init --yes
272
+ ```
273
+ `--yes` leaves an existing `honestweek.config.json` untouched; add `--force` to overwrite it.
274
+ 2. **`discover`** → scans the **last completed week's** sessions **and session-end handoffs** (`.claude/handoffs/*.md`, for `featured`/`reference` repos; `display` repos are never read) from your allowlisted repos and writes the gitignored, **redacted** `honestweek.draft.json`. Handoffs contribute their tagged claims, reversals, and cited commits as additional, bounded material. Deterministic: no model call.
275
+ ```bash
276
+ node bin/honestweek.mjs discover # or: discover --week 2024-W23
277
+ ```
278
+ 3. **`/honestweek`** (the skill) → **distils** the draft into the human-reviewable `honestweek.items.json`, with a status badge **and** a receipt on every item. This is the one model-judgment step; see [`SKILL.md`](SKILL.md) for the distillation contract.
279
+ For `page` or `site` output without the opt-in goals registry, run `node bin/honestweek.mjs digest prepare`. It scans the completed week from Claude Code and Codex, updates the gitignored private prompt inbox and balanced review model, and writes the public-safe `honestweek.prompt-items.json` lane. Use `digest candidates` and `digest explain <item-ref>` to inspect the exact score, selection reason, privacy result, and transcript receipts. Use `digest keep`, `hide`, `delete <item-ref> --yes`, or confirmed `delete --all --yes` to control current items in any category, then run `validate` and `build`. Keep changes selection only and never bypasses receipt or privacy gates. If the redactor would still change an item's redacted text on a second pass, that one item is held back as `high-risk`, its text is replaced by a single placeholder in the private files, and the rest of the week still builds. Delete removes private review text and leaves a no-text tombstone so preparation cannot regenerate the item; it cannot recall an output you've already built. `digest reset-tombstones <item-ref>|--week <YYYY-Www>|--all --yes` is the explicit regeneration control. The balanced digest lane and the goals page are not yet compatible; use the existing distillation path when the goals registry is present.
280
+
281
+ Selected next steps and cues labelled `unresolved idea: <subject>` carry automatically for at most the next two reporting weeks. They must still pass the current privacy gate, automatic floor, target, and category cap. `digest carry-forward <item-ref>` schedules one current public-safe candidate for exactly the next digest and does not extend automatic carry. A human turn labelled `picked up: <subject>` or `ruled out: <subject>` retires one unambiguous matching carry. Every carried or renewed item discloses why it appeared and its first-seen and current week. Carry history is private, redacted, and limited to 12 week records.
282
+
283
+ A lifecycle build binds the exact configured output bytes and next carry state with hashes. If an interrupted build leaves `honestweek.carry.pending.json`, the next `prepare`, `validate`, or `build` recovers only a recognized hash combination. Use `digest recover --discard-pending` only when the output differs and carry is still at its prior hash. Unknown states fail closed. Use `prompts list`, `source`, `keep`, `hide`, and `delete` when you want the prompt inbox controls directly. Automatic selection discloses its floor, overall target, category caps, omitted counts, and uncertainty. Privacy edits are deterministic redactions; ambiguous or residual high-risk material stays private. `prompts curate` remains available when you intentionally want the prompt-only lane.
284
+ > Optional but recommended: gate the distilled items before building:
285
+ > ```bash
286
+ > node bin/honestweek.mjs validate # add --no-dashes for the voice rule
287
+ > ```
288
+ > `validate` exits `2` if any item lacks a valid badge or a receipt, **names a `display`-role repo or cites a commit against one**, or lets a configured redaction term survive into the prose. It catches an authoring leak at the source instead of relying on build-time scrubbing.
289
+ 4. **`build`** → re-derives and **git-verifies every cited commit**. It **aborts with exit code `2`** if any cited commit is unresolved or its `authorEmail` is not in `identity.authorEmails`, writing nothing rather than emit a half-true summary. A `shipped` badge additionally requires every cited commit to have **landed**: reachable from the repo's default branch (origin/HEAD as recorded locally, else `main`/`master`, else the repo's only branch), checked offline from local refs, never a fetch. Real work still on an unmerged branch keeps its receipt and is downgraded to `in progress`, announced on stderr; if the repo has no determinable default branch, the `shipped` claim is unverifiable and the build aborts (exit `2`).
290
+ ```bash
291
+ node bin/honestweek.mjs build
292
+ ```
293
+ 5. **emit** → on success, `build` renders the final **local** output in the configured `output.mode` (`post` / `changelog` / `digest` / `report` / `page` / `site`) to `output.file`. The `digest` carries a git-derived **Activity** summary (commits and active days for `featured`/`reference` repos; `display` repos are never git-read, so they get no metrics, and an unreadable repo gets no fabricated `0`). `page` renders a self-contained, interactive HTML **standalone site** (see below). You review it and publish it yourself.
294
+ 6. **`preview`** (optional) → serves the built `output.file` on a local-only `127.0.0.1` server, then opens your browser. A Markdown output is converted to a locked-down HTML page; the `page` output is already HTML and is served verbatim (with its inline interactivity). It is a viewer: it reads the file `build` wrote, publishes nothing, and needs no internet. Press Ctrl+C to stop.
295
+ ```bash
296
+ node bin/honestweek.mjs preview # add --no-open to just print the URL, or --port <n>
297
+ ```
298
+
299
+ ## Mining solved problems worth publishing (`mine`)
300
+
301
+ The weekly flow above answers "what did I ship". `mine` answers a different question:
302
+ **did I solve a problem that a stranger is going to hit too?**
303
+
304
+ Not every hard hour is worth writing up. When your own code breaks and you fix your own
305
+ code, nobody else can use that. But when a tool *you did not write* fails in your
306
+ environment and you work out why, someone else will hit the same wall and paste the same
307
+ error into a search box. That second kind is rare, it is already sitting in your session
308
+ logs, and it is almost never written down.
309
+
310
+ `mine` finds those, ranks them, and, with `--draft`, writes one up.
311
+
312
+ ```bash
313
+ node bin/honestweek.mjs mine # report what is undecided
314
+ node bin/honestweek.mjs mine --draft # and write the top one up as a post
315
+ ```
316
+
317
+ **What it reads.** Claude Code (`~/.claude/projects`), Codex (`~/.codex/sessions`) and
318
+ Cowork session logs. Pick with `--corpus claude-code,codex,cowork`. A name outside that
319
+ list is an error (exit 1), not an empty scan: a typo must never read as a quiet week.
320
+
321
+ **How it decides.** A session is a candidate only when all three hold:
322
+
323
+ | Requirement | Why |
324
+ | --- | --- |
325
+ | A quotable error from software you did not write | It is what a stranger types into a search box. Errors from your own compiler, test runner or git are excluded. |
326
+ | Diagnosis outside your working tree | Probing the machine, reading another program's install directory, or researching a third party's known behaviour. |
327
+ | Evidence it was resolved | An unresolved failure is a bug report, not a guide. |
328
+
329
+ A session that edited your repo far more than it investigated anything else is rejected
330
+ however good it looks otherwise. That is ordinary work.
331
+
332
+ **The ledger.** Findings land in `honestweek.findings.json` with a status. The number
333
+ that matters is the **backlog**: findings you have not yet accepted or declined:
334
+
335
+ ```text
336
+ ERROR SIGNAL — backlog 3 undecided; oldest waiting 12 day(s).
337
+ ```
338
+
339
+ "Found 3 things this run" measures the tool. The backlog measures whether anything
340
+ reached a reader, and it can only fall when **you** decide:
341
+
342
+ ```bash
343
+ node bin/honestweek.mjs mine --decide "<finding key>=published" # or =declined
344
+ ```
345
+
346
+ **Drafts are honest by construction.** A draft asserts nothing about today. Its
347
+ last-verified field is emitted **empty**, its publication date is left blank, and it
348
+ carries a checklist where every item starts `UNVERIFIED`, plus a "What I could not
349
+ check" section. Two things a session log can never establish are always listed there:
350
+ whether anyone actually searches for this, and whether the fix still works on the
351
+ current build. `mine` never publishes anything.
352
+
353
+ **When it is blind, it says so.** Every run reports files found per corpus and the
354
+ retention floor: the oldest session still on disk, since agents delete old logs. If a
355
+ corpus resolves to a real directory holding zero logs, `mine` **exits `2`**: a zero from
356
+ a blind sensor is not evidence of a quiet week.
357
+
358
+ Configure the destination under `mine` in your config (all optional):
359
+
360
+ ```json
361
+ {
362
+ "mine": {
363
+ "ledger": "honestweek.findings.json",
364
+ "ownRepos": ["you/your-repo"],
365
+ "publishedErrorStrings": ["an error you already wrote about"],
366
+ "draft": {
367
+ "dir": "src/content/blog",
368
+ "frontmatter": { "title": "", "description": "", "date": "", "tags": [], "lastVerified": "" }
369
+ }
370
+ }
371
+ }
372
+ ```
373
+
374
+ `draft.frontmatter` is your destination's schema, not honestweek's: keys it recognises
375
+ are filled in, keys it does not are passed through empty for you. `ownRepos` stops
376
+ issues on your own repositories counting as evidence that someone else's software broke.
377
+ honestweek reads the GitHub remote of each configured repository for this, except `display`
378
+ repositories, which it never runs `git` against: list their `owner/name` under `ownRepos` if
379
+ issues there should count as yours.
380
+
381
+ See [`docs/mining.md`](docs/mining.md) for the detector's signals, what is measured
382
+ versus guessed at, and how the score bar was calibrated.
383
+
384
+ ## Sample output
385
+
386
+ A short, fabricated (clean-room) example. The distilled `honestweek.items.json`:
387
+
388
+ ```jsonc
389
+ {
390
+ "week": { "start": "2024-06-10", "end": "2024-06-16" },
391
+ "items": [
392
+ {
393
+ "text": "Auth redirect now keeps the session cookie across the login bounce.",
394
+ "repo": "your-project",
395
+ "status": "shipped",
396
+ "receipt": { "sessionId": "a1b2c3d4", "primaryCommit": "9f8e7d6" }
397
+ },
398
+ {
399
+ "text": "Retry queue for failed webhook deliveries, designed but not yet wired in.",
400
+ "repo": "your-project",
401
+ "status": "designed, not proven",
402
+ "receipt": { "sessionId": "a1b2c3d4" }
403
+ }
404
+ ]
405
+ }
406
+ ```
407
+
408
+ Rendered to the default `digest` output. Every line carries a status badge and a receipt:
409
+
410
+ ```markdown
411
+ # Weekly digest — 2024-06-10 to 2024-06-16
412
+
413
+ ## Shipped
414
+ - **shipped** — Auth redirect now keeps the session cookie across the login bounce. _(your-project)_ (`9f8e7d6`)
415
+
416
+ ## Designed, not proven
417
+ - **designed, not proven** — Retry queue for failed webhook deliveries, designed but not yet wired in. _(your-project)_ (`a1b2c3d4`)
418
+ ```
419
+
420
+ ## Standalone site (`page` mode)
421
+
422
+ Set `"output": { "mode": "page" }` and `build` writes one self-contained, interactive
423
+ HTML file (`honestweek.report.html` by default), a polished **standalone site** with a
424
+ git-derived commits/day chart, collapsible per-project cards with metrics, status-badged
425
+ items, and an expandable git receipt on each. No target project, no framework, no build
426
+ step, and **zero external resources** (inline CSS + JS, system fonts), so it opens
427
+ anywhere and `preview` can serve it under a no-egress CSP:
428
+
429
+ ```bash
430
+ node bin/honestweek.mjs build # writes honestweek.report.html
431
+ node bin/honestweek.mjs preview # serves it on 127.0.0.1 + opens your browser
432
+ ```
433
+
434
+ Same honesty engine as every other mode: every cited commit is verify-or-abort'd, every
435
+ number on the page is a deterministic honestweek derivation (git for commits + the chart),
436
+ and curated prose is HTML-escaped. A per-project card's **active-days** is
437
+ `max(commit-active days, session-active days, entry-active days)`, so a display-role /
438
+ session-only project shows the days it genuinely had interactive sessions (counted from your
439
+ local session logs, never authored) instead of a blank. A card's header can never report fewer
440
+ active days than the dated rows shown beneath it, even when a session ran from one project's
441
+ directory but was curated as another's work by content. In `site` mode the same reconciliation
442
+ keeps the header's "sessions this week" from falling below that active-day span (a session
443
+ happens on one day, so N active days mean at least N sessions); for a cross-cwd generalized
444
+ project that reconciled figure is a lower bound on its distinct session-days, not a raw
445
+ session-log tally. Every figure is a deterministic count, never authored. (To
446
+ instead generate INTO an existing website's data
447
+ file (the integrated path), use `site` mode with a committed `output.adapter`; see
448
+ `docs/site-integration.md`.)
449
+
450
+ ### A goals page too (opt-in, multi-page)
451
+
452
+ Drop a `honestweek.objectives.json` registry beside your config and `page` mode becomes
453
+ **multi-page**: it emits a second self-contained page, `goals.html`, next to `report.html`
454
+ and cross-links the two. The goals page groups your verified work **by goal** instead of by
455
+ project: goal cards with a kind chip, a what / why / how, a per-week activity strip, status
456
+ counts, and an expandable list of the entries behind each goal. With **no** registry, `page`
457
+ mode stays single-page exactly as above (the goals page is purely additive).
458
+
459
+ The registry is the publish gate: only goals listed in it appear, and a work item that maps
460
+ to no goal is omitted. It's validated fail-closed before anything is written (an invalid or
461
+ leaky registry aborts the whole build, writing neither page).
462
+
463
+ ```jsonc
464
+ // honestweek.objectives.json (opt-in; absent -> single-page)
465
+ {
466
+ "schemaVersion": 1,
467
+ "groups": ["open source", "this site"], // area sections, in this order
468
+ "groupDescriptions": { // optional per-area what/why intro
469
+ "open source": { "teaser": "Tooling, in the open.", "what": "...", "why": "..." }
470
+ },
471
+ "objectives": {
472
+ "ship-the-tool": { // any anchor-safe id
473
+ "publicLabel": "Ship the tool as an open engine",
474
+ "publicGroup": "open source", // must be one of groups
475
+ "kind": "continuous", // optional: "continuous" | "finite"
476
+ "what": "...", "why": "...", "how": "...", // optional card body
477
+ "howType": "sessions" // optional: "sessions" | "mined" | "planned"
478
+ }
479
+ },
480
+ "projectToObjective": { "your-project": "ship-the-tool" }, // repo label -> goal id
481
+ "page": { "title": "My goals", "lede": "..." } // optional page copy overrides
482
+ }
483
+ ```
484
+
485
+ A work item resolves to a goal by its own `objectiveId` (if set and in the registry), else by
486
+ `projectToObjective[<its repo label>]`. Cross-week goal activity aggregates the current week
487
+ plus any weeks in your local `output.archive` (so a first run shows one week, richer as weeks
488
+ accrue). An optional `honestweek.goal-changelog.json` adds a "what changed" band for
489
+ structural goal-set changes (a goal added / split / retired / relabeled / merged).
490
+
491
+ `preview` serves **both** pages (so the cross-links resolve), still loopback-only under the
492
+ same no-external-egress CSP:
493
+
494
+ ```bash
495
+ node bin/honestweek.mjs build # writes report.html + goals.html (when the registry is present)
496
+ node bin/honestweek.mjs preview # serves both at 127.0.0.1 (/ and /goals.html)
497
+ ```
498
+
499
+ ## A report for a client (`client` mode)
500
+
501
+ A weekly log is for you. A client report is for the person paying for the work: what you did for them over a period you choose (a sprint, a month, the contract so far), in their words, with the evidence attached. It's one light, printable HTML file (`honestweek.client.html` by default) they can read in a browser or save as a PDF.
502
+
503
+ It keeps every guarantee the weekly modes have. Every change in it names the pull requests it came from, every cited commit is verify-or-abort'd and has to be yours and on the default branch to count as merged, and a cited commit dated outside the period aborts the build. The numbers at the top (pull requests merged, commits on the main branch, days with work landed) and the activity chart are read from git, and an unreadable repo leaves them blank rather than too low. An appendix lists every pull request of yours that landed in the period, marking which ones the report describes, so nothing is quietly left out.
504
+
505
+ The source is what reached the default branch, not a week of session logs:
506
+
507
+ 1. Add a `client` block to the config (it names the client, and optionally who it's for and from, plus link prefixes so PR numbers become links), and set `"output": { "mode": "client" }`. Use a separate folder and config for each client.
508
+ 2. List what landed in the period. This writes the gitignored `honestweek.history.json` and prints only counts:
509
+ ```bash
510
+ node bin/honestweek.mjs history --from 2026-04-01 --to 2026-06-30
511
+ ```
512
+ 3. Distil it into `honestweek.items.json` (the skill does this): a `period` with the same dates, `content` (a `title`, a one-sentence `headline`, `summary` paragraphs, the `themes` the work falls into, and optional `next` steps, which are shown as planned and never counted), and one item per meaningful change with a `theme`, a `title` and `summary` written for the client, a status, and `commits` citing the squash-merge commits it came from. Mark the few that matter most with `"highlight": true`.
513
+ 4. `validate`, `build`, and `preview` as usual. Put anything the client must never see (billing, other clients) in `redaction.terms` so `validate` stops it at the source.
514
+
515
+ In a client report, `shipped` reads as **Merged**: on the main branch and checked against git. It doesn't claim the change has been released to production, and the report says so.
516
+
517
+ ### Shaping it for the reader (reader profiles)
518
+
519
+ Different readers want different things from the same report. An optional `honestweek.reader.json` beside the config describes the one this report is for: which sections come first, extra sections that gather the changes they care about, areas to leave out, and whether to also write a short note for wherever they read updates. It never changes a fact: every view shows the same entries, statuses and counts, an area it leaves out is counted on the page, and the full record and "how this report was made" are always there.
520
+
521
+ - An extra section picks its changes either **by git**, from the issue numbers the commits' messages name (`"select": { "issues": [12, 14] }`), or **by hand**, from tags on items (`"select": { "tags": ["requested"] }`). The page says which.
522
+ - Every section and every line of writing guidance says where it came from: `their-words`, `your-notes` (both with a `ref`), or `guess`. If everything in the file is a guess, `build` tells you the view is unconfirmed.
523
+ - `"format": { "note": true }` also writes `<report>.note.md`: the headline, the reader's sections and what's next, in a few lines, pointing to the full report.
524
+ - Anything a profile can't honestly do fails the build instead: redefining "done", unknown keys, a missing source, excluding an area that doesn't exist, an item tag no section picks.
525
+
526
+ Without the file, the report uses the shipped default and client layers. The design and its rules are in [docs/reader-profiles.md](docs/reader-profiles.md).
527
+
528
+ ## Config reference
529
+
530
+ Your `honestweek.config.json` mirrors `honestweek.config.example.json`. Whether you commit it is up to you, but its `redaction` lists are the words you want hidden, so keep a config that has them out of anything public (`init` adds it to `.gitignore` when you give it private words):
531
+
532
+ ```jsonc
533
+ {
534
+ "identity": { "authorEmails": ["you@example.com"] }, // required, non-empty; the commit-authorship allowlist
535
+ "week": { "startsOn": "monday", "timezone": "UTC" }, // optional; startsOn is "monday" for v0.1; timezone is an IANA zone (defaults to the host zone)
536
+ "repos": [ // required, non-empty
537
+ { "path": "/path/to/your/repo", "label": "your-project", "role": "featured" },
538
+ { "path": "~/code/a-repo-you-contribute-to", "label": "a-shared-repo", "role": "reference" },
539
+ { "path": "~/code/a-client-repo", "label": "a-private-project", "role": "display" }
540
+ ],
541
+ "redaction": { "codenames": [], "names": [], "terms": [] }, // optional; default-empty private term-lists, scrubbed case-insensitively
542
+ "curation": { "maxItems": 12, "automaticMinScore": 2, "retentionWeeks": 12, "automaticCarryWeeks": 2, "categoryCaps": { "prompts": 2, "ideas": 2, "techniques": 3, "decisions": 2, "reversals": 1, "nextSteps": 2 } }, // disclosed digest target, floor, bounded carry, and category caps
543
+ "privacy": { "publicRenditions": { "enabled": true, "maxAutomaticChangedPercent": 20, "generalizationMappings": {}, "neverPublicTerms": [] } }, // deterministic public-rendition gate
544
+ "output": { "mode": "digest", "file": "honestweek.digest.md" }, // optional; mode ∈ post|changelog|digest|report|page|site|client, default digest
545
+ "client": { "name": "your-client", "preparedFor": "Their name", "preparedBy": "Your name", "organization": "Your business", "prLinks": { "your-project": "https://github.com/your-org/your-project/pull/" } }, // required for mode client only
546
+ "voice": { "denyMeta": false }, // optional; OFF by default. true = lint authored prose for withholding/honesty-meta (see below)
547
+ "goalsFile": "honestweek.goals.json" // optional; the goal list `view` reads
548
+ }
549
+ ```
550
+
551
+ | Field | Meaning |
552
+ | --- | --- |
553
+ | `identity.authorEmails` | The emails a commit must be authored by to count as yours. `build` aborts on any cited commit not authored by one of these. |
554
+ | `week.startsOn` | `"monday"` (the only supported value in v0.1). |
555
+ | `week.timezone` | IANA timezone used to compute the week boundary; defaults to your host zone. |
556
+ | `repos[].path` | A repo path. `~`/`~/` expands to your home dir; relative paths resolve against the config file. Sessions are attributed to this repo from **any working tree of the same git repository**: the path itself, sub-directories, and every `git worktree`, including ones checked out at a sibling path rather than inside it. Git reads (commits, handoffs, metrics) always use this path alone, so a worktree's branch or detached `HEAD` never becomes the basis for your commit counts. A separate *clone* has its own git database and is never attributed here. |
557
+ | `repos[].label` | The short name items reference and outputs display. |
558
+ | `repos[].role` | One of the three trust levels below. |
559
+ | `redaction.codenames` / `names` / `terms` | Private tokens scrubbed from all output, in any letter case. A term is found as a word, after an underscore or a digit, or as one part of a camel-case name (`acme_report`, `AcmeReport`, `XMLAcmeThing`). A web-address or file-name part that starts with a codename or term of four or more letters is replaced whole (`www.acmehq.com`, `http://acmehq:3000`, `acmereport.pdf`); a person's name is matched that way only in a web address, so "Bill" leaves `billing.ts` alone. A word that only shares letters with a term (`academy`) is kept. Default empty (clean-room). |
560
+ | `curation.*` | Local weekly-selection policy. Defaults target 12 items with caps of 2 prompts, 2 ideas, 3 techniques, 2 decisions, 1 reversal, and 2 next steps. The automatic floor is 2. `automaticCarryWeeks` defaults to 2 and is hard-limited to 2. `retentionWeeks` defaults to 12 and is hard-limited to 12. Explicit keeps and one-week renewals are never silently dropped, but they never bypass receipt or privacy gates. |
561
+ | `privacy.publicRenditions.*` | Public-rendition gate. `enabled` defaults true for the local artifact, `maxAutomaticChangedPercent` defaults to and cannot exceed 20, and `neverPublicTerms` extends hard redaction. `generalizationMappings` remains empty in this slice. Ambiguous or residual high-risk material in every category stays private. |
562
+ | `output.mode` | `post` (build-in-public update), `changelog` (in-repo `CHANGELOG.md` section), `digest` (the private, local-only weekly file; the default and trust anchor), `report` (grouped by project, each headed by its git-derived metrics; the structured weekly-work-log shape, still a local file you publish yourself), `site` (integrate the verified report into a target website's data artifact via a committed adapter (advanced; see [docs/site-integration.md](docs/site-integration.md))), or `client` (a printable report of the work done for one client over the items file's `period`; see [A report for a client](#a-report-for-a-client-client-mode)). |
563
+ | `output.file` | Where the output is written. Defaults per mode when unset. (Not used by `site`, whose write path comes from the adapter.) |
564
+ | `output.adapter` | **Required for `site` mode only**: path to the committed adapter (resolved like a repo path): a `.json` *static* field-map, or a `.mjs` *transform* (`transform(model, ctx)`) for artifacts needing grouping/sorting/joins. It maps the verified model onto the site's data artifact; the artifact's own write path lives in the adapter. |
565
+ | `output.redact` | Default `true` (honestweek scrubs every byte). For `site` mode only, `false` delegates string redaction to the committed transform (so a target with its own redactor gets exact placeholder parity), permitted **only with a transform adapter**; verify-or-abort and the numeric fact-fence always run. See [docs/site-integration.md](docs/site-integration.md). |
566
+ | `output.skipProgramSessions` | Default `true`. For `page` and `site` modes, the interactive-session count leaves out a Claude Code session that a program, a background task or another session opened and that has no turn from you, and counts one you sent a turn to later from your first turn, on that turn's day, the way the rest of honestweek reads a program's turns. Current Claude Code marks who sent each turn (`turnOrigin`: `human` when it came from your own session, typed or pasted); older logs don't, and count as before. Set it to `false` to count the old way. If you publish this count, it changes from 0.2.0 wherever your logs record `turnOrigin`. See [docs/site-integration.md](docs/site-integration.md). |
567
+ | `output.archive` / `output.archiveDir` | Opt-in local weekly archive. With `archive: true`, `build` also snapshots each week to `<archiveDir>/<weekStart>.json` and maintains `<archiveDir>/index.json` (the "/log" series; default dir `honestweek.archive`). Local files only, never pushed. |
568
+ | `client.name` | **Required for `client` mode.** The client or product the report covers. |
569
+ | `client.preparedFor` / `preparedBy` / `organization` | Optional lines for the report's header: who it's for, who wrote it, and the business it comes from. |
570
+ | `client.prLinks` | Optional map of repo label to an https prefix (`https://github.com/your-org/your-project/pull/`), so a PR number derived from a verified commit becomes a link. Every key must be a configured repo label. |
571
+ | `voice.denyMeta` | Opt-in authored-prose honesty lint, **OFF by default**. When `true`, `build` aborts (exit 2, writes nothing) if an authored-prose field (item `title`/`summary`/`text`, or curated `content`/`projects` prose) *narrates its own withholding* ("keeping the specifics sealed", "kept generic here", "not public-facing") or *announces the page's own honesty* ("show the work honestly, receipts and retractions included", "belongs in an honest log"). That's what an honest log should show through its badges and receipts, not say about itself. It's the prose analogue of the numeric fact-fence, names each offending field plus matched phrase plus rule, and is **never** applied to verified evidence snippets/receipts (where a word like "sealed" can legitimately appear); conversely, keep authored prose out of evidence-named keys (`commits`, `receipt`, `snippet`, ...), which are treated as evidence and skipped. Absent, nothing changes. |
572
+ | `history` | Optional. How far back `view` reads with no `--days`, `--from` or `--to`: `{ "days": 30 }`, `{ "from": "2025-01-01" }`, a range in the past `{ "from": "2025-01-01", "to": "2025-03-31" }`, or `{ "all": true }`. The last 7 days or fewer always load whole. A longer choice loads at most the newest `historyLimitMB` of logs and says which days it loaded when that cuts it short. Leave it out for the last 7 days. Setup and Settings write it. |
573
+ | `historyLimitMB` | Optional. The most log data, in MB, a saved `history` longer than a week loads at once, and the most the Problems page reads for the window before a longer choice (a week's week before always loads whole): 500 unless you raise it (50 to 20000). Settings shows an estimate of the time and memory before you save a new one. |
574
+ | `goalsFile` | Optional. The goal list `view` reads, resolved like a repo path. Leave it out and `view` runs without goals, or pass `--goals <file>` for one run. It's not the goals page's `honestweek.objectives.json`; see [The goal list](#the-goal-list). |
575
+ | `longSessionTokens` | Optional. How many tokens of context an agent can carry before the Problems page flags it for going on, from 10000 to 10000000, for example `150000`. Leave it out and that check is off: no vendor recommends a number. Settings sets it. |
576
+ | `voice.denyPhrases` / `voice.allowPhrases` | Optional string lists (default empty). `denyPhrases` **extends** the built-in denylist with your own phrases (literal, case-insensitive). `allowPhrases` is the false-positive **off-ramp**: it exempts a legitimate phrase a built-in pattern would otherwise flag (surgical to the matched text), so one over-eager match doesn't force you to disable the whole lint. |
577
+
578
+ **Repo roles:**
579
+
580
+ - **`featured`**: git-read **and** git-verified, and headlined in the output.
581
+ - **`reference`**: git-read but not headlined.
582
+ - **`display`**: summarized generically and **NEVER git-read**. Use it for repos you want acknowledged without reading their commits.
583
+
584
+ ## Sidecars
585
+
586
+ | File | Status |
587
+ | --- | --- |
588
+ | `honestweek.draft.json` | The redacted weekly digest from `discover`. **Gitignored.** An intermediate working artifact, never published. |
589
+ | `honestweek.prompts.json` | The private, redacted Claude Code and Codex prompt inbox plus no-text deletion tombstones. **Gitignored.** Never read by a renderer. |
590
+ | `honestweek.curated.json` | The private, redacted six-category review model from `digest prepare`. **Gitignored.** It contains exact selection and privacy decisions. A deleted current-week item leaves only a no-text tombstone. |
591
+ | `honestweek.digest.pending.json` | A no-text transaction marker used only to recover an interrupted `digest prepare`. **Gitignored.** Other commands fail closed while it exists. |
592
+ | `honestweek.prompt-items.json` | The public-safe lane. Version 1 is prompt-only; version 2 is the balanced digest. **Gitignored.** `validate` and `build` reconstruct it from local sources before use. |
593
+ | `honestweek.carry.json` | The private, redacted carry history, bounded to 12 week records. **Gitignored.** Only a successful lifecycle build advances it. |
594
+ | `honestweek.carry.pending.json` | The hash-bound output/carry recovery envelope for an interrupted lifecycle build. **Gitignored.** Unknown output and carry combinations fail closed. |
595
+ | `honestweek.items.json` | The distilled, human-reviewable items. **Yours to keep or ignore** (not gitignored unless you add it; safe to delete). |
596
+ | `honestweek.reader.json` (opt-in) | The reader profile for a client report: who it's for, what they see first, and where each line of that came from. Holds a real person's preferences, so keep it private with the report. |
597
+ | `<report>.note.md` (opt-in) | The short note a reader profile asks for with `format.note`, written beside the client report. Yours to share. |
598
+ | `honestweek.history.json` | What landed on the default branch in a period, from `history`: the raw material for a client report. **Gitignored.** Redacted before it's written; only counts are printed. |
599
+ | `honestweek.drafts/` (opt-in) | Post drafts from `mine --draft`, with their claims still unverified. **Gitignored** in a folder `init` set up; elsewhere, add it yourself or set `mine.draft.dir`. |
600
+ | `honestweek.harvest.json` | Proposed redaction-denylist candidates from `harvest`. **Gitignored.** Only the count is printed; the raw nouns stay local for you to review. |
601
+ | `honestweek.codex-judgments/` (opt-in) | What your own `codex` wrote about each Codex session when you press Run with Codex in `view`, one file per session. **Gitignored**: the folder ignores itself and gets a line in the config folder's `.gitignore`. Redacted before it's written. |
602
+ | `output.file` (e.g. `honestweek.digest.md`) | The final rendered output. **Yours to keep or ignore.** |
603
+ | `honestweek.config.json` | Your config. `init` adds it to `.gitignore` when you give it private words, since it then lists them; it can also hold private repo paths. Un-ignore it if you want it tracked. |
604
+ | `honestweek.archive/` (opt-in) | The local weekly snapshots + `index.json` (the "/log" series). Only written when `output.archive` is true. **Yours to keep, ignore, or commit.** |
605
+ | `honestweek.objectives.json` (opt-in) | The goal registry that turns `page` mode multi-page (emits `goals.html`). Absent → single-page. The publish gate for goals; commit it if you want the goals page. |
606
+ | `honestweek.goal-changelog.json` (opt-in) | Optional append-only log of structural goal-set changes, rendered as the goals page's "what changed" band. |
607
+ | `honestweek.findings.json` (opt-in) | The `mine` findings ledger: what was found, and what you accepted or declined. **Commit it**: it is the only record of what you already said no to, and everything in it is de-identified and redacted before it is written. |
608
+
609
+ ## What it does NOT do / privacy model
610
+
611
+ - **Only your own allowlisted repos are read.** `git` runs only against the repositories in your `repos` list, apart from the setup scans that suggest what to list (`init`, and Setup and Settings in `view`), which look in the folder you run them in and the folders next to it, and the checks that `discover`'s draft file and Settings' config aren't tracked in the folder you run them in. Weekly reports use only sessions from those repos; `mine` reads every session in your logs, as [SECURITY.md](SECURITY.md) explains.
612
+ - **`display`-role repos are summarized generically and NEVER git-read.** There is no code path that runs `git` against a `display` repo.
613
+ - **Output stays local until you publish it.** honestweek writes local files only.
614
+ - **No telemetry, no network egress.** honestweek makes no network call. The one exception is yours to start: with Include /insights on, Run /insights and Run with Codex run your own `claude` or `codex`, which send your sessions to Claude or OpenAI after asking. The optional `preview` server is loopback-only (`127.0.0.1`): it serves your already-built output with no key, so any program or account on your machine can read it while it runs, and nothing leaves your machine. The `view` page is loopback-only too, answers only the page it opened, and keeps what it reads in memory; see [What `view` keeps private](#what-view-keeps-private).
615
+ - **Nothing is auto-published.** honestweek produces a draft; *you* are the publisher.
616
+
617
+ ### What the scrubber catches, and what it doesn't
618
+
619
+ Redaction is pattern-based and deliberately over-redacts when a pattern is ambiguous. It reliably removes email addresses (including ones with an encoded `@`, like `%40`), home and user paths (including `~/…`, the root account's `/root/…`, URL-encoded paths, and the user name in Claude Code's encoded project folder names like `C--Users-you-…`), prefixed API keys (GitLab's `glpat-` too) and JWTs, high-entropy tokens of 32+ characters, UUIDs, bare 9+ digit runs, currency amounts, and every term you list under `redaction`, whether its accents are written composed or decomposed. A bare hex string of 32 or more characters counts as a token too, unless it's exactly 40 characters, the length of a full commit id. Keys in what it writes, like a chart's repo labels or a tool's name, are scrubbed the same way as values.
620
+
621
+ It also hides the value of a field whose name says it's a secret: a password, passphrase, token, secret, API key, access or private key, credential, cookie, signature or authorization. The name can be spelled `API_KEY`, `x-api-key`, `client_secret`, `dbPassword`, `authtoken`, `DB_PASS`, `PGPASSWORD`, `MYSQL_PWD` or ODBC's `PWD`, and the value can follow `=`, `=>`, `:`, `:=`, `==` or `===`, sit in a quoted JSON string at any level of escaping, sit inside an XML element named that way (`<password>…</password>`), or follow a `--password` flag or a `-Password` parameter. A `password:` line and an `Authorization:` or `Cookie:` header are hidden to the end of the line, a quote, or the next `key:` on it. In a JSON record read back whole, a value under a key like that is hidden too. Bearer and Basic credentials, the password in a web address (`redis://:…@host`) or after `curl -u user:…`, and a PowerShell `ConvertTo-SecureString` literal (after `-String` or `-AsPlainText`, or piped in) go the same way. Only the value is replaced, with `[redacted:secret]`, so you can still see which field held it. A key that only ends in `Key`, like `fileKey` or `sessionKey`, isn't a secret, and neither is a value like `true`, `none`, or a test count after `pass:`.
622
+
623
+ It is a safety net, not a guarantee. Known gaps, so you can decide rather than assume:
624
+
625
+ - **Short secrets with nothing naming them.** A hand-picked password under 32 characters that no field, flag, header or scheme names (a bare `hunter2` in a sentence, a password glued to `mysql -p`, an item in a plural `tokens` list) is indistinguishable from prose and survives.
626
+ - **Prose that reads like a field.** Because it errs toward hiding, a sentence that starts like one loses the word after the colon: `Auth: users get logged out` is published as `Auth: [redacted:secret] get logged out`. In goal text (an objective's label, `what`, `why` or `how`, or a changelog entry), anything the redactor would change stops `build` instead, so reword a line like `Auth: refresh sessions quietly` there. Plain words after `Bearer` or `Basic` (`basic validation`) and a type annotation (`login(password: string)`) are left alone.
627
+ - **A value after a bold label.** In `**Token:** abc123` the field's value reads as the closing `**`, so `abc123` still shows. Keep secrets out of Markdown bold labels.
628
+ - **A quoted part inside a header.** A quoted part (`Cookie: theme="dark"; session=…`, `Authorization: Digest … response="…"`) ends the hidden part at its quote, so what follows can show.
629
+ - **Unlisted spellings of a listed term.** Adding `AcmeCorp` does not cover `Acme Corp`, `Acme-Corp`, or `Doe, Jane` for `Jane Doe`. List the variants you care about; `harvest` proposes candidates from your own draft.
630
+ - **Structured personal data.** Phone numbers, SSNs, and space- or hyphen-separated card numbers are not matched. Only unbroken 9+ digit runs are.
631
+ - **UNC paths.** `\\server\Users\you\…` is not matched; drive-letter and POSIX forms are.
632
+
633
+ Read the built output before you publish it. That review is part of the design, not a formality, and `preview` exists to make it easy.
634
+
635
+ ### The launch invariant
636
+
637
+ honestweek's two non-negotiable promises:
638
+
639
+ 1. **A receipt on every line.** Every emitted item points to its source: a commit SHA or a session turn. An item that reaches the renderer without a receipt is a build error, not a receipt-less line.
640
+ 2. **It never asserts a motive the log does not contain.** honestweek defaults to **under-claiming**: verified/measured work that has landed on the repo's default branch reads as `shipped`; real work still on an unmerged branch reads as `in progress`; anything weaker reads as `designed, not proven`. It never narrates intent the transcript doesn't support.
641
+
642
+ ## Releasing (maintainers)
643
+
644
+ honestweek is on npm, starting with version 0.2.0. I publish each version from my own terminal and then tag it, in the order [docs/releasing.md](docs/releasing.md) sets out. The `files` allowlist in `package.json` decides what ships (`bin/`, `lib/`, `SKILL.md`, the example config and the plugin manifests), and `test/package-contents.test.mjs` pins it.
645
+
646
+ ## Contributing and security
647
+
648
+ [CONTRIBUTING.md](CONTRIBUTING.md) covers setup (there's nothing to install), the constraints every change keeps, and how to report a bug without pasting your own logs. To report a security or privacy problem privately, see [SECURITY.md](SECURITY.md).
649
+
650
+ ## License
651
+
652
+ [MIT](LICENSE)
653
+
654
+ ## Which Claude Code turns count as yours
655
+
656
+ Current Claude Code marks each turn with who sent it, in a `turnOrigin` field: `human` when it came from your own session, typed or pasted, `sdk` when a program sent it (a script, the Agent SDK, a headless `claude -p` run, or another session through one), and other values for a background task's notice or a message from another session. The interactive-session count in `page` and `site` modes reads it too, unless you set `output.skipProgramSessions` to `false`. The weekly digest, the prompt inbox behind `prompts` and the digest's Prompt highlights, and `mine` read a turn as yours only when it's marked `human` or isn't marked at all, as in logs from older Claude Code, which read exactly as before. A turn marked as anyone else's isn't one of your prompts, your words in a session's digest entry, an idea or decision cue, or the first prompt `mine` uses to tell sessions apart. A session where only a program, a task or another session sent turns isn't one you worked in, so the digest and `mine` leave it out; one a program opened and you typed into later still counts. A program's turn keeps its place in the session's turn numbers, so prompts you've already kept or hidden keep their receipts. It also ends your turn, even when it's only a slash command or a notice, so a test run or reply that follows it isn't credited to your prompt. Claude Code also logs a turn in a queue before delivering it, and only the delivery (the turn itself, or a note attached mid-turn) says who sent it, so `mine` counts a queued turn once, as its delivery, and not at all when the delivery is someone else's. A value honestweek doesn't recognize counts as someone else's here; Replay reads one as yours and marks that as inferred.
657
+
658
+ ## Codex Voice and session logs
659
+
660
+ honestweek reads regular JSONL files under `$CODEX_HOME/sessions` and `$CODEX_HOME/archived_sessions`, excluding `subagents`. It does not read `history.jsonl`, plaintext logs, or other app state. A human turn is read from either shape Codex has used: the current `response_item` message with `role: "user"`, or the older `event_msg` / `user_message` string. Codex sends its own context (environment, `AGENTS.md`, plugin lists) and other agents' hand-offs through the same user slot, so a block that opens with a tag or the `AGENTS.md` preamble is dropped, only the request is kept from the IDE extension's wrapper (open file, tabs, mentioned files), and a message carrying a delegation, heartbeat, automation, or approval-review block isn't counted as a person at all. When a turn is written in both shapes, it's counted once. A session started with `codex exec` is never counted as mine: another agent or a script usually starts those, so none of its messages becomes a prompt in the inbox, the digest or the miner, and the work history shows its first message as the agent's starting instruction. A session I type in that only mentions `codex exec` still counts. A Voice or dictated turn is ingested only when Codex records its transcript as one of those message shapes. The `audio`, `local_audio`, image, reasoning, tool-output, and other non-message fields are never retained as prompt text. A paired shell record sets only the observed-verification boolean when it contains one literal recognized test or commit command, an explicit zero exit, and matching positive evidence. Current Codex `exec` wrappers qualify only in a closed form that forwards the unchanged shell result; they are parsed without evaluation, and their source and output text are discarded. Raw session ids and working paths become hashes or private attribution; the redacted prompt, privacy audit, timestamp, source, turn, and receipt hashes remain in the current gitignored review store. Raw transcript retention remains Codex's responsibility and is not changed by honestweek.
661
+
662
+ A valid Codex session record does not need a final assistant message. Its public-safe human prompt can contribute to cross-session lexical recurrence and automatic draft selection, but it cannot supply assistant-final cues or observed verification unless those records exist. A missing, unconfigured, or `display`-role working directory makes the turn private. Private or hidden turns cannot supply recurrence evidence or enter automatic output. An ambiguous or high-risk human prompt is withheld from prompt recurrence and prompt output. A labelled cue in that human prompt retains the prompt receipt and conservative prompt audit; an assistant-final cue is gated separately on its own redacted rendition and exact receipt. A malformed record or missing Codex session identity makes that source unreadable and preserves the prior store. The private prompt store is regenerated for the completed week. Its no-text deletion tombstones persist until explicit reset, and redacted lifecycle carry persists only within the limits described above.