frizz 0.7.7 → 0.8.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.
- package/README.md +15 -45
- package/dist/claude-agent-broker.js +7 -4
- package/dist/dev-child.js +422 -273
- package/dist/frizz.js +1003 -398
- package/package.json +1 -1
- package/runtime/cc-worker/.claude-plugin/plugin.json +1 -1
- package/runtime/cc-worker/DECISIONS.md +31 -2
- package/runtime/cc-worker/agents/high.md +7 -0
- package/runtime/cc-worker/agents/low.md +7 -0
- package/runtime/cc-worker/agents/max.md +7 -0
- package/runtime/cc-worker/agents/medium.md +7 -0
- package/runtime/cc-worker/agents/xhigh.md +7 -0
- package/runtime/cc-worker/bin/frizz-mcp.mjs +3 -2
- package/runtime/cc-worker/hooks/agent-dispatch.mjs +7 -6
- package/runtime/cc-worker/hooks/hooks.json +0 -2
- package/runtime/cc-worker/hooks/scratchpad.mjs +5 -3
- package/runtime/cc-worker/hooks/session-seed.mjs +17 -17
- package/runtime/cc-worker/skills/gh/SKILL.md +5 -19
- package/web-dist/assets/{TerminalPane-Cb8jOFP9.js → TerminalPane-BIBHC61j.js} +1 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-Dtbg2eZ0.js → abnfDiagram-VRR7QNED-CcFQGFPf.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-BZEZt7jZ.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-DzQjWW7u.js → architectureDiagram-ZJ3FMSHR-DErIQOIs.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-BJnpkLMt.js → blockDiagram-677ZJIJ3-CpsUqur1.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-COdatsYu.js → c4Diagram-LMCZKHZV-D2dHmCEJ.js} +1 -1
- package/web-dist/assets/channel-DdFRPviT.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-CORMw4Vm.js → chunk-32BRIVSS-aOCEfxRW.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-C7lEadTg.js → chunk-52WLFC77-2iw4nJPC.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-DZy4F97l.js → chunk-C7G6YPKG-BPD3iHVE.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-HynlfV9p.js → chunk-EX3LRPZG-DrefHift.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-BbwKNhKm.js → chunk-FWX5IMBZ-By940EHT.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-lIhOZSmL.js → chunk-HOUHSVGY-B1Cqvz7e.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-WGxaMO8c.js → chunk-ICXQ74PX-1LkVpWuI.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-B-cx0f3u.js → chunk-MOJQB5TN-Ip1cy64r.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-DJceVwZH.js → chunk-OGEWGWER-CNjVyu8F.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-CGwHZns8.js → chunk-PUDLZKDR-9HZR6DAU.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-PTSWtmk1.js → chunk-Q4XR5HBZ-vtWwOCuQ.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-VNxHZPcf.js → chunk-V7JOEXUC-DC6YaHG0.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-ZXYCz_Aw.js → chunk-VAUOI2AC-CP-xe7SD.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-9WCtmFJp.js → chunk-VR4S4FIN-wbxDFptH.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-V4EBjpmt.js → chunk-WYO6CB5R-dibXmwpK.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-CPW0Z0ae.js → chunk-ZGVPDNZ5-_y_itJHG.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-Bf3duLb8.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-Bf3duLb8.js +1 -0
- package/web-dist/assets/{cynefin-VYW2F7L2-E7PklfJD.js → cynefin-VYW2F7L2-D1RYokZP.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-JIXAPjDf.js → cynefinDiagram-TSTJHNR4-qofqoy3T.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-DjXrdcNx.js → dagre-VKFMJZFB-CgHLoGFk.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY--i9i0qhm.js → diagram-FQU43EPY-JEAs4LOb.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-DxgcENZ_.js → diagram-G47NLZAW--tLd4Lf7.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-CUy9Nr90.js → diagram-NH7WQ7WH-DPbw9CJU.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-DbTbUaCb.js → diagram-OA4YK3LP-CDrb7nWs.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-2gk6xhOq.js → diagram-WEI45ONY-DJswZe3f.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-uE2iDETg.js → ebnfDiagram-CCIWWBDH-BP8-PZMF.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-dztd4MUw.js → erDiagram-Q63AITRT-BQXuebf5.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-DOLxRQQ5.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-DoK1yb0H.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-DAds6Aht.js → ganttDiagram-NO4QXBWP-DotMb935.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-Ci0XVvIa.js → gitGraph-TEB2WS4Q-B1vbYyKQ.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-C6FULyt8.js → gitGraphDiagram-IHSO6WYX-BjDXKk4m.js} +1 -1
- package/web-dist/assets/index-CmrDpsD8.css +1 -0
- package/web-dist/assets/{index-CNy5uOpI.js → index-Cs0TDGMu.js} +124 -124
- package/web-dist/assets/{info-DKCQHKI2-9N77dOiw.js → info-DKCQHKI2-xLTLqQju.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-BymP3PgG.js → infoDiagram-FWYZ7A6U-BFfYUsrC.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-CU_kQBz1.js → ishikawaDiagram-FXEZZL3T-45a7VMwm.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-DZN15HSd.js → journeyDiagram-5HDEW3XC-CEBUpu59.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-J4wR5g_3.js → kanban-definition-HUTT4EX6-RwKtDFzG.js} +1 -1
- package/web-dist/assets/{line-SRzGpiDr.js → line-DStcMIry.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-CGBscNGo.js → mermaid-parser.core-B0ekgQMA.js} +3 -3
- package/web-dist/assets/{mermaid.core-xNdwXb1r.js → mermaid.core-w1hcQaPy.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-gR2dbzrj.js → mindmap-definition-LN4V7U3C-D_n38Imb.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-DrR4W6I3.js → packet-7NZHBO7P-CstGeBOX.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-DN7R-_t4.js → pegDiagram-2B236MQR-DvowVyTO.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-C8VjQAFZ.js → pie-RZYD4A2V-BOP2j_HH.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-5w64zdD1.js → pieDiagram-ENE6RG2P-CKRqu_2f.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-B4rbezq_.js → quadrantDiagram-ABIIQ3AL-zSArSS8R.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-CTbbPB8m.js → radar-I7S5WNFK-BqRdNIBw.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-CY1er15b.js → railroad-3IZDKUUU-BaKcl_LU.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-itqDLg1p.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-ze7rLVCi.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-DKsYkEuG.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-Bx2HJ3yT.js → railroadDiagram-RFXS5EU6-BrXTQge9.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-BLK-Y2rx.js → requirementDiagram-TGXJPOKE-DBBNi_SS.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-Dk-8Miv-.js → sankeyDiagram-HTMAVEWB-BwFi7xFy.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DL2alfR-.js → sequenceDiagram-DBY2YBRQ-CeivqMeT.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-Bka44wf1.js → stateDiagram-2N3HPSRC-C6NZsnFm.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-B3YRnI4W.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-e0GbMwIr.js → swimlanes-5IMT3BWC-C0MubXTG.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-CXva4Ic9.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-CT3GFq89.js → timeline-definition-FHXFAJF6-CtxwSvFu.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-BJauJ0bm.js → treeView-QDETBFTQ-CXcwSjey.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-DCX7A-nx.js → treemap-6X3UGDF4-Uspgr-d1.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-D4dm2iTR.js → vennDiagram-L72KCM5P-tZamQQAQ.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-DklTDSId.js → wardley-OPB4EBWU-0_79c19P.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-CikP5hBd.js → wardleyDiagram-EHGQE667-uYmUsP66.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-FXuOAFpz.js → xychartDiagram-FW5EYKEG-BsOU7Wf7.js} +1 -1
- package/web-dist/index.html +2 -2
- package/runtime/cc-worker/agents/fable-high.md +0 -8
- package/runtime/cc-worker/agents/fable-low.md +0 -8
- package/runtime/cc-worker/agents/fable-max.md +0 -8
- package/runtime/cc-worker/agents/fable-medium.md +0 -8
- package/runtime/cc-worker/agents/fable-xhigh.md +0 -8
- package/runtime/cc-worker/agents/haiku.md +0 -7
- package/runtime/cc-worker/agents/opus-high.md +0 -8
- package/runtime/cc-worker/agents/opus-low.md +0 -8
- package/runtime/cc-worker/agents/opus-max.md +0 -8
- package/runtime/cc-worker/agents/opus-medium.md +0 -8
- package/runtime/cc-worker/agents/opus-xhigh.md +0 -8
- package/runtime/cc-worker/agents/sonnet-high.md +0 -8
- package/runtime/cc-worker/agents/sonnet-low.md +0 -8
- package/runtime/cc-worker/agents/sonnet-max.md +0 -8
- package/runtime/cc-worker/agents/sonnet-medium.md +0 -8
- package/runtime/cc-worker/agents/sonnet-xhigh.md +0 -8
- package/runtime/cc-worker/bin/browser-mcp-tools.json +0 -1192
- package/runtime/cc-worker/bin/browser-mcp.mjs +0 -730
- package/runtime/cc-worker/hooks/precompact-instructions.mjs +0 -133
- package/runtime/cc-worker/skills/waits/SKILL.md +0 -84
- package/web-dist/assets/architecture-TIHT7OUA-CTxVpl9_.js +0 -1
- package/web-dist/assets/channel-COS0Ygbp.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-Df5TLnrN.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-Df5TLnrN.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-DPVPOEaJ.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-BMIMgVYd.js +0 -1
- package/web-dist/assets/index-D6LsViUY.css +0 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-DfEpkrtJ.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-Csunejgu.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-BgRslbM_.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-6KcScVPX.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-jaJhlDbE.js +0 -8
package/package.json
CHANGED
|
@@ -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 keeps its own free-form scratch directory (.frizz/threads/<session-id>/). Supplies the 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 keeps its own free-form scratch directory (.frizz/threads/<session-id>/). Supplies the effort-only frizz:<effort> sub-agent profiles (frizz:low … frizz:max; the model rides the Agent tool's own parameter), 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",
|
|
@@ -1032,7 +1032,7 @@ Maintainer's call, verbatim: *"This is obviously something that should not be a
|
|
|
1032
1032
|
|
|
1033
1033
|
Three removals, one theme — Frizz's shipped worker contract states frizz MECHANICS, and everything else belongs to the repo or to the dispatch that starts the thread.
|
|
1034
1034
|
|
|
1035
|
-
- **`runtimeGate` (setting) + `RUNTIME_GATE` (prompt module) — gone.** The browser-QA loop (drive it in Chrome, screenshot into the handoff, escalate to an adversarial reviewer) was frizz's own engineering norm shipped to every worker Frizz dispatches anywhere. That is what `FRIZZ.md` / `CLAUDE.md` are for: `frizzConfigBlock` already injects a repo's own conventions into every spawn/adopt/resume, and this repo keeps its full browser-QA section there. What remains in the shipped contract is the repo-agnostic line that was already in the Quality bar — *"Verify behavior end-to-end before calling anything done."* `VISUAL_EVIDENCE` **stays**: it documents Frizz's guarded local-image proxy, a platform capability, not a QA policy. `chrome-devtools` also stays always-mounted — giving a worker a browser is a capability, not an opinion about when to use it.
|
|
1035
|
+
- **`runtimeGate` (setting) + `RUNTIME_GATE` (prompt module) — gone.** The browser-QA loop (drive it in Chrome, screenshot into the handoff, escalate to an adversarial reviewer) was frizz's own engineering norm shipped to every worker Frizz dispatches anywhere. That is what `FRIZZ.md` / `CLAUDE.md` are for: `frizzConfigBlock` already injects a repo's own conventions into every spawn/adopt/resume, and this repo keeps its full browser-QA section there. What remains in the shipped contract is the repo-agnostic line that was already in the Quality bar — *"Verify behavior end-to-end before calling anything done."* `VISUAL_EVIDENCE` **stays**: it documents Frizz's guarded local-image proxy, a platform capability, not a QA policy. `chrome-devtools` also stays always-mounted — giving a worker a browser is a capability, not an opinion about when to use it. **(Reversed 2026-08-26 — see the entry at the end of this file. The reasoning above survives one step further than it should have: mounting a browser is itself an opinion, and it was billed to every worker in tokens.)**
|
|
1036
1036
|
- **Model + Effort — removed from the settings drawer.** They are chosen per dispatch in the prompt box (`DispatchPreferences`, one profile per runtime); a second global copy only made it ambiguous which one applied. `Settings.model` / `Settings.effort` survive on the wire: `dispatch-preferences.ts` still seeds the composer's first-run profile from them and `dispatch.ts` still falls back to them for GitHub batch dispatch.
|
|
1037
1037
|
- **`autoResumeOnLimit` — gone; auto-resume is unconditional.** A thread cut off mid-turn by an exhausted subscription window always gets its own "continue" when the window rolls. `ThreadView.limitPause.autoResume` survives on the wire but is now purely a STALENESS verdict (`resolveLimitPause`): a fault old enough that the wake will never arrive stops promising one.
|
|
1038
1038
|
|
|
@@ -1105,9 +1105,38 @@ and "exists" stopped meaning "the worker wrote something".
|
|
|
1105
1105
|
|
|
1106
1106
|
Maintainer: *"Changing the model and effort in a prompt box. That should be remembered, that new setting, but it should also be applied globally across all projects."* It was remembered — `DispatchPreferences` has been durable since the composer grew the selector — but in the per-project SQLite `settings` row, so one server serving N projects showed N different profiles, and a choice made in one project was invisible in the next.
|
|
1107
1107
|
|
|
1108
|
-
- **The record now
|
|
1108
|
+
- **The record is now the `dispatchPreferences` entry of a machine-level key/value store** — `server/machine-config.ts`, one JSON object at `<data>/config.json` keyed by record name, each value validated by its owner's schema — resolved store → this project's stored row → the Settings-derived default. The context exposes `getDispatchPreferences`/`setDispatchPreference` closures over `home`, so the router never learns where the record is.
|
|
1109
|
+
- **The store is the machine-level counterpart of a project database's `settings` table, and it has two tenants from day one.** It first landed as a file of its own, `dispatch-preferences.json`; the maintainer asked *"surely we have some general-purpose system for storing bits of persistent configuration like this?"* — there was none at machine level (`settings.json`, `registry.json` and `cloud.json` each hand-roll a reader and writer), so the answer was to build it and move the machine settings (`font`, `notifications`, `localFileOpener`, `projectRail`) into it as the `settings` record. The old `settings.json` is read as a fallback and never written again; a settings reset removes both. `registry.json` and `cloud.json` were left as they are — each has its own lifecycle and locking story, and neither was the question.
|
|
1109
1110
|
- **No migration.** A project that chose a profile before the file existed keeps showing it from its row; the next selection, made anywhere, writes the file and is what every project opens on from then on. Every write still mirrors into the row, so an older server reading that database sees the same choice.
|
|
1110
1111
|
- **The whole record moved, including the per-runtime `permissionMode` inside it.** That field is vestigial — no `SetDispatchPreferenceInput` variant can set it and the composer's resolver never reads it (dispatch permission is decided server-side from Settings) — so nothing per-project was given up. Settings' own `permissionMode` stays per project, as before.
|
|
1111
1112
|
- **The web cache treats `["dispatchPreferencesGet"]` as machine-wide** (`lib/queryKeyScope.ts`), so the composer's optimistic write on one project is what a client-side switch paints on the next, rather than that project's last-seen copy for the beat before a refetch.
|
|
1112
1113
|
|
|
1113
1114
|
Verified on a real two-project stack (launcher + tenant on one server): a profile chosen through the tenant's RPC is what the launcher reads, and back; a per-project `settingsSet` on the launcher stayed invisible to the tenant, which is the control that the two prefixes reach different projects.
|
|
1115
|
+
## 2026-08-26: Frizz mounts NO browser — a `chrome-devtools` server is the project's to bring
|
|
1116
|
+
|
|
1117
|
+
Maintainer: *"Is the Chrome DevTool stuff something that frizz automatically injects? Why not just let the user bring that themselves? That's very confusing to me. I feel like there's a level of opinionation here that we don't really want."*
|
|
1118
|
+
|
|
1119
|
+
This reverses the 2026-08-03 line above (*"`chrome-devtools` also stays always-mounted — giving a worker a browser is a capability, not an opinion"*). The capability argument stopped holding once the bill was measured: the server's 29 tool schemas sat in the prefix of **every** worker session at **~6,400 tokens**, and most workers never open a page. A capability nobody asked for, charged per turn, is an opinion.
|
|
1120
|
+
|
|
1121
|
+
- **Both backends stopped injecting it.** Claude's inline `--mcp-config` (`claudeMcpConfig`, `dispatch.ts`) and codex's `-c mcp_servers.chrome-devtools=…` app-server override (`codex-mcp.ts`) now mount the unified `frizz` server and nothing else. Parity was the point of the original pairing and it is the point of the removal.
|
|
1122
|
+
- **The lazy proxy went with it.** `cc-worker/bin/browser-mcp.mjs` and its committed schema snapshot `browser-mcp-tools.json` existed only to make the always-on mount affordable in MEMORY (159 MB → ~17 MB per worker, 2026-08-19). With no mount there is nothing to proxy, so they are deleted along with `chromeDevtoolsMcpSpec` / `chromeDevtoolsMcpMount` / `resolveBrowserMcpScript` / `CHROME_DEVTOOLS_MCP`, `scripts/harvest-browser-mcp-tools.mjs`, and the worker-plugin closure entries that required them. The memory win it bought is now the token win.
|
|
1123
|
+
- **Nothing about a browser is banned — it is just not Frizz's to decide.** A project adds a `.mcp.json` (plus `enabledMcpjsonServers` in `.claude/settings.json`, so a headless worker is never blocked on the approval prompt); an operator runs `claude mcp add --scope user`. Frizz's `--mcp-config` ADDS to whatever the CLI discovered rather than replacing it (frizz never passes `--strict-mcp-config`), so both paths reach a dispatched worker untouched.
|
|
1124
|
+
- **This repo does exactly that, and that is the whole demonstration.** Frizz's own skills drive Chrome headless, so the repo root carries the `.mcp.json` that used to be injected — pinned `chrome-devtools-mcp@1.7.0 --experimentalPageIdRouting --headless --isolated --no-usage-statistics`, the same argv the deleted spec rendered. Verified end-to-end on a disposable stack: a worker dispatched in a scratch project with no config reported `frizz` tools and no browser; a worker dispatched in this repo reported the full `mcp__chrome-devtools__*` set with no permission prompt.
|
|
1125
|
+
- **What deliberately stayed.** The orphan reaper still reaps `chrome-devtools-mcp` processes by name (a browser the USER brought leaks exactly the same way), and the transcript still renders a `take_screenshot` image result. Neither depends on who mounted the server.
|
|
1126
|
+
|
|
1127
|
+
## 2026-08-26: Sub-agent profiles are effort-only, and the dispatch epilogue carries mechanics, not a handoff format
|
|
1128
|
+
|
|
1129
|
+
Follow-on to the browser decision above, from the same audit of what Frizz registers into a worker that the worker did not ask for. The maintainer's frame — *"a level of opinionation here that we don't really want"* — applied to two more registrations, and the frizz Goal had this thread decide them itself.
|
|
1130
|
+
|
|
1131
|
+
- **16 `frizz:<model>-<effort>` profiles → 5 `frizz:<effort>` ones.** The model×effort grid existed because the Agent tool once had no way to pin either; today its own `model` parameter overrides a profile's model, so the only knob a profile still has to carry is `effort`. The grid cost ~1,340 tokens of agent descriptions on every session, and those descriptions doubled as a routing doctrine ("Opus matches Fable and costs less", "Haiku for scripted harvest only") that no project asked for. `low` … `max` carry no model and inherit the worker's; Haiku, which takes no effort setting, is dispatched with `model: "haiku"` and no profile. The worker contract's Sub-agents section now states the two knobs and nothing about which tier deserves which task.
|
|
1132
|
+
- **The dispatch-hook epilogue kept only what a helper cannot discover.** Its first paragraph prescribed the shape of a helper's final message (status, files, SHA, evidence, caveats, next action); that is a handoff format, and it is gone — one sentence remains saying the final message is what the dispatcher reads. The rest stayed because each line is a mechanic learned from a real failure: the `SendMessage({to: "main"})` upward channel, the own-file rule for the scratch directory, no fan-out of its own unless asked, and the symlinked-`.output` wait-loop trap.
|
|
1133
|
+
- **Verified** by the live harness (`_live_broker_workerenv.mts`, now dispatching `frizz:low`): a real broker worker through the real server dispatched the profile and it ran.
|
|
1134
|
+
|
|
1135
|
+
## 2026-08-26: three more worker registrations deleted — the waits skill, the pre-compaction brief, and the toon nudge
|
|
1136
|
+
|
|
1137
|
+
Third pass of the same audit that removed the browser mount and the model×effort profile grid above, and the same test: does Frizz register this into every worker because the worker needs it, or because Frizz has an opinion?
|
|
1138
|
+
|
|
1139
|
+
- **`skills/waits` is DELETED.** Maintainer: *"I feel like the waits skill is being replaced now. I don't think we need that. We have our own system now for registering watchers and whatnot as tools."* The skill's whole job was teaching a worker how to hold a wait open without falling out of the board's Active band, and the durable half of that is now TOOLS — `mcp__frizz__watch_pr`, `mcp__frizz__timer`, `mcp__frizz__recurring_prompt` — which carry their own descriptions and need no playbook. What remains (a sub-agent owns the wait, `run_in_background` does not hold a rest, never fake a wait with a foreground sleep) is already stated once in the system-prompt contract, which is where a mechanical rule belongs.
|
|
1140
|
+
- **The portable monitors STAYED.** `skills/gh/scripts/{ci-watch,github-watch,review-watch}.mjs` are generated byte-for-byte from `monitors/` and are load-bearing for two other readers: the codex worker prompt names their absolute directory (`monitorScriptsDir()`, `dispatch.ts`, pinned by `dispatch.test.ts`), and `skills/gh` documents them as its declared-tooling fallback. Only the skill went.
|
|
1141
|
+
- **`hooks/precompact-instructions.mjs` is DELETED**, with both its `PreCompact` registrations. Maintainer: *"the pre-compaction instructions are probably too opinionated, entirely too opinionated."* It handed the summarizer an editorial brief about WHAT to preserve — plan, alternatives rejected, rationale, at high fidelity — which is a prescription about how someone else's work should be remembered. `scratchpad.mjs --mode=precompact` keeps both matchers: it only says the worker's scratch files exist and names their paths, which is mechanics.
|
|
1142
|
+
- **The `toon` bullet is gone from the seed's `⟦gh available⟧` block and from `skills/gh`.** Maintainer: *"It seems pretty opinionated to tell it to pipe through toon, given that toon is probably not installed on most machines. That might be over the line."* The original reasoning (`plans/github-integration.md` §9: worker-side yes, server-side no) was measured against THIS machine's toolchain; a `command -v toon` guard makes the advice safe but not less opinionated, and it spent prompt tokens on every authed session to describe a binary almost no repo has. The one raw-API recipe that piped through it now uses `--jq`, which ships with `gh`.
|
|
@@ -294,8 +294,9 @@ const WATCH_PR = {
|
|
|
294
294
|
type: "string",
|
|
295
295
|
description:
|
|
296
296
|
"Required for `add`. The pull request, as `owner/repo#123` or a GitHub PR URL. A ref that " +
|
|
297
|
-
"cannot be parsed
|
|
298
|
-
"no watcher, because you would come to rest
|
|
297
|
+
"cannot be parsed, or a PR the server's own `gh` cannot read, is REFUSED rather than stored — " +
|
|
298
|
+
"a watcher that can never fire is worse than no watcher, because you would come to rest " +
|
|
299
|
+
"believing you were covered. A refusal names the reason; a transient one is worth one retry.",
|
|
299
300
|
},
|
|
300
301
|
for: {
|
|
301
302
|
type: "string",
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
// foreground agent blocks the worker's turn; a human interjection orphans it).
|
|
7
7
|
// 2) STRIP `name`/`team_name` — setting either strands a nested dispatch (its result routes
|
|
8
8
|
// wrong and never returns cleanly), so scrub both silently.
|
|
9
|
-
// 3) AUTO-APPEND a
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
9
|
+
// 3) AUTO-APPEND a short ORCHESTRATION EPILOGUE carrying only what a helper cannot discover on
|
|
10
|
+
// its own: that its final message is the return value, the `SendMessage({to: "main"})` upward
|
|
11
|
+
// channel, the own-file rule for the scratch directory, no fan-out of its own unless asked, and
|
|
12
|
+
// how a helper it DID dispatch is collected. It carries no handoff format and no build, test,
|
|
13
|
+
// git or process policy — the maintainer had the handoff-format doctrine cut on 2026-08-26.
|
|
13
14
|
//
|
|
14
15
|
// WHY NESTING IS DEFAULT-OFF (2026-08-04, maintainer's call): the epilogue used to speak about a
|
|
15
16
|
// helper's own helper only in the conditional ("if you dispatch a helper of your own…"), which reads
|
|
@@ -45,10 +46,10 @@ import { readFileSync } from 'node:fs';
|
|
|
45
46
|
const EPILOGUE = `
|
|
46
47
|
|
|
47
48
|
---
|
|
48
|
-
[ORCHESTRATION EPILOGUE — auto-appended by the frizz worker dispatch hook] You are a helper sub-agent for a frizz worker. Your final message is the handoff
|
|
49
|
+
[ORCHESTRATION EPILOGUE — auto-appended by the frizz worker dispatch hook] You are a helper sub-agent for a frizz worker. Your final message is the handoff your dispatcher reads: say what you did, what you verified, and what remains.
|
|
49
50
|
The worker has a scratch directory (it will name the path if it wants your notes on disk). Write your OWN file there — never edit or delete a file another agent wrote, and never treat one shared document as yours to rewrite. Writing your own file there is Frizz coordination state, not a project deliverable or source edit, so it remains allowed when a delegated task limits your deliverable paths with phrases such as "write only <path>" or "do not modify the repo"; never classify it as unauthorized or roll it back. Other project files, including repository-root files, remain governed by your delegated authority; their location alone neither permits nor forbids editing. Do not edit other \`.frizz/\` state unless your prompt explicitly asks you to.
|
|
50
51
|
You have an upward channel while you work: \`SendMessage({to: "main", summary: "<5-10 words>", message: "…"})\` delivers to your dispatcher. Use it when the dispatcher acting before you finish could change the outcome—for example, when you hit an unresolved blocker, complete a milestone another task needs, or discover that your instructions should change. Do not use it for routine progress updates.
|
|
51
|
-
Do the work yourself: do NOT dispatch sub-agents of your own unless your dispatch prompt explicitly tells you to. You are already one prong of someone else's fan-out
|
|
52
|
+
Do the work yourself: do NOT dispatch sub-agents of your own unless your dispatch prompt explicitly tells you to. You are already one prong of someone else's fan-out; a slice that feels large is still yours to work through in your own turn.
|
|
52
53
|
If your prompt DOES ask you to dispatch a helper, its completion is delivered to you automatically. Never hand-roll a wait loop over a helper's transcript or \`.output\` path to decide whether it finished: that path is a SYMLINK, so \`stat\` without \`-L\` reports the link's own size (the length of its target path, ~150 bytes) and its frozen creation mtime, and the \`"type":"result"\` record is not reliably written — so a helper that is working hard reads as tiny, stale, and dead, and you will discard live work and redo it. Judge a helper only by its completion notification or the text it returns. Give it a \`description\` naming its narrower slice rather than restating your own, so the dispatch tree stays readable.`;
|
|
53
54
|
|
|
54
55
|
/** @param {unknown} obj @returns {never} */
|
|
@@ -58,14 +58,12 @@
|
|
|
58
58
|
{
|
|
59
59
|
"matcher": "auto",
|
|
60
60
|
"hooks": [
|
|
61
|
-
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/precompact-instructions.mjs\"" },
|
|
62
61
|
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scratchpad.mjs\" --mode=precompact" }
|
|
63
62
|
]
|
|
64
63
|
},
|
|
65
64
|
{
|
|
66
65
|
"matcher": "manual",
|
|
67
66
|
"hooks": [
|
|
68
|
-
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/precompact-instructions.mjs\"" },
|
|
69
67
|
{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/scratchpad.mjs\" --mode=precompact" }
|
|
70
68
|
]
|
|
71
69
|
}
|
|
@@ -280,9 +280,11 @@ if (mode === 'session-start') {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
// ── mode: precompact ─────────────────────────────────────────────────────────────────────────────
|
|
283
|
-
// PLAIN STDOUT —
|
|
284
|
-
// `
|
|
285
|
-
//
|
|
283
|
+
// PLAIN STDOUT — handed to the summarizer as its `Additional Instructions:`. cc's usual
|
|
284
|
+
// `hookSpecificOutput` JSON would be read as literal instructions instead. Worded as an ordinary
|
|
285
|
+
// editorial note: a summarizer REFUSES instructions that read like prompt-hijacking (DECISIONS.md).
|
|
286
|
+
// This is the ONLY PreCompact hook the plugin registers — `precompact-instructions.mjs`, which also
|
|
287
|
+
// steered the summarizer, was deleted on 2026-08-26 as too opinionated.
|
|
286
288
|
if (mode === 'precompact') {
|
|
287
289
|
const files = listScratch();
|
|
288
290
|
if (files.length === 0) process.exit(0);
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
// frontmatter, no status field — a worker SIGNALS through its final message (fences), and anything that
|
|
9
9
|
// must outlive its context window is an arrangement it makes for itself. This hook injects, on every
|
|
10
10
|
// session start (startup/resume/clear/compact):
|
|
11
|
-
// 1. `core` — a runtime
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// signal-at-rest anchor + a pointer to the system-prompt contract.
|
|
11
|
+
// 1. `core` — a runtime POINTER, not a copy of the contract: the full worker contract lives ONCE in
|
|
12
|
+
// the system prompt (workerPrompt.ts) the server injects at spawn. This carries only what a
|
|
13
|
+
// static system prompt can't: the runtime scratch-directory PATH, and a one-line pointer.
|
|
15
14
|
// 2. the SCRATCH DIRECTORY — `.frizz/threads/<session_id>/`, a folder the worker may use as it likes.
|
|
16
15
|
// 3. on `compact` — a short re-grounding (compaction drops the deep model + this orientation).
|
|
17
16
|
//
|
|
@@ -57,21 +56,23 @@ const scratch = sid
|
|
|
57
56
|
? '.frizz/threads/' + sid + '/'
|
|
58
57
|
: '.frizz/threads/<session-id>/';
|
|
59
58
|
|
|
60
|
-
// A RUNTIME
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
59
|
+
// A RUNTIME pointer, NOT a copy of the contract. The full worker contract (signal fences,
|
|
60
|
+
// scratch-directory rules, sub-agent rules, the question handback, the stop criterion) lives ONCE in
|
|
61
|
+
// the system prompt frizz injects at spawn (workerPrompt.ts / loadWorkerPrompt) — re-applied on every
|
|
62
|
+
// resume, and it survives compaction. This hook adds only what a static system prompt CANNOT carry:
|
|
63
|
+
// the runtime-derived scratch-directory PATH, plus (below) the compaction re-read nudge and the
|
|
64
|
+
// auth-gated gh guidance.
|
|
65
|
+
//
|
|
66
|
+
// It used to restate the fence protocol, the stop criterion and the autonomy rule in full — ~4.4 KB
|
|
67
|
+
// (~1,100 tokens) on every startup, resume, clear AND compact, all of it already in the 42 KB system
|
|
68
|
+
// prompt. Trimmed 2026-08-26 (maintainer: "Definitely trim the session seed hook if it's fully
|
|
69
|
+
// repetitive") as part of cutting the per-session token overhead Frizz adds over a plain TUI session.
|
|
66
70
|
const core =
|
|
67
|
-
'⟦frizz worker contract⟧ You are a frizz WORKER driving EXACTLY ONE effort. Your FULL operating contract — the end-of-turn signal fences, scratch-directory rules, sub-agent rules,
|
|
68
|
-
'SCRATCH DIRECTORY (OPTIONAL): `' + scratch + '` — a folder kept FOR YOU
|
|
69
|
-
'DO NOT REST WHILE THE INSTRUCTION HAS PARTS LEFT — finish them in THIS turn; a milestone, a green test run and a long turn are none of them stopping points, and announcing the next step or writing it into a scratch file is not doing it.\n' +
|
|
70
|
-
'ALWAYS SIGN OFF WITH A FENCE, per the fence rules in your system prompt. A rest with NO fence is not a handoff — it is an item nobody can triage, and frizz will tell you so. ```done only when the effort\'s real work is COMPLETE (code LANDED on the mainline — an open PR is NOT done, park it on ```awaiting until it MERGES) and is a DISMISSAL (its card files the thread away where nobody looks again), so if the thread points at future work AT ALL — a pre-fix investigation, a live code-change discussion, follow-up work you DISCOVERED even when someone else will do it — ask a ```question instead, and uncertain is not done; a verdict that ends in something the HUMAN must now do (post this comment, merge or decline, pick one of these) is a ```question carrying your recommendation as option A, never a done card, because a draft you wrote but did not send is filed away with the thread; when your OWN mandate is complete and what is left is a separable effort, DO it first — dispatch a sub-agent, whose result comes BACK to you, so it lands on YOUR card — and ASK second; mcp__frizz__spawn_thread is the LAST resort, for work that genuinely cannot ride on your card, because a spawned thread reports only to the human and nothing it learns returns to you or its siblings; the ONE exception is a planning session whose plan file is fully written and persisted, because that artifact outlives the thread; ```awaiting parks your OWN background work — a shell, a sub-agent, an armed timer, a registered PR watcher — never CI/releases/merge progression (those stay ACTIVE), and never a person: waiting on a person is a ```question; ```question is the operator ask. Waiting on your own background shell? Your shells and sub-agents are watched AUTOMATICALLY — frizz wakes you when one finishes, fence or no fence. NAME it in the fence\'s YAML frontmatter anyway — plural keys taking lists (`shells: [<id>]`, `agents:`, `timers:`, `prs:`) plus a required `for:` duration, then `---` and your prose — and rest: that is what lets you stop without frizz asking you for a handoff, and what shows the human what you are waiting for. Frizz checks every name against what you actually have running. Keep the write-up SHORT: 1-3 sentences, then bullets starting with a **bolded verb phrase**. The fence and the prose above it are TWO SURFACES, not one message written twice — the card is the ledger of what shipped, the prose is only what a ledger cannot hold, and a sentence that would read the same in either belongs in exactly one. And a done message says what HAPPENED: delete every dangling "one thing to carry forward" or "a follow-up could" — do it, spawn it onto its own card, ask about it, or DROP it, and if it is not worth a card it is not worth a sentence.\n' +
|
|
71
|
-
'DECIDE rather than ask: anything derivable from the code, the conventions, or ordinary engineering judgment is YOURS to settle — asking permission to do the work you were dispatched to do is not a question, it is the job. Reserve the operator for the irreversible and the genuinely human-owned.';
|
|
71
|
+
'⟦frizz worker contract⟧ You are a frizz WORKER driving EXACTLY ONE effort. Your FULL operating contract — the end-of-turn signal fences (```done / ```awaiting / ```question), the scratch-directory rules, the sub-agent rules, the question handback and the stop criterion — lives in your SYSTEM PROMPT; follow it there. Always sign off with a fence.\n' +
|
|
72
|
+
'SCRATCH DIRECTORY (OPTIONAL): `' + scratch + '` — a folder kept FOR YOU, nothing in it read automatically, never a substitute for doing the work. Give each sub-agent its OWN file rather than a shared one.';
|
|
72
73
|
|
|
73
74
|
const grounding =
|
|
74
|
-
'⟦frizz worker re-grounding (post-compaction)⟧ Context was just compacted. You are still the frizz worker for effort `' + thread + '` — read whatever you left yourself in `' + scratch + '` NOW to recover your working state and to-do list before asserting anything, and re-read any code before claiming how it is structured.
|
|
75
|
+
'⟦frizz worker re-grounding (post-compaction)⟧ Context was just compacted. You are still the frizz worker for effort `' + thread + '` — read whatever you left yourself in `' + scratch + '` NOW to recover your working state and to-do list before asserting anything, and re-read any code before claiming how it is structured. Your system prompt still carries the full contract; sign off with a fence as it says.';
|
|
75
76
|
|
|
76
77
|
// AUTH-GATED gh guidance — teach the worker to use `gh` well, but ONLY when signed in.
|
|
77
78
|
// Shell `gh auth status --active`: exit 0 = an active gh account is authenticated. The whole gate is
|
|
@@ -84,7 +85,6 @@ const ghBlock =
|
|
|
84
85
|
'• READ freely: `gh issue view N -R OWNER/REPO --comments`, `gh pr view N`, `gh pr diff N`, `gh pr checks N`, `gh run list`/`gh run view`, `gh api repos/OWNER/REPO/…`. Prefer `--json <fields>` over scraping human text.\n' +
|
|
85
86
|
'• SEARCH across the repo (and GitHub) with `gh search issues`/`gh search prs` when hunting related work, duplicates, or prior art.\n' +
|
|
86
87
|
'• READ-ONLY BOUNDARY: never comment, label, assign, close, review, approve, or merge — no mutation of any kind — UNLESS the human explicitly asks in this session. Default to producing your findings/review as your final message, not as a GitHub post.\n' +
|
|
87
|
-
'• TOON: pipe LARGE, FLAT `gh … --json` output through `toon` when `command -v toon` finds it. Skip it when unavailable, for tiny payloads, or for deeply-nested output — the savings are noise and nesting defeats tabularization.\n' +
|
|
88
88
|
'Load the `frizz:gh` skill for the full playbook (recipes + explicit project-local monitor selection + native Monitor/background-Bash CI/PR watches).';
|
|
89
89
|
|
|
90
90
|
let ghAuthed = false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gh
|
|
3
|
-
description: The gh-CLI playbook for a frizz worker signed into GitHub (invoke as frizz:gh). Load this whenever your effort touches GitHub — reading or triaging an issue or PR, reviewing a diff, checking CI/release status, or searching issues/PRs — to use `gh` eagerly and correctly: the read-vs-write boundary (never comment/label/close/merge unless the human asks),
|
|
4
|
-
version: 0.1.
|
|
3
|
+
description: The gh-CLI playbook for a frizz worker signed into GitHub (invoke as frizz:gh). Load this whenever your effort touches GitHub — reading or triaging an issue or PR, reviewing a diff, checking CI/release status, or searching issues/PRs — to use `gh` eagerly and correctly: the read-vs-write boundary (never comment/label/close/merge unless the human asks), concrete read recipes, and active Monitor/background-Bash CI/PR watches. Only meaningful when you are signed in (`gh auth status --active` exit 0); the session-seed hook injects a pointer here when you are.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
metadata:
|
|
6
6
|
internal: true
|
|
7
7
|
---
|
|
@@ -10,7 +10,7 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
You are a **frizz worker** and you are **signed into the `gh` CLI in a GitHub repo** (the session-seed hook confirmed `gh auth status --active` before pointing you here). `gh` is the fastest path to issue / PR / CI / release context — reach for it before guessing, and prefer it over scraping the web UI or reasoning from memory.
|
|
12
12
|
|
|
13
|
-
This skill is the full playbook the injected `⟦gh available⟧` block summarizes: the **read-vs-write boundary**,
|
|
13
|
+
This skill is the full playbook the injected `⟦gh available⟧` block summarizes: the **read-vs-write boundary**, concrete **read recipes**, and how to keep a **CI/PR watch** active until the next actionable event.
|
|
14
14
|
|
|
15
15
|
## The one hard rule — READ freely, WRITE only when asked
|
|
16
16
|
|
|
@@ -23,20 +23,6 @@ This skill is the full playbook the injected `⟦gh available⟧` block summariz
|
|
|
23
23
|
|
|
24
24
|
There is no server-side enforcement of this; the boundary is yours to hold.
|
|
25
25
|
|
|
26
|
-
## toon — pipe LARGE, FLAT gh JSON through the shim
|
|
27
|
-
|
|
28
|
-
`toon` (Token-Oriented Object Notation) losslessly re-encodes JSON ~30–40% smaller for LLM context. Use it only when a `gh … --json` result you're reading into YOUR context is **large and flat** (a list page: `gh issue list`, `gh pr list`, `gh search`, `gh api` list endpoints) and `command -v toon` succeeds. It is optional: do not install it or assume a home-directory-specific location.
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
if command -v toon >/dev/null 2>&1; then
|
|
32
|
-
gh issue list -R OWNER/REPO --json number,title,url,updatedAt --limit 50 | toon
|
|
33
|
-
else
|
|
34
|
-
gh issue list -R OWNER/REPO --json number,title,url,updatedAt --limit 50
|
|
35
|
-
fi
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
**Skip toon** for tiny payloads (a handful of fields, one item) and for **deeply-nested** JSON (`reactionGroups`, review threads, nested files) — nesting defeats tabularization, so the savings collapse to noise and you add a parse tax for yourself. A single `gh pr view N --json …` is small — read it raw.
|
|
39
|
-
|
|
40
26
|
## Read recipes
|
|
41
27
|
|
|
42
28
|
Always scope with `-R OWNER/REPO` so a command is dir-independent, and prefer `--json <fields>` (+ `-q <jq>`) so you pull exactly what you need.
|
|
@@ -52,7 +38,7 @@ gh issue list -R OWNER/REPO --search "sort:reactions-desc is:open" --json number
|
|
|
52
38
|
**PRs + diffs**
|
|
53
39
|
```bash
|
|
54
40
|
gh pr view N -R OWNER/REPO --json title,body,state,labels,files,additions,deletions,url
|
|
55
|
-
gh pr diff N -R OWNER/REPO # the unified diff
|
|
41
|
+
gh pr diff N -R OWNER/REPO # the unified diff
|
|
56
42
|
gh pr checks N -R OWNER/REPO # CI check rollup for the PR
|
|
57
43
|
gh pr view N -R OWNER/REPO --comments # review threads + conversation
|
|
58
44
|
```
|
|
@@ -97,7 +83,7 @@ Use search to find duplicates, related work, and prior art before you conclude s
|
|
|
97
83
|
**Raw API** for anything the porcelain doesn't cover:
|
|
98
84
|
```bash
|
|
99
85
|
gh api repos/OWNER/REPO/commits/SHA/check-runs --jq '.check_runs[] | {name, conclusion}'
|
|
100
|
-
gh api "repos/OWNER/REPO/issues?state=open&labels=bug&per_page=50" | {
|
|
86
|
+
gh api "repos/OWNER/REPO/issues?state=open&labels=bug&per_page=50" --jq '.[] | {number, title, html_url}'
|
|
101
87
|
```
|
|
102
88
|
|
|
103
89
|
## Keep GitHub automation active
|