frizz 0.2.0 → 0.4.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 (115) hide show
  1. package/README.md +25 -20
  2. package/dist/claude-agent-broker.js +72 -27
  3. package/dist/dev-child.js +8302 -4628
  4. package/dist/frizz.js +1302 -701
  5. package/package.json +10 -4
  6. package/runtime/cc-worker/.claude-plugin/plugin.json +1 -1
  7. package/runtime/cc-worker/DECISIONS.md +81 -4
  8. package/runtime/cc-worker/bin/frizz-mcp.mjs +472 -58
  9. package/runtime/cc-worker/hooks/agent-dispatch.mjs +1 -1
  10. package/runtime/cc-worker/hooks/deny-plan.mjs +1 -1
  11. package/runtime/cc-worker/hooks/hooks.json +0 -7
  12. package/runtime/cc-worker/hooks/precompact-instructions.mjs +39 -28
  13. package/runtime/cc-worker/hooks/scratchpad.mjs +142 -169
  14. package/runtime/cc-worker/hooks/session-seed.mjs +16 -15
  15. package/runtime/cc-worker/skills/waits/SKILL.md +2 -2
  16. package/web-dist/apple-touch-icon.png +0 -0
  17. package/web-dist/assets/{TerminalPane-ROKHp1ib.js → TerminalPane-sd3XXjx5.js} +2 -2
  18. package/web-dist/assets/{abnfDiagram-VRR7QNED-DcpdhBs3.js → abnfDiagram-VRR7QNED-Bry_FIqg.js} +1 -1
  19. package/web-dist/assets/architecture-TIHT7OUA-CoMJQ5Ya.js +1 -0
  20. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-CUAKf0mn.js → architectureDiagram-ZJ3FMSHR-Baok4OeI.js} +1 -1
  21. package/web-dist/assets/{blockDiagram-677ZJIJ3-BPwpJIzx.js → blockDiagram-677ZJIJ3-BgHIO9lI.js} +1 -1
  22. package/web-dist/assets/{c4Diagram-LMCZKHZV-1lptuHzZ.js → c4Diagram-LMCZKHZV-rfj9Z17Z.js} +1 -1
  23. package/web-dist/assets/channel-D6uS1y7I.js +1 -0
  24. package/web-dist/assets/{chunk-32BRIVSS-CFR9AKjY.js → chunk-32BRIVSS-BwaHfK1Y.js} +1 -1
  25. package/web-dist/assets/{chunk-52WLFC77-CM9uct7m.js → chunk-52WLFC77-BmdQDZOA.js} +1 -1
  26. package/web-dist/assets/{chunk-C7G6YPKG-DiveJARw.js → chunk-C7G6YPKG-ByQFjoZe.js} +1 -1
  27. package/web-dist/assets/{chunk-EX3LRPZG-BE1CBw8F.js → chunk-EX3LRPZG-DQFudBKr.js} +1 -1
  28. package/web-dist/assets/{chunk-FWX5IMBZ-DL42uXiO.js → chunk-FWX5IMBZ-OW9qEPiq.js} +2 -2
  29. package/web-dist/assets/{chunk-HOUHSVGY-DPhJWgDw.js → chunk-HOUHSVGY-BdKLF8nO.js} +1 -1
  30. package/web-dist/assets/{chunk-ICXQ74PX-CwYy-6AP.js → chunk-ICXQ74PX-C1roqKR1.js} +1 -1
  31. package/web-dist/assets/{chunk-MOJQB5TN-Ds5I9wxq.js → chunk-MOJQB5TN-Cx0u1ZDK.js} +1 -1
  32. package/web-dist/assets/{chunk-OGEWGWER-DHiZJwQD.js → chunk-OGEWGWER-rxv9xtNR.js} +1 -1
  33. package/web-dist/assets/{chunk-PUDLZKDR-B-eyQTsF.js → chunk-PUDLZKDR-BXWPPPPi.js} +1 -1
  34. package/web-dist/assets/{chunk-Q4XR5HBZ-DK7dB3Ti.js → chunk-Q4XR5HBZ-CpqbD101.js} +1 -1
  35. package/web-dist/assets/{chunk-V7JOEXUC-Dn59m74L.js → chunk-V7JOEXUC-CP8_3qVt.js} +1 -1
  36. package/web-dist/assets/{chunk-VAUOI2AC-DK7x36hd.js → chunk-VAUOI2AC-Dl7xahpk.js} +1 -1
  37. package/web-dist/assets/{chunk-VR4S4FIN-D7-CI3Yl.js → chunk-VR4S4FIN-BKtMX64l.js} +1 -1
  38. package/web-dist/assets/{chunk-WYO6CB5R-B3l-mLCs.js → chunk-WYO6CB5R-DmLOdJcu.js} +1 -1
  39. package/web-dist/assets/{chunk-ZGVPDNZ5-Dobxlxie.js → chunk-ZGVPDNZ5-5wN7eXvS.js} +1 -1
  40. package/web-dist/assets/classDiagram-OUVF2IWQ-BW5YiBf4.js +1 -0
  41. package/web-dist/assets/classDiagram-v2-EOCWNBFH-BW5YiBf4.js +1 -0
  42. package/web-dist/assets/{cynefin-VYW2F7L2-Dh7RuEUJ.js → cynefin-VYW2F7L2-DUYahBXb.js} +1 -1
  43. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-ClPi2mZZ.js → cynefinDiagram-TSTJHNR4-Rm0i30nE.js} +1 -1
  44. package/web-dist/assets/{dagre-VKFMJZFB-52_WP1QV.js → dagre-VKFMJZFB-3uhsB-W3.js} +1 -1
  45. package/web-dist/assets/{diagram-FQU43EPY-D_1zVsTL.js → diagram-FQU43EPY-BUvflNRQ.js} +1 -1
  46. package/web-dist/assets/{diagram-G47NLZAW-CdZxuGUy.js → diagram-G47NLZAW-DUluIZel.js} +1 -1
  47. package/web-dist/assets/{diagram-NH7WQ7WH-C8pSFu0P.js → diagram-NH7WQ7WH-BBrwsbed.js} +1 -1
  48. package/web-dist/assets/{diagram-OA4YK3LP-C5bjZLre.js → diagram-OA4YK3LP-DWnTQBw4.js} +1 -1
  49. package/web-dist/assets/{diagram-WEI45ONY-Bxzhiuzn.js → diagram-WEI45ONY-BjEavoC0.js} +1 -1
  50. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-g-Z0J2wP.js → ebnfDiagram-CCIWWBDH-CW4xZAZH.js} +1 -1
  51. package/web-dist/assets/{erDiagram-Q63AITRT-DVNkgIHp.js → erDiagram-Q63AITRT-BemQ1R4B.js} +1 -1
  52. package/web-dist/assets/eventmodeling-45OFAUF4-BF5KB7ja.js +1 -0
  53. package/web-dist/assets/flowDiagram-23GEKE2U-BYo4Eytx.js +1 -0
  54. package/web-dist/assets/{ganttDiagram-NO4QXBWP-_71pQYEK.js → ganttDiagram-NO4QXBWP-lDdG5I_z.js} +1 -1
  55. package/web-dist/assets/{gitGraph-TEB2WS4Q-ChIZiGZS.js → gitGraph-TEB2WS4Q-Bw87a_Se.js} +1 -1
  56. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-DCHAFI0l.js → gitGraphDiagram-IHSO6WYX-B762r0yi.js} +1 -1
  57. package/web-dist/assets/index-B3QArXu2.css +1 -0
  58. package/web-dist/assets/index-CAapfhMv.js +365 -0
  59. package/web-dist/assets/{info-DKCQHKI2-BW-n_T1j.js → info-DKCQHKI2-DGOv6Gx0.js} +1 -1
  60. package/web-dist/assets/{infoDiagram-FWYZ7A6U-CgDYsKi9.js → infoDiagram-FWYZ7A6U-DL92kAzf.js} +1 -1
  61. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-ClzGNt9N.js → ishikawaDiagram-FXEZZL3T-CFYd4OtU.js} +1 -1
  62. package/web-dist/assets/{journeyDiagram-5HDEW3XC-DSCQxkHC.js → journeyDiagram-5HDEW3XC-QHuYL5zq.js} +1 -1
  63. package/web-dist/assets/{kanban-definition-HUTT4EX6-CdrdX9N8.js → kanban-definition-HUTT4EX6-DwmMluQ8.js} +1 -1
  64. package/web-dist/assets/{line-ha38Dc-1.js → line-Je_PFFHm.js} +1 -1
  65. package/web-dist/assets/{mermaid-parser.core-Z4uMcpip.js → mermaid-parser.core-BeiGWsn3.js} +3 -3
  66. package/web-dist/assets/{mermaid.core-iZRq3hbu.js → mermaid.core-BP8JrW48.js} +3 -3
  67. package/web-dist/assets/{mindmap-definition-LN4V7U3C-DmhInJO_.js → mindmap-definition-LN4V7U3C-BsmjCIrM.js} +1 -1
  68. package/web-dist/assets/{packet-7NZHBO7P-DBPB36Kl.js → packet-7NZHBO7P-D6ekYYGJ.js} +1 -1
  69. package/web-dist/assets/{pegDiagram-2B236MQR-CAH3ljfj.js → pegDiagram-2B236MQR-CQc2Kt0u.js} +1 -1
  70. package/web-dist/assets/{pie-RZYD4A2V-_h_eX4Ca.js → pie-RZYD4A2V-C_45fO8J.js} +1 -1
  71. package/web-dist/assets/{pieDiagram-ENE6RG2P-DFBPus8j.js → pieDiagram-ENE6RG2P-Dg5z6iWt.js} +1 -1
  72. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-DMvOCjt8.js → quadrantDiagram-ABIIQ3AL-c7gZxuCX.js} +1 -1
  73. package/web-dist/assets/{radar-I7S5WNFK-2EzoPHEZ.js → radar-I7S5WNFK-D80XNJQq.js} +1 -1
  74. package/web-dist/assets/{railroad-3IZDKUUU-BPJnn-hm.js → railroad-3IZDKUUU-Brz7eZQ0.js} +1 -1
  75. package/web-dist/assets/railroad-abnf-AHOZXSZD-D44pcGhJ.js +1 -0
  76. package/web-dist/assets/railroad-ebnf-EBAXGLYW-CiWVH5SP.js +1 -0
  77. package/web-dist/assets/railroad-peg-LSFZ7HO6-Cy1B6-pN.js +1 -0
  78. package/web-dist/assets/{railroadDiagram-RFXS5EU6-DKq5FagA.js → railroadDiagram-RFXS5EU6-Db9K7bty.js} +1 -1
  79. package/web-dist/assets/{requirementDiagram-TGXJPOKE-BJ5tGazp.js → requirementDiagram-TGXJPOKE-m1ipMrDe.js} +1 -1
  80. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-XSJjcBhX.js → sankeyDiagram-HTMAVEWB-4Zz9ry0k.js} +1 -1
  81. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-CBb8emSe.js → sequenceDiagram-DBY2YBRQ-CZeGHw4X.js} +1 -1
  82. package/web-dist/assets/{stateDiagram-2N3HPSRC-DDfRW94V.js → stateDiagram-2N3HPSRC-rLUVs1Pg.js} +1 -1
  83. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-w7QDFEvx.js +1 -0
  84. package/web-dist/assets/{swimlanes-5IMT3BWC-DvRYbkZi.js → swimlanes-5IMT3BWC-BAeBdscz.js} +1 -1
  85. package/web-dist/assets/swimlanesDiagram-G3AALYLV-UhdgWpNZ.js +8 -0
  86. package/web-dist/assets/{timeline-definition-FHXFAJF6-BNUa_DwI.js → timeline-definition-FHXFAJF6-DL0eWMF-.js} +1 -1
  87. package/web-dist/assets/{treeView-QDETBFTQ-I6-IW6nJ.js → treeView-QDETBFTQ-gEtzLMA8.js} +1 -1
  88. package/web-dist/assets/{treemap-6X3UGDF4-CWWmEUYJ.js → treemap-6X3UGDF4-CCym1Gz6.js} +1 -1
  89. package/web-dist/assets/{vennDiagram-L72KCM5P-DTDrPGLk.js → vennDiagram-L72KCM5P-cF97-nb5.js} +1 -1
  90. package/web-dist/assets/{wardley-OPB4EBWU-CNsdgXXA.js → wardley-OPB4EBWU-DQJHCGbM.js} +1 -1
  91. package/web-dist/assets/{wardleyDiagram-EHGQE667-YE0tq3Kh.js → wardleyDiagram-EHGQE667-0CnHzXLX.js} +1 -1
  92. package/web-dist/assets/{xychartDiagram-FW5EYKEG-D0ofMX8C.js → xychartDiagram-FW5EYKEG-9YDOp4m5.js} +1 -1
  93. package/web-dist/favicon-16.png +0 -0
  94. package/web-dist/favicon-32.png +0 -0
  95. package/web-dist/favicon.svg +17 -61
  96. package/web-dist/icon-192.png +0 -0
  97. package/web-dist/icon-512.png +0 -0
  98. package/web-dist/icon-maskable-512.png +0 -0
  99. package/web-dist/index.html +19 -8
  100. package/web-dist/manifest.webmanifest +3 -3
  101. package/runtime/cc-worker/hooks/scratchpad-stop.mjs +0 -125
  102. package/runtime/cc-worker/skills/handoff/SKILL.md +0 -209
  103. package/web-dist/assets/architecture-TIHT7OUA-CAviNivx.js +0 -1
  104. package/web-dist/assets/channel-CqKDIFQF.js +0 -1
  105. package/web-dist/assets/classDiagram-OUVF2IWQ-B_-6iXYY.js +0 -1
  106. package/web-dist/assets/classDiagram-v2-EOCWNBFH-B_-6iXYY.js +0 -1
  107. package/web-dist/assets/eventmodeling-45OFAUF4-MpmeH5YZ.js +0 -1
  108. package/web-dist/assets/flowDiagram-23GEKE2U-D-QgjjhF.js +0 -1
  109. package/web-dist/assets/index-w4v-GZEc.js +0 -358
  110. package/web-dist/assets/index-zyi22LPz.css +0 -1
  111. package/web-dist/assets/railroad-abnf-AHOZXSZD-YeUoiySk.js +0 -1
  112. package/web-dist/assets/railroad-ebnf-EBAXGLYW-Ddw1SuGG.js +0 -1
  113. package/web-dist/assets/railroad-peg-LSFZ7HO6-Dd8BOGeW.js +0 -1
  114. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-hc41W5Lx.js +0 -1
  115. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BZyGdgSG.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frizz",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "description": "A local web UI for running many coding agents at once",
6
6
  "keywords": [
@@ -38,21 +38,27 @@
38
38
  "frizz-dev:uninstall": "nub scripts/install-global-cli.mjs --uninstall",
39
39
  "install:global": "nub scripts/install-global-cli.mjs",
40
40
  "typecheck": "tsc -b packages/shared packages/rpc packages/server . && pnpm --filter @frizz/web typecheck",
41
- "test": "nub --test --test-force-exit 'board/*.test.mjs' 'scripts/**/*.test.mjs' 'src/**/*.test.ts' 'packages/shared/src/**/*.test.ts' 'packages/server/src/**/*.test.ts' 'packages/web/src/**/*.test.ts'",
41
+ "test": "nub scripts/run-tests.mjs",
42
42
  "prepack": "node ./scripts/prepare-package.mjs && node ./scripts/build-package.mjs && node ./scripts/publish-manifest.mjs --strip",
43
- "postpack": "node ./scripts/publish-manifest.mjs --restore"
43
+ "postpack": "node ./scripts/publish-manifest.mjs --restore && node ./scripts/prepare-package.mjs --clean"
44
44
  },
45
45
  "dependencies": {
46
46
  "@parcel/watcher": "^2.5",
47
- "node-pty": "^1.1"
47
+ "node-pty": "^1.1",
48
+ "qrcode-generator": "^2.0.4"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@types/node": "^24",
51
52
  "esbuild": "^0.25.0",
53
+ "jsqr": "^1.4.0",
52
54
  "puppeteer": "^25.3.0",
53
55
  "typescript": "^5.7"
54
56
  },
55
57
  "pnpm": {
58
+ "overrides": {
59
+ "react": "19.2.7",
60
+ "react-dom": "19.2.7"
61
+ },
56
62
  "onlyBuiltDependencies": [
57
63
  "node-pty",
58
64
  "@parcel/watcher",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frizz",
3
- "description": "Worker-side frizz plugin for frizz-spawned sessions. Each session is a WORKER driving ONE effort (slug via env FRIZZ_THREAD): it SIGNALS through its final message (done, human/timer awaiting, question), keeps automatable waits active with Claude wait tools, and PERSISTS through a scratchpad blackboard (.frizz/threads/<session-id>/scratch.md) with an optional stop_hook reminder. Supplies the frizz:<model>-<effort> sub-agent profiles (dispatch as frizz:opus-high, frizz:sonnet-medium, frizz:haiku, …), the on-demand frizz:gh skill, and hooks that seed the worker contract, enforce background/name-stripped sub-agent dispatch, and deny the interactive question/plan prompts (deny-ask, deny-plan) that would hang a dashboard worker. Hooks are inert unless FRIZZ_THREAD is set.",
3
+ "description": "Worker-side frizz plugin for frizz-spawned sessions. Each session is a WORKER driving ONE effort (slug via env FRIZZ_THREAD): it SIGNALS through its final message (done, human/timer awaiting, question), keeps automatable waits active with Claude wait tools, and keeps its own free-form scratch directory (.frizz/threads/<session-id>/). Supplies the frizz:<model>-<effort> sub-agent profiles (dispatch as frizz:opus-high, frizz:sonnet-medium, frizz:haiku, …), the on-demand frizz:gh skill, and hooks that seed the worker contract, enforce background/name-stripped sub-agent dispatch, and deny the interactive question/plan prompts (deny-ask, deny-plan) that would hang a dashboard worker. Hooks are inert unless FRIZZ_THREAD is set.",
4
4
  "version": "0.1.10",
5
5
  "author": { "name": "Colin McDonnell" },
6
6
  "homepage": "https://github.com/colinhacks/frizz",
@@ -30,8 +30,8 @@ what was ported from the orchestrator `cc/` plugin, what was dropped, and why.
30
30
  | Hook | Event | Ported from | What it does for a worker |
31
31
  | --- | --- | --- | --- |
32
32
  | `session-seed.mjs` | SessionStart (startup/resume/clear/compact) | cc `session-seed.mjs` | Injects the single-thread worker contract + the bound slug + its file path; re-grounds on compact. Also writes cc's `off` sentinel defensively (see interplay). |
33
- | `precompact-instructions.mjs` | PreCompact (auto/manual) | new — no cc equivalent | Steers WHAT SURVIVES compaction: emits an editorial brief asking the summarizer to preserve the high-level approach (plan, alternatives rejected, rationale) at high fidelity, plus a closing "Re-grounding before continuing:" section naming the scratchpad path and the files to re-read. **PLAIN STDOUT is the channel** — cc's usual `hookSpecificOutput` JSON would be handed to the summarizer as its literal instructions. Skips sub-agent contexts (the derived scratchpad path is only guaranteed for the top-level worker). |
34
- | `scratchpad.mjs` | SessionStart (startup/resume/clear/compact) + PreCompact (auto/manual) + UserPromptSubmit + PostToolUse | new — no cc equivalent | Keeps the ONE per-thread scratchpad (`.frizz/threads/<sid>/scratch.md`) written and re-grounded across compaction. `--mode=session-start` injects the pad's HEAD back verbatim on the context-losing sources (compact/resume/clear) plus a re-read pointer, and teaches the contract when the pad is still an unwritten skeleton; `--mode=precompact` (**plain stdout**) hands the head to the summarizer; `--mode=nudge` fires on BOTH UserPromptSubmit and PostToolUse (mid-turn — the one that matters for long autonomous turns) once context has grown past `STALE_TOKENS` since the last write. Both nudge channels share one state file, so mid-turn firing does not multiply reminders. NOT gated on `FRIZZ_THREAD`; `--via=project` marks the repo-local registration and defers to this one inside a frizz worker. |
33
+ | `precompact-instructions.mjs` | PreCompact (auto/manual) | new — no cc equivalent | Steers WHAT SURVIVES compaction: emits an editorial brief asking the summarizer to preserve the high-level approach (plan, alternatives rejected, rationale) at high fidelity, plus a closing "Re-grounding before continuing:" section naming the thread's scratch-directory path and the files to re-read. **PLAIN STDOUT is the channel** — cc's usual `hookSpecificOutput` JSON would be handed to the summarizer as its literal instructions. Skips sub-agent contexts (the derived scratch-directory path is only guaranteed for the top-level worker). |
34
+ | `scratchpad.mjs` | SessionStart (startup/resume/clear/compact) + PreCompact (auto/manual) + UserPromptSubmit + PostToolUse | new — no cc equivalent | Keeps a worker aware of its per-thread scratch DIRECTORY (`.frizz/threads/<sid>/`). `--mode=session-start` NAMES the files in it on the context-losing sources (compact/resume/clear) a listing, never their content — and otherwise teaches the arrangement (write a doc, then arm `post_compaction`); `--mode=precompact` (**plain stdout**) tells the summarizer those files exist so it carries their paths forward; `--mode=nudge` fires on BOTH UserPromptSubmit and PostToolUse (mid-turn — the one that matters for long autonomous turns) once context has grown past `STALE_TOKENS` since the last write. Both nudge channels share one state file, so mid-turn firing does not multiply reminders. NOT gated on `FRIZZ_THREAD`; `--via=project` marks the repo-local registration and defers to this one inside a frizz worker. |
35
35
  | `agent-dispatch.mjs` | PreToolUse(Agent) | cc `agent-dispatch.mjs` | Enforces `run_in_background:true`, strips `name`/`team_name`, appends a worker-flavored orchestration epilogue. |
36
36
  | `bash-background.mjs` | PreToolUse(Bash) | new | Denies a local shell job that escapes through `&` without a later `wait` or EXIT trap, including one hidden inside a command-position `bash -c '…'`. Shell job control bypasses Claude's task registry, so Frizz cannot track or wake it; self-contained probe concurrency, and a wrapper handed to another program (`ssh`/`docker run`/`limactl shell`), remain allowed. |
37
37
  | `agent-bind.mjs` | PostToolUse(Agent) | cc `agent-bind.mjs` (verbatim behavior) | Records `agentId → thread` into `.frizz/.agent-bindings.jsonl` in cc's exact format, so a worker's THREAD-tagged helper renders on the frizz board's per-thread liveness. |
@@ -125,6 +125,23 @@ decision, not an artifact-portability implementation detail. A future isolation
125
125
  which settings/auth surfaces are preserved before adding `--settings`, a config-home override, or a
126
126
  global-plugin disable mechanism.
127
127
 
128
+ **2026-08-16 — the SDK broker had drifted off this policy, and is back on it.** The tmux transport
129
+ spawned a plain `claude`, which reads all three settings scopes, so the policy above held by default.
130
+ The Agent-SDK broker takes an explicit `settingSources` and the SDK's own default is `[]` — nothing at
131
+ all — so when the broker became the default Claude transport it read no config whatsoever. The
132
+ 2026-07-26 fix restored `project` + `local` (the repo's `CLAUDE.md` / `AGENTS.md` / `.claude/skills`)
133
+ and left `user` out, on a rationale written into the code — "the operator's personal `~/.claude` config
134
+ is theirs, not something a dispatched worker should silently inherit" — that this record had already
135
+ rejected. The gap was invisible because everything it withheld fails QUIETLY: the operator's `env`
136
+ block (which is where an API-proxy front-end writes its base-URL/token pair, so a broker session
137
+ authenticates differently from the CLI in the same shell), `autoCompactWindow` (so sessions compacted
138
+ at the default threshold, not the configured one), `permissions`, `hooks` and `enabledPlugins`.
139
+ Measured against the maintainer's real config, one variable, observed through a project-scope hook:
140
+ `--setting-sources=project,local` reported their `env` block UNSET, `user,project,local` reported it
141
+ applied, both sessions exiting 0 with empty stderr. The default is now all three scopes — the same
142
+ thing a plain `claude` in the same cwd reads. A frizz thread is the operator's own session on their own
143
+ machine, so the surprising behavior was the divergence, not the inheritance.
144
+
128
145
  ## 2026-07-02: Stop hook removed
129
146
  stop-flush.mjs is no longer wired (script kept for reference). User call: under frizz the
130
147
  tailer/board already surface worker state live, and the block-until-file-edited nag forced even
@@ -273,10 +290,22 @@ defect, and arguably correct: an explicit human rule should beat a blanket polic
273
290
 
274
291
  MARKER: `<stateDir>/perm-requests/<slug>.json` now carries `decision` / `rule` / `reason` / `command`
275
292
  alongside the original fields. The tailer treats ONLY a deferred request as a human block (an
276
- auto-resolved one must never card as "Needs you"), and surfaces the last allow/deny as `permPolicy` —
277
- the only durable record an approval leaves anywhere, since allows are never written to the transcript.
293
+ auto-resolved one must never card as "Needs you"), and surfaces the last DENIAL as `permPolicy`.
278
294
  A marker with no `decision` (an older plugin build) still blocks exactly as before.
279
295
 
296
+ APPROVALS ARE NOT SURFACED — reversed 2026-08-07. The tailer originally retained allows too, on the
297
+ reasoning that an approval leaves no other durable record (Claude Code renders "Allowed by
298
+ PermissionRequest hook" in the pane and writes nothing to the transcript), and Chat rendered them as
299
+ one quiet `Auto-approved <command> · rule <name>` line. The flaw was that `permPolicy` has no CLEAR:
300
+ the line stuck to the bottom of the thread permanently, so one routine `git status --short` read as
301
+ the thread's standing condition long after the turn that ran it (maintainer: *"This message just
302
+ showed up randomly, and now it's stuck showing up in the thread forever … it's fucking useless"*).
303
+ Nothing was blocked and nobody was waiting, so the visibility it bought was worth less than the
304
+ permanent noise. Denials keep the card: they are rare, they changed what the worker could do, and the
305
+ refusal also lands in the transcript, so the card is a pointer to something real rather than the only
306
+ copy of it. If approval visibility is ever wanted again it needs an EXPIRY (or a per-turn scope) —
307
+ re-adding the sticky line is not the fix.
308
+
280
309
  VERIFICATION: `scripts/verify-perm-marker.mjs` runs the REAL hook the way Claude Code does and
281
310
  asserts every branch. The allow path was additionally driven against a REAL interactive `claude` (it
282
311
  cannot be exercised under `claude -p`, where PermissionRequest hooks do not fire).
@@ -1023,3 +1052,51 @@ The rule now LEADS both child-facing epilogues, with the collection paragraph ke
1023
1052
  This is a PROMPT-level default, deliberately NOT the hook-level depth-2 DENY rejected on 2026-07-31 as too blunt: a dispatcher that genuinely wants a prong fanned out says so in the prompt and the child dispatches, unmodified. Also left alone: `workerPrompt.ts` — the root contract already authorizes fan-out *"when work genuinely decomposes"*, and the root is the one agent whose fan-out is wanted.
1024
1053
 
1025
1054
  Pinned by a new test in `agent-dispatch-hook.test.ts` (the lead-with-the-default wording plus the re-hinged conditional) and one in `scratchpad-hook.test.ts` (the codex block).
1055
+
1056
+
1057
+ ## 2026-08-06: the canonical scratchpad is DELETED — a free scratch directory, and compaction recovery moves to the recurring prompt
1058
+
1059
+ Frizz provisioned one canonical `scratch.md` per thread and a `SessionStart` hook spliced its HEAD into
1060
+ the context window after every compaction. The argument for the injection was sound and is worth
1061
+ restating, because it is what any replacement has to answer: a bare "remember to read your scratchpad"
1062
+ routes recovery through a decision the model can skip, which is exactly the failure the pad existed to
1063
+ prevent.
1064
+
1065
+ It still lost, on three counts. It made a MAINTAINED FILE the price of admission for every worker,
1066
+ including the ones whose whole task was one edit. It needed a merge-only contract per backend to stop
1067
+ sub-agents clobbering the one document — an epilogue in `agent-dispatch.mjs`, a `--mode=subagent-start`
1068
+ epilogue for codex, a legend line in every provisioned pad, and a paragraph of the worker contract, all
1069
+ of it policing a hazard rather than removing it. And the injection was INVISIBLE to the operator, who
1070
+ could neither see what their worker would be handed nor change it.
1071
+
1072
+ **What replaced it, maintainer's design:** the thread gets `.frizz/threads/<session-id>/` as a free-form
1073
+ scratch DIRECTORY — nothing provisioned into it, no reserved filename, no format — and compaction
1074
+ recovery moves to `mcp__frizz__recurring_prompt`'s new POST-COMPACTION trigger (scheduler SOURCE 7,
1075
+ landed the same day). The worker writes whatever doc it likes and LINKS it in the prompt; frizz re-sends
1076
+ that text the instant the context is summarized away. Durable in SQLite, visible and editable in the
1077
+ thread footer, and the worker chooses what it gets back.
1078
+
1079
+ The sub-agent story falls out for free: **one file per writer**. There is nothing to merge, so there is
1080
+ nothing to clobber, and the entire merge contract is deleted rather than reworded. Both child epilogues
1081
+ now say "write your OWN file; never edit or delete a file another agent wrote". The delegated-authority
1082
+ carve-out ("write only <path>" must not forbid the child's own coordination file) MOVED out of the
1083
+ worker contract and into the two epilogues that actually reach a child — it is pinned in
1084
+ `agent-dispatch-hook.test.ts` and `scratchpad-hook.test.ts` rather than in the contract goldens.
1085
+
1086
+ **The accepted cost, stated plainly rather than engineered around.** The maintainer chose this over a
1087
+ hybrid that kept a canonical doc, knowing compaction recovery degrades from a guaranteed injection to a
1088
+ pointer the model can skip. So the hook now NAMES the files in the directory and never their content
1089
+ (`scratchpad-hook.test.ts` pins that a body written into a scratch file does not appear in the
1090
+ injection). Re-growing that listing back into a content injection would restore exactly what was
1091
+ removed. The guaranteed channel is the arming, and every surface that mentions the directory also
1092
+ mentions `post_compaction: true`, because a folder nothing ever reads back is a folder of notes nobody
1093
+ opens.
1094
+
1095
+ **Two migrations that cost nothing.** `discover.ts`'s transcript-recovery sentinel shortened from
1096
+ `threads/<id>/scratch.md` to `threads/<id>/` — the new string is a PREFIX of the old one, so every
1097
+ transcript written before today still matches and no live thread lost its recovery path (pinned by
1098
+ `discover.test.ts`). And the Doc tab now renders the directory: files concatenated under a heading
1099
+ each, newest first, dotfiles excluded (frizz's own `.scratchpad-state.json` is not the worker's notes),
1100
+ binaries named rather than inlined, with per-file and total caps that say when they truncated. It is
1101
+ gated on the directory being NON-EMPTY rather than merely present, since dispatch now creates it empty
1102
+ and "exists" stopped meaning "the worker wrote something".