optbrew 0.1.2 → 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 (119) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/.codex-plugin/plugin.json +2 -2
  4. package/AGENT_INSTALL.md +94 -0
  5. package/CHANGELOG.md +74 -1
  6. package/README.ko.md +129 -105
  7. package/README.md +129 -105
  8. package/THIRD_PARTY_NOTICES.md +88 -0
  9. package/docs/platforms.md +45 -8
  10. package/docs/release.md +37 -4
  11. package/lib/cli.mjs +5 -2
  12. package/lib/install.mjs +2 -1
  13. package/lib/records.mjs +2 -1
  14. package/lib/transaction.mjs +12 -5
  15. package/lib/update.mjs +3 -2
  16. package/package.json +29 -9
  17. package/plugin.json +2 -2
  18. package/skills/.claude-plugin/icon.png +0 -0
  19. package/skills/.claude-plugin/plugin.json +23 -0
  20. package/skills/README.md +27 -0
  21. package/skills/optbrew/SKILL.md +223 -8
  22. package/skills/optbrew/THIRD_PARTY_NOTICES.md +88 -0
  23. package/skills/optbrew/bundle-manifest.json +409 -49
  24. package/skills/optbrew/modules/naver-searchadvisor/scripts/audit.mjs +4 -4
  25. package/skills/optbrew/references/ai-crawlers.json +1 -1
  26. package/skills/optbrew/references/ai-crawlers.md +1 -1
  27. package/skills/optbrew/references/api.md +6 -4
  28. package/skills/optbrew/references/check-registry.json +16 -16
  29. package/skills/optbrew/references/chrome-paths.json +31 -0
  30. package/skills/optbrew/references/endpoints.json +10 -0
  31. package/skills/optbrew/references/harness-signals.json +5 -0
  32. package/skills/optbrew/references/intake.md +76 -5
  33. package/skills/optbrew/references/judging.md +233 -0
  34. package/skills/optbrew/references/limits.json +26 -0
  35. package/skills/optbrew/references/measurement.md +1 -1
  36. package/skills/optbrew/references/messages.ko.json +170 -0
  37. package/skills/optbrew/references/report.md +18 -6
  38. package/skills/optbrew/references/routing.md +2 -2
  39. package/skills/optbrew/references/runbooks/anthropic-api-key.md +34 -0
  40. package/skills/optbrew/references/runbooks/chrome-install.md +56 -0
  41. package/skills/optbrew/references/runbooks/cwv-site-collection.md +38 -0
  42. package/skills/optbrew/references/runbooks/google-api-key.md +51 -0
  43. package/skills/optbrew/references/runbooks/gsc-export.md +32 -0
  44. package/skills/optbrew/references/runbooks/index.json +18 -0
  45. package/skills/optbrew/references/runbooks/key-set-claude-cloud.md +32 -0
  46. package/skills/optbrew/references/runbooks/key-set-codex.md +33 -0
  47. package/skills/optbrew/references/runbooks/key-set-local.md +40 -0
  48. package/skills/optbrew/references/runbooks/naver-searchadvisor-export.md +32 -0
  49. package/skills/optbrew/references/runbooks/network-claude-cloud-custom.md +33 -0
  50. package/skills/optbrew/references/runbooks/network-codex-approval.md +26 -0
  51. package/skills/optbrew/references/runbooks/network-codex-config.md +36 -0
  52. package/skills/optbrew/references/runbooks/seranking.md +38 -0
  53. package/skills/optbrew/references/schemas/contract.schema.json +42 -15
  54. package/skills/optbrew/references/scoring.md +40 -5
  55. package/skills/optbrew/references/source-analysis.md +40 -0
  56. package/skills/optbrew/references/versions.json +9 -0
  57. package/skills/optbrew/scripts/adapters/anthropic.mjs +5 -5
  58. package/skills/optbrew/scripts/adapters/imports.mjs +138 -1
  59. package/skills/optbrew/scripts/audit.mjs +10 -96
  60. package/skills/optbrew/scripts/cli.mjs +5 -2
  61. package/skills/optbrew/scripts/core/bundle.mjs +30 -13
  62. package/skills/optbrew/scripts/core/capabilities.mjs +8 -4
  63. package/skills/optbrew/scripts/core/cdp.mjs +105 -0
  64. package/skills/optbrew/scripts/core/checks/canonical-consistency.mjs +56 -0
  65. package/skills/optbrew/scripts/core/checks/cwv-field.mjs +77 -0
  66. package/skills/optbrew/scripts/core/checks/discovery.mjs +43 -0
  67. package/skills/optbrew/scripts/core/checks/document-title.mjs +62 -0
  68. package/skills/optbrew/scripts/core/checks/entity-identity.mjs +31 -0
  69. package/skills/optbrew/scripts/core/checks/fact-consistency.mjs +31 -0
  70. package/skills/optbrew/scripts/core/checks/fetch-response.mjs +18 -0
  71. package/skills/optbrew/scripts/core/checks/index-policy.mjs +16 -0
  72. package/skills/optbrew/scripts/core/checks/index.mjs +18 -0
  73. package/skills/optbrew/scripts/core/checks/internal-navigation.mjs +67 -0
  74. package/skills/optbrew/scripts/core/checks/locale-links.mjs +55 -0
  75. package/skills/optbrew/scripts/core/checks/naver-markup.mjs +21 -0
  76. package/skills/optbrew/scripts/core/checks/observation.mjs +37 -0
  77. package/skills/optbrew/scripts/core/checks/prepare.mjs +103 -0
  78. package/skills/optbrew/scripts/core/checks/render-content.mjs +104 -0
  79. package/skills/optbrew/scripts/core/checks/search-crawl-policy.mjs +29 -0
  80. package/skills/optbrew/scripts/core/checks/structured-data-truth.mjs +46 -0
  81. package/skills/optbrew/scripts/core/chrome-temp.mjs +68 -0
  82. package/skills/optbrew/scripts/core/chrome.mjs +546 -0
  83. package/skills/optbrew/scripts/core/collector.mjs +65 -59
  84. package/skills/optbrew/scripts/core/compare.mjs +18 -1
  85. package/skills/optbrew/scripts/core/config.mjs +31 -0
  86. package/skills/optbrew/scripts/core/contracts.mjs +31 -2
  87. package/skills/optbrew/scripts/core/cwv.mjs +100 -0
  88. package/skills/optbrew/scripts/core/derive.mjs +10 -161
  89. package/skills/optbrew/scripts/core/evidence-store.mjs +112 -0
  90. package/skills/optbrew/scripts/core/facts.mjs +203 -19
  91. package/skills/optbrew/scripts/core/findings.mjs +19 -1
  92. package/skills/optbrew/scripts/core/html.mjs +41 -3
  93. package/skills/optbrew/scripts/core/index-targets.mjs +118 -0
  94. package/skills/optbrew/scripts/core/judgments.mjs +675 -0
  95. package/skills/optbrew/scripts/core/keys.mjs +86 -0
  96. package/skills/optbrew/scripts/core/link-graph.mjs +93 -0
  97. package/skills/optbrew/scripts/core/messages.mjs +23 -0
  98. package/skills/optbrew/scripts/core/metrics.mjs +4 -2
  99. package/skills/optbrew/scripts/core/migration.mjs +37 -0
  100. package/skills/optbrew/scripts/core/page-select.mjs +136 -0
  101. package/skills/optbrew/scripts/core/probe.mjs +83 -0
  102. package/skills/optbrew/scripts/core/protocol.mjs +38 -14
  103. package/skills/optbrew/scripts/core/render.mjs +160 -0
  104. package/skills/optbrew/scripts/core/report-compose.mjs +377 -0
  105. package/skills/optbrew/scripts/core/report-html.mjs +198 -0
  106. package/skills/optbrew/scripts/core/report-page.mjs +14 -0
  107. package/skills/optbrew/scripts/core/report.mjs +357 -131
  108. package/skills/optbrew/scripts/core/runbooks.mjs +63 -0
  109. package/skills/optbrew/scripts/core/scope.mjs +23 -5
  110. package/skills/optbrew/scripts/core/score.mjs +12 -4
  111. package/skills/optbrew/scripts/core/secrets.mjs +2 -0
  112. package/skills/optbrew/scripts/core/stages.mjs +694 -0
  113. package/skills/optbrew/scripts/core/transport.mjs +157 -0
  114. package/skills/optbrew/scripts/core/weights.mjs +2 -1
  115. package/skills/optbrew/scripts/key.mjs +90 -0
  116. package/skills/optbrew/scripts/preflight.mjs +176 -0
  117. package/skills/optbrew/scripts/run.mjs +81 -0
  118. package/skills/optbrew/source-lock.json +1 -1
  119. package/source-lock.json +1 -1
package/README.md CHANGED
@@ -1,149 +1,173 @@
1
1
  # optbrew
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/optbrew.svg)](https://www.npmjs.com/package/optbrew)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
+
3
6
  [한국어](README.ko.md)
4
7
 
5
- Optbrew is a local skill and CLI for checking a site's search readiness, making approved local changes, and comparing evidence before and after. It combines five pinned source bundles—mblode SEO, Naver Search Advisor, Firecrawl SEO Audit, Magnus SEO, and SE Ranking SEO—with seven selected marketing guides. One top-level `SKILL.md` routes to the included guides. The bundle works from its pinned files; it does not fetch a moving upstream revision during a run.
8
+ A search-readiness audit skill for coding agents. optbrew checks a site for Google, Naver and AI answer engines, fixes the local files you approve, checks again under the same conditions, and writes a scored report built from replayable evidence.
9
+
10
+ - One skill for five profiles: **SEO**, **NEO** (Naver), **AEO**, **GEO** and **LLMO**.
11
+ - One call for a beginner: answer one set of start questions, then the agent runs the whole audit and hands you an HTML report.
12
+ - Five pinned audit guide bundles merged into 22 check families. An issue that several guides report is counted once.
13
+ - Every verdict in the report can be recomputed from the raw responses that were collected and hashed.
14
+ - No headline score when the evidence is thin: below 80% coverage the report shows the measured part and its bounds.
15
+ - Works with Codex, Claude Code, Cursor, OpenCode and Pi. Scoring and reports need no API account.
16
+
17
+ ## Why optbrew
18
+
19
+ Being found now means three different things: ranking in Google, showing in Naver, and being cited in AI answers. Each has its own guides, and the guides overlap and disagree. An agent asked to "improve SEO" usually picks one checklist, edits files, and reports success without proof.
20
+
21
+ optbrew gives the agent one workflow and one scoring rule for all five profiles. It counts what it measured, marks what it could not measure as unknown instead of passing it, and keeps a local fix separate from a production result. A high readiness score is not a promise of traffic or citations, and the report says so.
6
22
 
7
- The CLI can calculate a score and write a report from stored JSON without an API account. A site audit needs a declared target and scope. Publication, search engine submission, remote site changes, and paid calls require separate authority. Read [platform support](docs/platforms.md) for the difference between installing a file and confirming that a host invoked it.
23
+ ## How it works
24
+
25
+ 1. **Ask.** You give the URL. optbrew reads the start page, the sitemap and your setup (Chrome, a Google key, network access). Then it sends one message with the start questions: your guidance level, the goal, the questions people search for, the facts it read from the site, and the page limit. The questions, the guides and the report are in Korean. Reply with an answer for each number, or just "시작" (start) to take the defaults. If one thing blocks the audit, such as a network that is closed, you get one setup guide first. Up to three more guides appear as one-line offers; you open one by answering with its word, such as "키" (key).
26
+ 2. **Audit.** One command collects the pages, renders up to 10 of them (one of each kind of page) in a headless Chrome of its own, measures speed and runs the code checks. It audits pages from the sitemap and from links on the start page, up to your limit: 50 pages by default, up to 200 if you raise it. The limit counts every request, so redirects and the robots and sitemap files use part of it. It follows a redirect to the `www` or `https` twin of your address and says so in the report. It stores every response with its hash.
27
+ 3. **Judge.** The agent reads the page text that code cannot judge, such as claims, answer clarity and freshness. It cites the sentences it relied on. A second call of the same command checks that the cited text exists in the evidence, then scores.
28
+ 4. **Report.** You get three files with the same content: `report.html` (open this one; it is a single self-contained file), `report.md` and `report.json`. The text is in Korean. Each problem has one fix with the number of pages it affects. A numbered list of steps tells you how to fill each blank, such as a missing Google key. Blanks are shown as unknown, never as a pass.
29
+ 5. **Fix and re-check (optional).** The agent proposes changes to local files. Nothing is edited, deployed or submitted without your approval. After you deploy, the same collection runs again under the same conditions, so the before and after are comparable.
30
+
31
+ What the script measures by itself, and what still needs the guides and the agent's judgment:
32
+
33
+ | Profile | Target | Measured by the script | Left to judgment |
34
+ |---|---|---|---|
35
+ | SEO | Google and web search | Fetch status, `noindex` in meta and `X-Robots-Tag`, titles, robots.txt for Googlebot, canonical, redirect chains, discovery through links and sitemap, JSON-LD syntax | Content quality and intent fit |
36
+ | NEO | Naver | robots.txt for Yeti, Open Graph, description, canonical, viewport, title repetition, blocked CSS or JS | Naver-specific content guidance |
37
+ | AEO, GEO | Answer engines and AI search | robots.txt for the AI search bots in [ai-crawlers.md](skills/optbrew/references/ai-crawlers.md) (training bots are never scored) | Answer structure, claims, authorship, freshness |
38
+ | LLMO | How models describe you | Whether name, address, phone and founding year agree across pages, and whether the pages describe one business | Whether those facts are true |
39
+ | All | Speed and scripts | Whether the text still shows after JavaScript runs in Chrome. Field Core Web Vitals (LCP, INP, CLS) from Google's Chrome UX Report and PageSpeed Insights | Nothing. The Chrome lab values are shown as a run condition and are never scored |
40
+
41
+ Engine-specific checks run for the engines you name as targets. Name the AI answer engines you care about, such as ChatGPT, Claude or Perplexity. Naver is added on its own when the goal names it, you give a Naver export, or the site is Korean (`lang="ko"` or an address ending in `.kr`). Google is always a target. The scoring rule is in [scoring.md](skills/optbrew/references/scoring.md). The 80% coverage threshold is optbrew's own rule, not a search engine standard.
8
42
 
9
43
  ## Install
10
44
 
11
- Requires Node.js 22 or later. The internal Python audit utilities need Python 3.10 or later; missing Python leaves those utilities unrun. From this checkout, first inspect the targets in an isolated project directory named `site`:
45
+ Requires [Node.js](https://nodejs.org) 22 or later. Python 3.10 or later is optional; without it, the internal Python audit utilities stay unrun. Pick one of the five methods. The examples install for Codex and Claude Code at user level; the agent IDs are `codex`, `claude-code`, `cursor`, `opencode` and `pi`.
12
46
 
13
- Bash and PowerShell use the same commands:
47
+ In Windows PowerShell, if `npx` or `optbrew` reports that running scripts is disabled, type `npx.cmd` or `optbrew.cmd` instead.
14
48
 
15
- ```text
16
- node bin/optbrew.mjs install --agents codex,claude-code,cursor,opencode,pi --scope project --project ./site --strategy copy --dry-run --json
17
- node bin/optbrew.mjs install --agents codex,claude-code,cursor,opencode,pi --scope project --project ./site --strategy copy --json
18
- node bin/optbrew.mjs doctor --agents codex,claude-code,cursor,opencode,pi --scope project --project ./site --json
49
+ ### 1. npm
50
+
51
+ ```bash
52
+ npm install -g optbrew@0.2.0
53
+ optbrew install --agents codex,claude-code --scope user --dry-run
54
+ optbrew install --agents codex,claude-code --scope user
55
+ optbrew doctor --agents codex,claude-code --scope user
19
56
  ```
20
57
 
21
- Create `site` first and run these commands from the repository root. `--strategy link` is the default; `copy` also works when links are unavailable. The managed record lives under that project's `.optbrew/install`. For one host, replace the comma-separated list with its exact ID: `codex`, `claude-code`, `cursor`, `opencode`, or `pi`. Use `--scope user` only when you intend to install into user-level host directories. The install command checks the bundle manifest and refuses to replace an unmanaged target.
58
+ The dry run prints the folders it will write. `doctor` checks the files and their hashes.
22
59
 
23
- To get the checkout, clone `https://github.com/nowwcastle-sudo/optbrew` and run the commands above from its root. `npm install -g optbrew` installs the same CLI as an `optbrew` command; replace `node bin/optbrew.mjs` with `optbrew` in the commands above. Native host distribution and the ZIP path are described in [platform support](docs/platforms.md).
60
+ ### 2. npx
24
61
 
25
- ## First use
62
+ Runs the same CLI without a global install:
26
63
 
27
- Ask the host to use optbrew with the target URL, goal, site ownership or access, allowed local changes, and available evidence. For a local audit, declare the URL scope before collection. The default collection ceilings are 50 URLs, depth 3, and concurrency 2. A new fetch starts only while fewer requests than the limit have been made, and a redirect chain that has started is completed; a chain follows at most min(10, `max_urls`) redirects, so the requests beyond the limit are at most concurrency x min(10, `max_urls`), which is 20 with the defaults; private addresses need an explicit local target. The workflow records raw evidence, readiness observations, local changes, and follow-up checks. It does not infer a site's production result from a passing local test.
64
+ ```bash
65
+ npx optbrew@0.2.0 install --agents codex,claude-code --scope user
66
+ npx optbrew@0.2.0 doctor --agents codex,claude-code --scope user
67
+ ```
28
68
 
29
- The examples below replay bundled synthetic fixtures. They make no provider call. Run them from the checkout root and choose fresh output paths:
69
+ ### 3. PowerShell (Windows)
30
70
 
31
- Bash and PowerShell use the same commands:
71
+ ```powershell
72
+ irm https://raw.githubusercontent.com/nowwcastle-sudo/optbrew/v0.2.0/install.ps1 | iex
73
+ ```
32
74
 
33
- ```text
34
- node bin/optbrew.mjs score --input ./before.json --output ./score.json
35
- node bin/optbrew.mjs compare --before ./before.json --after ./after.json --output ./comparison.json
36
- node bin/optbrew.mjs report --input ./remote-only.json --output-dir ./report-output
75
+ The script is pinned to this release. It checks Node.js, shows the target folders, installs for Codex and Claude Code, and stops with an error if `doctor` finds a problem. To read it first, or to choose agents or a project folder:
76
+
77
+ ```powershell
78
+ irm https://raw.githubusercontent.com/nowwcastle-sudo/optbrew/v0.2.0/install.ps1 -OutFile install.ps1
79
+ powershell -ExecutionPolicy Bypass -File .\install.ps1 -Agents codex,claude-code,cursor
37
80
  ```
38
81
 
39
- For those literal commands, copy `tests/fixtures/scoring/before.json` and `after.json` into the current directory, and copy `tests/fixtures/reports/remote-only.json` plus its sibling evidence files into the current directory. For real work, pass your own validated `ScoreInput` or `ReportPacket` paths. See [scoring](skills/optbrew/references/scoring.md), [measurement](skills/optbrew/references/measurement.md), and [report evidence](skills/optbrew/references/report.md) for the contracts.
82
+ Add `-Scope project -Project C:\path\to\site` to install into one project.
40
83
 
41
- ## Score and report
84
+ ### 4. Plugin
42
85
 
43
- The five optbrew readiness profiles are SEO, NEO when Naver is a target, AEO, GEO, and LLMO. The 22 unique check families are counted once even when several guides find the same issue. An unknown applicable check remains in the denominator; an evidenced `not_applicable` check is excluded. The result includes score, measured coverage, missing-data bounds, blockers, and unresolved core checks. The 80% coverage threshold is an optbrew rule, not a search engine standard. A high readiness score does not prove indexing, traffic, citations, accuracy, conversions, or revenue.
86
+ Claude Code:
44
87
 
45
- What the audit script observes by itself, from the responses it collected: fetch status; indexing directives in meta tags and `X-Robots-Tag`, scoped to each target engine; missing or duplicated titles; robots.txt access per declared engine (Googlebot, Yeti and the AI search bots in [`ai-crawlers.md`](skills/optbrew/references/ai-crawlers.md); training bots are never scored); canonical target and redirect-chain length; discovery through links or a declared sitemap; JSON-LD syntax; Naver markup (Open Graph, description, canonical, viewport, title repetition, blocked CSS or JS); and cross-page consistency of name, address, phone and founding year. SEO and NEO therefore have scripted access, indexing and markup checks. AEO and GEO stay readiness audits: answer structure, claims, authorship and freshness still need the guides and agent judgment. LLMO gets a cross-page consistency check, which shows disagreement between pages but does not prove a fact is true. A seeded-defect test and its limits are in `docs/validation/detection-0.1.2.md` (repository only).
88
+ ```bash
89
+ claude plugin marketplace add nowwcastle-sudo/optbrew
90
+ claude plugin install optbrew@optbrew
91
+ ```
92
+
93
+ Codex:
46
94
 
47
- When measured coverage is below 80%, the report withholds the single headline number and shows the measured subset with its bounds. Each headline score is printed with its coverage.
95
+ ```bash
96
+ codex plugin marketplace add nowwcastle-sudo/optbrew
97
+ codex plugin add optbrew@optbrew
98
+ ```
48
99
 
49
- The report keeps readiness, remedies, actual outcomes, and remaining work in separate tables. Actual outcomes need owner exports or a fixed AI question panel. A normal outcome comparison uses two complete, adjacent 28-day windows with matching definitions and filters. A local edit remains local until deployment and a production observation have their own evidence.
100
+ claude.ai, Claude Desktop and Cowork: open Customize > Plugins, choose Add > Add marketplace, enter `nowwcastle-sudo/optbrew`, then add `optbrew`.
50
101
 
51
- ## APIs and cost
102
+ Plugins follow this repository's `main` branch and update through the host's plugin commands or marketplace sync.
52
103
 
53
- API access is optional. A Claude or Claude Code subscription does not supply Anthropic API billing. To use a direct API key, follow the [official key guide](https://platform.claude.com/docs/en/get-api-key): Console → Settings → API keys. Put the key in the `ANTHROPIC_API_KEY` environment variable in your own shell or secret manager; never put a real value in a report. A key spanning multiple Anthropic workspaces may require an `anthropic-workspace-id` header. The direct adapter introduced in v0.1.0 still does not set that header, so use a compatible key or a separately approved host capability.
104
+ ### 5. Ask your agent
54
105
 
55
- The direct adapter accepts only text `{model,max_tokens,messages}` requests for the exact model IDs `claude-fable-5-1`, `claude-opus-5-5`, `claude-sonnet-5-5`, and `claude-haiku-5-5`. `max_tokens` cannot exceed 128,000. Each attempt needs one token reservation of at least `1,000,000 + max_tokens`, a matching ledger budget, and an approval reference. This is a worst-case capacity bound, not a bill estimate. Record the current price source, estimated spend, and approved stop condition before the first paid call. Extra fields, tools, search, non-text input, unknown models, or currency-only bounds make zero direct calls. See [API boundaries](skills/optbrew/references/api.md).
106
+ Paste this into Codex, Claude Code or another coding agent:
56
107
 
57
- SE Ranking has its own [API](https://seranking.com/api.html), [MCP instructions](https://seranking.com/api/integrations/mcp), account plan, and credits. Its [HTTP MCP endpoint](https://api.seranking.com/mcp) uses its documented OAuth or direct-token path, independently of `ANTHROPIC_API_KEY`. Available tools depend on the subscription. Neither connection is required for offline scoring. Use actual account prices and credits when deciding whether to run a paid capability; no price is built into this README.
108
+ ```text
109
+ Install the optbrew skill for me. Read https://raw.githubusercontent.com/nowwcastle-sudo/optbrew/v0.2.0/AGENT_INSTALL.md and follow it step by step. Ask me which agents and which scope to use, and show me the planned changes before you install.
110
+ ```
111
+
112
+ [AGENT_INSTALL.md](AGENT_INSTALL.md) gives the agent a command and a pass check for each step, and the cases where it must stop and ask you.
58
113
 
59
- ## Update and rollback
114
+ Installing from a source checkout, the Agent Skills CLI, Pi packages and Claude web uploads are covered in [platform support](docs/platforms.md).
60
115
 
61
- For a managed project installation, rebuild or obtain a verified newer optbrew bundle before updating. From the checkout root:
116
+ ## Quick start
62
117
 
63
- Bash and PowerShell use the same commands:
118
+ Start a new agent session and ask, for example:
64
119
 
65
120
  ```text
66
- node bin/optbrew.mjs check-updates --json
67
- node bin/optbrew.mjs update --scope project --project ./site --json
68
- node bin/optbrew.mjs rollback --scope project --project ./site --release-version 0.1.0 --json
121
+ Run optbrew on https://example.com. Goal: show up in Naver and get cited in AI answers.
69
122
  ```
70
123
 
71
- `check-updates --package optbrew` reads the latest version from the npm registry; without `--package` it reports `local_only`. `update` uses the current CLI bundle, verifies it, and updates all targets in that install record; it does not silently replace local edits. `rollback` needs that version in the record's retained prior releases. The shown rollback will therefore fail on a fresh 0.1.2 install and applies to a managed installation that retains local 0.1.0. `npm update -g optbrew` updates npm's package files after release; it does not rewrite a copy already placed in an agent skills directory. Run the managed `update` command again after updating the CLI. A managed 0.1.1 install cannot be updated to 0.1.2: `update` stops with `migration_required` (see the reinstall steps below). Native plugin and Pi package update paths are in [platform support](docs/platforms.md).
72
-
73
- ### Reinstall after a migration_required update
74
-
75
- Release 0.1.2 uses evaluation version 0.2.0 (0.1.1 used 0.1.0), so scores and baselines made with 0.1.1 are not comparable with 0.1.2: `compare` returns `not_comparable`, and you run the baseline audit again with 0.1.2. For the same reason `optbrew update` on a managed 0.1.1 install stops with `migration_required` and changes nothing; the message lists the paths and commands. There is no `uninstall` command. Replace the install with the blocks below, from the 0.1.2 checkout root. Each block first runs the read-only `reinstall-plan`, which validates the install record (every target must be exactly the agent's `skills/optbrew` path) and refuses a tampered one before anything is deleted. The shell then deletes only the paths it printed, targets first and the managed root last, so the block can be run again after a failure. The commands never touch `.optbrew/runs` (your audit evidence); do not delete the whole `.optbrew` folder. Full explanation: [platform support](docs/platforms.md).
76
-
77
- User scope:
78
-
79
- ```powershell user
80
- $ErrorActionPreference = 'Stop'
81
- [Console]::OutputEncoding = [Text.Encoding]::UTF8
82
- $plan = @(node bin/optbrew.mjs reinstall-plan --scope user)
83
- if ($LASTEXITCODE) { exit $LASTEXITCODE }
84
- foreach ($line in $plan) {
85
- $f = $line -split "`t"
86
- if ($f[0] -eq 'delete-link') { [IO.Directory]::Delete($f[1]) }
87
- elseif ($f[0] -eq 'delete-dir') { Remove-Item -Recurse -Force -LiteralPath $f[1] }
88
- }
89
- foreach ($line in $plan) {
90
- $f = $line -split "`t"
91
- if ($f[0] -eq 'install') { node bin/optbrew.mjs install --agents $f[1] --scope user --strategy $f[2]; if ($LASTEXITCODE) { exit $LASTEXITCODE } }
92
- elseif ($f[0] -eq 'agents') { node bin/optbrew.mjs doctor --agents $f[1] --scope user; exit $LASTEXITCODE }
93
- }
94
- ```
124
+ optbrew then checks your setup and sends the start questions in one message. Answer each number, or reply "시작" (start) to accept the defaults. A missing Google key, Chrome or export file does not stop the audit. The blank is listed in the report with the steps to fill it.
95
125
 
96
- ```bash user
97
- set -e
98
- plan=$(node bin/optbrew.mjs reinstall-plan --scope user)
99
- while IFS=$'\t' read -r kind a b; do
100
- case "$kind" in delete-link | delete-dir) rm -r -- "$a" ;; esac
101
- done <<< "$plan"
102
- while IFS=$'\t' read -r kind a b; do
103
- case "$kind" in
104
- install) node bin/optbrew.mjs install --agents "$a" --scope user --strategy "$b" ;;
105
- agents) node bin/optbrew.mjs doctor --agents "$a" --scope user ;;
106
- esac
107
- done <<< "$plan"
108
- ```
126
+ The audit takes a few minutes. Everything it writes goes to `optbrew-audit/<site>-<date>` in your working folder: the evidence (every response with its hash) and the three reports. Open `report.html` first. The same name with a number added (`-2`, `-3`) is used when the folder already exists. Private, internal and local addresses (such as `localhost` or `192.168.x.x`) are refused, so audit the public address of the site.
109
127
 
110
- Project scope (replace `./site` with your project folder; it appears once):
111
-
112
- ```powershell project
113
- $ErrorActionPreference = 'Stop'
114
- [Console]::OutputEncoding = [Text.Encoding]::UTF8
115
- $project = './site'
116
- $plan = @(node bin/optbrew.mjs reinstall-plan --scope project --project $project)
117
- if ($LASTEXITCODE) { exit $LASTEXITCODE }
118
- foreach ($line in $plan) {
119
- $f = $line -split "`t"
120
- if ($f[0] -eq 'delete-link') { [IO.Directory]::Delete($f[1]) }
121
- elseif ($f[0] -eq 'delete-dir') { Remove-Item -Recurse -Force -LiteralPath $f[1] }
122
- }
123
- foreach ($line in $plan) {
124
- $f = $line -split "`t"
125
- if ($f[0] -eq 'install') { node bin/optbrew.mjs install --agents $f[1] --scope project --project $project --strategy $f[2]; if ($LASTEXITCODE) { exit $LASTEXITCODE } }
126
- elseif ($f[0] -eq 'agents') { node bin/optbrew.mjs doctor --agents $f[1] --scope project --project $project; exit $LASTEXITCODE }
127
- }
128
+ ### Google API key (optional)
129
+
130
+ A free Google API key makes the real-visitor speed scores (LCP, INP, CLS) fill reliably. When optbrew offers it, answer "키" (key) to see how to get one. Then save it from your own terminal, never in the chat. In Codex and Claude Code cloud, the key guide shows where to save it instead.
131
+
132
+ ```bash
133
+ optbrew key set google
134
+ optbrew key status
135
+ optbrew key remove google
128
136
  ```
129
137
 
130
- ```bash project
131
- set -e
132
- project='./site'
133
- plan=$(node bin/optbrew.mjs reinstall-plan --scope project --project "$project")
134
- while IFS=$'\t' read -r kind a b; do
135
- case "$kind" in delete-link | delete-dir) rm -r -- "$a" ;; esac
136
- done <<< "$plan"
137
- while IFS=$'\t' read -r kind a b; do
138
- case "$kind" in
139
- install) node bin/optbrew.mjs install --agents "$a" --scope project --project "$project" --strategy "$b" ;;
140
- agents) node bin/optbrew.mjs doctor --agents "$a" --scope project --project "$project" ;;
141
- esac
142
- done <<< "$plan"
138
+ `set` asks for the key with hidden input. `status` shows only whether a key exists and the first 8 characters of its hash. `remove` deletes it. If you did not install with npm, use `npx optbrew@0.2.0 key set google`, or answer "키" and copy the exact command from the guide. The skill folder has the same command too: `node <skill folder>/scripts/key.mjs set google`. The key is saved in `.optbrew/credentials.json` in your home folder, outside every project, and the environment variable `OPTBREW_GOOGLE_API_KEY` takes priority if it is set. optbrew sends the key to Google only in a request header, and never writes it to a report, a log or the evidence.
139
+
140
+ ## Update
141
+
142
+ ```bash
143
+ npm install -g optbrew@latest
144
+ optbrew update --scope user
143
145
  ```
144
146
 
145
- ## Support and license
147
+ With npx, run `npx optbrew@latest update --scope user`. `optbrew check-updates --package optbrew` tells you, without changing anything, whether npm has a newer release than the CLI you are running; `optbrew doctor --json` shows the `release_version` installed in your agent folders. `npm update` alone does not touch copies already placed in agent folders; the `update` command does.
148
+
149
+ ### Upgrading from 0.1.x
150
+
151
+ 0.2.0 changes the evaluation version (0.4.0), the audit protocol (0.2.0) and the contract schema (2.0.0). So:
152
+
153
+ - A managed install of any 0.1.x release stops with `migration_required`, and `optbrew update` changes nothing. Follow [Reinstall after a migration_required update](docs/platforms.md#reinstall-after-a-migration_required-update); the steps delete only paths that a read-only check printed and never touch your audit evidence.
154
+ - A plugin install (Claude Code, Codex, claude.ai) follows `main`, so the plugin update commands of your host work as before.
155
+ - An output folder or evidence packet from a 0.1.x run is refused with one sentence: run the audit again in a new folder. Scores from different evaluation versions are not comparable, so `compare` reports `not_comparable` against a 0.1.x baseline. Run the baseline audit again with 0.2.0.
156
+
157
+ ## APIs and cost
158
+
159
+ Nothing here requires a paid account. A direct Anthropic API call or an [SE Ranking](https://seranking.com/api.html) call needs your approval, a recorded budget and a stop condition first; a Claude subscription does not include API billing. The Google key above is your own, and the Google speed services it calls are free. Keys stay in your environment variables or the key file and never go into a report. Details: [API boundaries](skills/optbrew/references/api.md).
160
+
161
+ ## Documentation
162
+
163
+ - [Platform support](docs/platforms.md): install paths per agent, checkout commands, reinstall steps
164
+ - [Scoring](skills/optbrew/references/scoring.md), [measurement](skills/optbrew/references/measurement.md) and [report evidence](skills/optbrew/references/report.md)
165
+ - [Changelog](CHANGELOG.md) and [release process](docs/release.md)
166
+
167
+ ## Contributing
168
+
169
+ Contributions are welcome: bug reports, false positives from a real site, guide updates, translations and code. See [CONTRIBUTING.md](CONTRIBUTING.md).
146
170
 
147
- Managed install, doctor, update, and rollback cover Codex, Claude Code, Cursor, OpenCode, and Pi at the documented default paths. Custom host directories, project trust, and session reload rules can change discovery. Ordinary ChatGPT chat uses attached files and instructions; it is not the same installation path as Codex or a Work/desktop plugin. Claude web requires manual ZIP upload and re-upload for updates. Host discovery and a successful real invocation require separate checks.
171
+ ## License
148
172
 
149
- The Naver bundle retains an index of official [Search Advisor guides](https://searchadvisor.naver.com/guide). It excludes the 55 original Naver article bodies, so full offline article lookup is unavailable. Follow the official links while online. Included source licenses and changes are listed in [third-party notices](skills/optbrew/THIRD_PARTY_NOTICES.md); optbrew's own code is [MIT licensed](LICENSE). Service access and API data rights are separate from those code licenses. Release packaging and verification are in [release instructions](docs/release.md).
173
+ optbrew's own code is [MIT licensed](LICENSE). The bundled guides keep their own licenses, listed in [third-party notices](skills/optbrew/THIRD_PARTY_NOTICES.md). The Naver bundle keeps an index of the official [Search Advisor guides](https://searchadvisor.naver.com/guide) but not the 55 article bodies; follow the official links while online.
@@ -8,3 +8,91 @@ The files below retain their upstream copyright and permission notices. Service
8
8
  - **magnus-seo** — magnus919/agent-skills at 2e8fb962819b2b01b270620f92f0cc7213d77ef1; MIT; Git license blob 9745e19f4b20d77c134964ae1bf0af0ace5c4db7; exact notice: [licenses/magnus-seo.txt](skills/optbrew/licenses/magnus-seo.txt). Exclusions: Unselected agent skills.
9
9
  - **seranking-seo** — seranking/seo-skills at fd6d1408f2e6a06454d81c07c29e0f04342eb9ba; MIT; Git license blob ca6b9a33c8234bf47cdcfb2dc157b308195845c5; exact notice: [licenses/seranking-seo.txt](skills/optbrew/licenses/seranking-seo.txt). Exclusions: extensions/google/install.sh and extensions/firecrawl/install.sh: upstream installers disabled; scripts/google_auth.py and root scripts: upstream authentication and provider execution disabled; optbrew capability adapters replace active commands; Unselected campaign, ad, social and other upstream skills.
10
10
  - **marketing-search** — coreyhaines31/marketingskills at 5b2c0007766c6a1cf1d53fd8fc73e979e0821022; MIT; Git license blob 7c48dd638a9ebed49a8ef0c0c4eea90105381cdf; exact notice: [licenses/marketing-search.txt](skills/optbrew/licenses/marketing-search.txt). Exclusions: Unselected marketing skills, installers and authoring utilities.
11
+
12
+ ## Borrowed text
13
+
14
+ These two works are not vendored code. SKILL.md, section "진행 보고", adapts the output rules of caveman. The top sections of the HTML report, added in the same release, follow the approach of eli5 (big picture, few words).
15
+
16
+ ### caveman
17
+
18
+ Source: https://github.com/JuliusBrussee/caveman, `skills/caveman/SKILL.md`, version 4.0.1. No upstream commit is recorded: the text was copied from the installed 4.0.1 plugin. License: Apache License, Version 2.0, https://www.apache.org/licenses/LICENSE-2.0. Changes: the rules were translated into Korean, shortened, and rewritten for progress sentences during an audit; SKILL.md marks the paragraph "변경함". Upstream keeps the pre-3.0.0 MIT text in its `LICENSE-MIT` file for contributions made before 3.0.0; that file is not redistributed here. The upstream NOTICE file follows word for word.
19
+
20
+ ```text
21
+ Caveman
22
+ Copyright 2026 Julius Brussee
23
+
24
+ Before Caveman 3.0.0, the parts of this repository outside the Engine-linked
25
+ runtime were licensed under the MIT License (see LICENSING.md). Contributions
26
+ made to those parts before 3.0.0 were received under the MIT License and remain
27
+ available under it. Its copyright and permission notice is retained in
28
+ LICENSE-MIT.
29
+
30
+ This product includes third-party software:
31
+
32
+ - engine/pixel/ is a Go port of pxpipe (https://github.com/teamchong/pxpipe),
33
+ used under the MIT License.
34
+ Copyright (c) 2026 claude-image-proxy contributors
35
+
36
+ - The glyph atlases embedded in engine/pixel/assets/ are rasterized from:
37
+ - Spleen 5x8, Copyright (c) 2018-2026, Frederic Cambus.
38
+ BSD 2-Clause License.
39
+ - GNU Unifont 16.0.04, dual-licensed under the SIL Open Font License 1.1 and
40
+ the GNU GPL version 2 (or later) with the GNU font-embedding exception.
41
+
42
+ - browse/ links these MIT-licensed Go modules:
43
+ - github.com/chromedp/chromedp, Copyright (c) 2016-2025 Kenneth Shaw
44
+ - github.com/chromedp/cdproto, Copyright (c) 2016-2025 Kenneth Shaw
45
+ - github.com/chromedp/sysutil, Copyright (c) 2016-2017 Kenneth Shaw
46
+
47
+ - The runtime binaries and the container image link third-party Go modules
48
+ under the MIT, BSD-3-Clause and Apache-2.0 licenses. Their license texts, and
49
+ the Go runtime's, ship with every binary release as
50
+ THIRD_PARTY_GO_LICENSES.tar.gz and in the image under /licenses/third_party/.
51
+
52
+ - packages/cli/src/index.ts contains a port, with changes, of Qwen Code
53
+ 0.22.3's MCP server and permission-rule matchers and its tool-name
54
+ normalization (https://github.com/QwenLM/qwen-code), used under the Apache
55
+ License, Version 2.0.
56
+ Copyright 2025 Google LLC
57
+ Copyright 2025 Qwen
58
+
59
+ - The @caveman-ai/cli package bundles MIT-licensed npm packages
60
+ (@clack/prompts, @clack/core, sisteransi, fast-string-width,
61
+ fast-string-truncated-width, fast-wrap-ansi); see packages/cli/NOTICE.
62
+
63
+ - extension/fonts/ holds the Geist and Geist Mono fonts,
64
+ Copyright (c) 2023 Vercel, in collaboration with basement.studio,
65
+ under the SIL Open Font License 1.1.
66
+
67
+ Full license texts: engine/pixel/NOTICE, engine/pixel/assets/SPLEEN_LICENSE.txt,
68
+ engine/pixel/assets/UNIFONT_LICENSE.txt, browse/NOTICE, packages/cli/NOTICE, and
69
+ extension/fonts/GEIST_LICENSE.txt.
70
+ ```
71
+
72
+ ### eli5
73
+
74
+ Source: the `eli5` plugin version 1.0.0 by Thariq Shihipar, from the claude-community plugin marketplace. Its `plugin.json` declares `"license": "MIT"`; the plugin ships no separate license file and states no copyright year. Use: only the approach "big pictures, few words" is followed; no upstream text is copied. The text below is the standard MIT License text with the author name taken from `plugin.json`. It is not copied from an upstream file.
75
+
76
+ ```text
77
+ MIT License
78
+
79
+ Copyright (c) Thariq Shihipar
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining a copy
82
+ of this software and associated documentation files (the "Software"), to deal
83
+ in the Software without restriction, including without limitation the rights
84
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
85
+ copies of the Software, and to permit persons to whom the Software is
86
+ furnished to do so, subject to the following conditions:
87
+
88
+ The above copyright notice and this permission notice shall be included in all
89
+ copies or substantial portions of the Software.
90
+
91
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
92
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
93
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
94
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
95
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
96
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
97
+ SOFTWARE.
98
+ ```
package/docs/platforms.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Platform installation and update paths
2
2
 
3
- Optbrew v0.1.2 contains one skill source at `skills/optbrew`. The managed CLI can place it at five hosts' documented default paths. A file in a host path proves placement, not that the host discovered, loaded, or invoked the skill. Confirm those three steps in a fresh host session before reporting host support as exercised.
3
+ Optbrew v0.2.0 contains one skill source at `skills/optbrew`. The managed CLI can place it at five hosts' documented default paths. A file in a host path proves placement, not that the host discovered, loaded, or invoked the skill. Confirm those three steps in a fresh host session before reporting host support as exercised.
4
4
 
5
5
  | Host | Managed project target | Managed user target | Discovery and invocation boundary |
6
6
  |---|---|---|---|
@@ -14,15 +14,51 @@ The CLI maps only these default targets. Custom roots, host policies, remote age
14
14
 
15
15
  ## Managed checkout and npm paths
16
16
 
17
- The [README](../README.md) shows parser-checked checkout commands for install, doctor, update, and rollback. The CLI validates bundle hashes before an install or update. `update` replaces every target in one managed record as a unit. An edited target makes the default update stop; the explicit `--local-changes backup-and-replace` policy retains a readable backup. `rollback --release-version VERSION` works only when that version is in the record's retained prior releases. A fresh installation has no older release.
17
+ The [README](../README.md) shows the npm, npx, PowerShell, plugin and agent install routes. This section holds the parser-checked commands for a source checkout. Clone `https://github.com/nowwcastle-sudo/optbrew`, create an empty `site` folder, and run them from the repository root. With the npm package installed, replace `node bin/optbrew.mjs` with `optbrew`.
18
+
19
+ Install into an isolated project folder, after a dry run:
20
+
21
+ Bash and PowerShell use the same commands:
22
+
23
+ ```text
24
+ node bin/optbrew.mjs install --agents codex,claude-code,cursor,opencode,pi --scope project --project ./site --strategy copy --dry-run --json
25
+ node bin/optbrew.mjs install --agents codex,claude-code,cursor,opencode,pi --scope project --project ./site --strategy copy --json
26
+ node bin/optbrew.mjs doctor --agents codex,claude-code,cursor,opencode,pi --scope project --project ./site --json
27
+ ```
28
+
29
+ `--strategy link` is the default; `copy` also works when links are unavailable. The managed record lives under that project's `.optbrew/install`. For one host, replace the comma-separated list with its exact ID. Use `--scope user` only when you intend to install into user-level host directories. The install command checks the bundle manifest and refuses to replace an unmanaged target.
30
+
31
+ Replay the bundled synthetic fixtures without any provider call. Copy `tests/fixtures/scoring/before.json` and `after.json`, and `tests/fixtures/reports/remote-only.json` with its sibling evidence files, into the current directory first:
32
+
33
+ Bash and PowerShell use the same commands:
34
+
35
+ ```text
36
+ node bin/optbrew.mjs score --input ./before.json --output ./score.json
37
+ node bin/optbrew.mjs compare --before ./before.json --after ./after.json --output ./comparison.json
38
+ node bin/optbrew.mjs report --input ./remote-only.json --output-dir ./report-output
39
+ ```
40
+
41
+ Check for updates, update, and roll back a managed project install:
42
+
43
+ Bash and PowerShell use the same commands:
44
+
45
+ ```text
46
+ node bin/optbrew.mjs check-updates --json
47
+ node bin/optbrew.mjs update --scope project --project ./site --json
48
+ node bin/optbrew.mjs rollback --scope project --project ./site --release-version 0.2.0 --json
49
+ ```
50
+
51
+ Rollback works only between releases that share the evaluation version, so no release before 0.2.0 can be rolled back to. The shown command reports that no earlier release is retained on a fresh 0.2.0 install; it applies once a later release that shares evaluation version 0.4.0 has updated the install.
52
+
53
+ The CLI validates bundle hashes before an install or update. `update` replaces every target in one managed record as a unit. An edited target makes the default update stop; the explicit `--local-changes backup-and-replace` policy retains a readable backup. `rollback --release-version VERSION` works only when that version is in the record's retained prior releases. A fresh installation has no older release.
18
54
 
19
55
  After a public npm release, `npm install -g optbrew` and `npm update -g optbrew` manage the package in npm. Neither command rewrites an old copied skill target. Run the installed CLI's managed `update` after the package update, then `doctor` and a new-session invocation check. `check-updates --package optbrew --json` is read-only and compares the installed release with the npm registry; without `--package` it returns `local_only`.
20
56
 
21
57
  ## Reinstall after a migration_required update
22
58
 
23
- Release 0.1.2 uses evaluation version 0.2.0; 0.1.1 used 0.1.0. The managed updater refuses a change of evaluation version, so `optbrew update` on a managed 0.1.1 install stops with `migration_required` and changes nothing. There is no `uninstall` command. Replace the install by hand: the blocks below delete the install's targets and then its managed root, and run `install` again from the 0.1.2 checkout. Scores and baselines made with 0.1.1 are not comparable with 0.1.2; `compare` returns `not_comparable` (`evaluation_version_changed`). Run the baseline audit again with 0.1.2.
59
+ Release 0.2.0 uses evaluation version 0.4.0, audit protocol 0.2.0 and contract schema 2.0.0. Release 0.1.3 used evaluation version 0.3.0 and 0.1.2 used 0.2.0. The managed updater refuses a change of evaluation version or of a scoring contract file, so `optbrew update` stops with `migration_required` and changes nothing on a managed install of any 0.1.x release. There is no `uninstall` command. Replace the install by hand: the blocks below delete the install's targets and then its managed root, and run `install` again from the 0.2.0 checkout. Scores and baselines made with a 0.1.x release are not comparable with 0.2.0; `compare` returns `not_comparable`, so run the baseline audit again. An output folder or evidence packet from a 0.1.x run is refused with one sentence that tells you to run the audit again in a new folder. A plugin install from a marketplace is not a managed install: it follows the repository and needs no reinstall.
24
60
 
25
- The blocks do not trust the install record. Each one first runs the read-only `node bin/optbrew.mjs reinstall-plan`, which resolves the home directory the way the CLI does (`HOME`, else the operating system's home directory), checks that the record belongs to this scope, that every recorded target is exactly the agent's `skills/optbrew` path (absolute, no `..`, no linked folder on the way, inside the scope or project), and that an existing target is a link to the managed bundle or a real folder holding a bundle manifest. If any check fails it prints the reason, exits with a nonzero code, and the block deletes nothing. Otherwise the shell deletes only the paths it printed: the targets first, then `<scope root>/.optbrew/installs/user` (user scope) or `<project>/.optbrew/install` (project scope), which holds the install record. Because the record goes last, you can run the same block again after a failure. The commands never touch `<scope root>/.optbrew/runs`, where your audit evidence lives; do not delete the whole `.optbrew` folder. Each agent is installed again with the strategy (`link` or `copy`) the record had, then `doctor` runs. Run the blocks from the 0.1.2 checkout root. If `reinstall-plan` refuses the record, fix or remove the named path by hand and look at it first; the CLI also refuses to overwrite a target it does not own.
61
+ The blocks do not trust the install record. Each one first runs the read-only `node bin/optbrew.mjs reinstall-plan`, which resolves the home directory the way the CLI does (`HOME`, else the operating system's home directory), checks that the record belongs to this scope, that every recorded target is exactly the agent's `skills/optbrew` path (absolute, no `..`, no linked folder on the way, inside the scope or project), and that an existing target is a link to the managed bundle or a real folder holding a bundle manifest. If any check fails it prints the reason, exits with a nonzero code, and the block deletes nothing. Otherwise the shell deletes only the paths it printed: the targets first, then `<scope root>/.optbrew/installs/user` (user scope) or `<project>/.optbrew/install` (project scope), which holds the install record. Because the record goes last, you can run the same block again after a failure. The commands never touch `<scope root>/.optbrew/runs`, where the audit evidence of 0.1.x lives, and never touch an `optbrew-audit` folder; do not delete the whole `.optbrew` folder, which also holds the Google key file. Each agent is installed again with the strategy (`link` or `copy`) the record had, then `doctor` runs. Run the blocks from the 0.2.0 checkout root. If `reinstall-plan` refuses the record, fix or remove the named path by hand and look at it first; the CLI also refuses to overwrite a target it does not own.
26
62
 
27
63
  User scope:
28
64
 
@@ -92,16 +128,17 @@ while IFS=$'\t' read -r kind a b; do
92
128
  done <<< "$plan"
93
129
  ```
94
130
 
95
- Inside 0.1.2 and later releases that keep evaluation version 0.2.0, `update` and `rollback` work as before. The same refusal and steps apply to any future release that changes the evaluation version.
131
+ Inside 0.2.0 and later releases that keep evaluation version 0.4.0 and the scoring contract files, `update` and `rollback` work as before. The same refusal and steps apply to any future release that changes the evaluation version or a scoring contract file.
96
132
 
97
133
  ## Native host routes
98
134
 
99
135
  These are alternatives to the managed CLI. Do not mix their ownership records for the same target path.
100
136
 
101
137
  - **Agent Skills tool:** Current [Vercel Skills CLI](https://github.com/vercel-labs/skills) documents `npx skills add ./` for a local source and `npx skills update optbrew` for an installation it owns. Run from a checkout containing the skill. Confirm its host selection and destination before writing. The public repository is `https://github.com/nowwcastle-sudo/optbrew`.
102
- - **Claude Code plugin:** The local `.claude-plugin/marketplace.json` and `plugin.json` name `optbrew@optbrew-local` at version 0.1.2. The installed Claude CLI help accepts `claude plugin marketplace add --scope project .`, then `claude plugin install --scope project optbrew@optbrew-local` from this checkout. Later, `claude plugin update --scope project optbrew@optbrew-local` applies the marketplace's newer version and requires a restart. These commands change Claude settings, so documentation checks inspect `--help` without registering a marketplace. [Claude Code plugin instructions](https://code.claude.com/docs/en/plugins) also describe the interactive `/plugin` path. Marketplace auto-update is a user setting; the marketplace file does not enable it. Verify the selected release version and a fresh-session invocation after a native update.
103
- - **Pi package:** Current [Pi package instructions](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) document `pi install ./local-package`, `pi install npm:package-name@version`, `pi list`, and `pi update --extensions`. `pi install ./` installs from a local checkout when Pi is installed; `pi install npm:optbrew@0.1.2` installs the published npm package. The package's `pi.skills` entry points to `./skills/optbrew`. A project-local package declaration uses Pi's `--local` option and is subject to project trust. Check the installed Pi version's help and package list before updating.
104
- - **Claude web:** Upload the built skill ZIP manually in the supported web interface. Upload a new ZIP again for each update. There is no verified automatic update of that upload.
138
+ - **Claude Code plugin:** `.claude-plugin/marketplace.json` names the plugin `optbrew@optbrew` and serves the `skills/` folder, whose `skills/.claude-plugin/plugin.json` lists `./optbrew`. Neither file pins a version, so each commit to `main` is a new plugin version. Run `claude plugin marketplace add nowwcastle-sudo/optbrew`, then `claude plugin install optbrew@optbrew` (add `--scope project` to keep it in one project). Later, `claude plugin update optbrew@optbrew` applies the marketplace's newer version and requires a restart. `claude plugin validate .` checks the marketplace and the served plugin from a checkout. The root `.claude-plugin/plugin.json` (version 0.2.0) still loads the whole checkout with `claude --plugin-dir .`. [Claude Code plugin instructions](https://code.claude.com/docs/en/plugins) also describe the interactive `/plugin` path. Marketplace auto-update is a user setting; the marketplace file does not enable it. Verify a fresh-session invocation after a native update.
139
+ - **Codex plugin:** `.agents/plugins/marketplace.json` lists the same `optbrew` plugin. Run `codex plugin marketplace add nowwcastle-sudo/optbrew`, then `codex plugin add optbrew@optbrew`, or choose it in `/plugins`. Start a new Codex task afterwards.
140
+ - **Pi package:** Current [Pi package instructions](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) document `pi install ./local-package`, `pi install npm:package-name@version`, `pi list`, and `pi update --extensions`. `pi install ./` installs from a local checkout when Pi is installed; `pi install npm:optbrew@0.2.0` installs the published npm package. The package's `pi.skills` entry points to `./skills/optbrew`. A project-local package declaration uses Pi's `--local` option and is subject to project trust. Check the installed Pi version's help and package list before updating.
141
+ - **Claude web (claude.ai, Claude Desktop, Cowork):** In Customize > Plugins, choose Add > Add marketplace and enter `nowwcastle-sudo/optbrew`, then add `optbrew`. The plugin is saved to your account, so cloud Claude Code sessions receive it too. Turn on Sync automatically for the marketplace, or select Check for updates, to pick up new commits. The marketplace serves `skills/` because claude.ai refuses a plugin with a top-level `bin/` folder. Uploading a ZIP of `skills/` (Add > Upload plugin) also works, but each update needs a new upload.
105
142
  - **Ordinary ChatGPT chat:** Attach the relevant skill files or ZIP and give the assistant the target and scope. This is attachment-guided use. It is not the Codex installation path and does not establish Work/desktop plugin discovery.
106
143
 
107
144
  The native syntax above comes from host documentation checked on 2026-10-14. It is documentation evidence, not proof that an installed host accepted the package or called the skill. No host registration, OAuth, account setting, or user-level install is performed by the documentation checks.
package/docs/release.md CHANGED
@@ -1,14 +1,47 @@
1
1
  # Release procedure
2
2
 
3
- This checkout is version 0.1.2. A package name, local manifest, or generated ZIP does not establish a public release. Publication, a Git tag, a push, and account changes require their own authorization. This page describes the reviewable local release artifacts and the checks to run before that decision.
3
+ This checkout is version 0.2.0. A package name, local manifest, or generated ZIP does not establish a public release. Publication, a Git tag, a push, and account changes require their own authorization. This page describes the reviewable local release artifacts and the checks to run before that decision.
4
4
 
5
5
  1. Confirm the source commit and clean intended diff. Match `package.json`, the portable plugin, Codex plugin, Claude plugin, marketplace entry, and ZIP name to one release version. Keep `evaluation_version` and `protocol_version` separate from the release version.
6
6
  2. Run `npm test` and `python -m unittest discover -s tests/python` on Python 3.10 or later. Run the focused `node --test tests/docs-commands.test.mjs` check when changing examples. The command check runs optbrew against isolated local fixtures; it makes no provider call.
7
- 3. Run `npm run build-bundle`, `node scripts/build-release.mjs --version 0.1.2 --output-dir dist`, `npm pack --pack-destination dist`, `node scripts/verify-release.mjs --dist dist`, and `npm pack --dry-run --json` from the repository root. Rebuild after changing the README or packaged files. Do not treat an older tarball as containing a later documentation edit.
7
+ 3. Build from a checkout made with `git clone -c core.autocrlf=false`. The root and `skills/` carry no `.gitattributes` (the Claude plugin directory refuses one there), so with `core.autocrlf=true` the skill files are CRLF in the working tree; the bundle hashes still match, but the ZIP and npm verifiers compare exact bytes and refuse them. Run `npm run build-bundle`, `node scripts/build-release.mjs --version 0.2.0 --output-dir dist`, `npm pack --pack-destination dist`, `node scripts/verify-release.mjs --dist dist`, and `npm pack --dry-run --json` from the repository root. Rebuild after changing the README or packaged files. Do not treat an older tarball as containing a later documentation edit.
8
8
  4. Inspect the npm file list, the ZIP file list, `bundle-manifest.json`, `source-lock.json`, licenses, and secret scan output. The same skill bytes and version must be traceable across the npm package and ZIP. Source notices belong in both. User run evidence, account configuration, keys, private cards, and authoring materials must stay outside both.
9
9
  5. Test a fresh isolated managed install, `doctor`, update from a retained earlier release, rollback, and fresh host discovery or invocation where a host is available. A dry run or manifest check does not prove invocation. Record the untested hosts and capabilities.
10
- 6. Only after a reviewed release decision, publish or upload the approved artifacts and verify the public npm and repository readback. Do not infer publication from successful local builds.
10
+ 6. Confirm CI on the exact commit that will be tagged. That commit exists only after the merge: `main` takes changes through a pull request with linear history, so the merge makes a commit that no earlier run has seen, and runs on the release branch or the pull request do not count. Do this after the merge of step 8 and before its tag. The `test` workflow (`.github/workflows/test.yml`) runs `npm test` on `ubuntu-latest` and on `windows-latest` with `core.autocrlf=true`, Chrome integration tests included, and its last step (`scripts/check-skips.mjs`) fails when a Chrome test was skipped or another test was skipped for a reason that is not listed there. The push to `main` starts the first run. Start two more on the same commit, one after the other, each when the previous one has finished (the workflow keeps one run per commit at a time): `gh workflow run test.yml --ref main`. Then `gh run list --workflow test.yml --branch main --commit <merge commit sha> --json event,conclusion,headSha,url` must list three runs (the `push` run and two `workflow_dispatch` runs) with `conclusion` `success`, each green on both systems. Do not rerun a red run until it turns green: one failed Chrome test (a leftover `gpu-process` of its own Chrome was seen once under load) is a flake to investigate. Read the two `Point optbrew at the runner's Chrome` steps of the newest run and add the Chrome version and path each runner printed to [Chrome locations and DevTools names](#chrome-locations-and-devtools-names-2026-10-16) with the date; also record whether the first Ubuntu run needed any sandbox workaround.
11
+ 7. Only after a reviewed release decision, and only after step 6 is green on the merge commit, publish or upload the approved artifacts and verify the public npm and repository readback. Do not infer publication from successful local builds. The owner runs these actions, not an agent: `git push`, the merge, the tag and its push, `gh release create`, and `npm publish dist/optbrew-X.Y.Z.tgz`. An agent prepares the artifacts and reads the results back.
12
+ 8. `main` is protected by a repository ruleset: no force push, no deletion, changes only through a pull request, linear history. Tags matching `v*` cannot be moved or deleted. Merge the release branch through a pull request, then tag the merge commit `vX.Y.Z`. The README's PowerShell installer and agent prompt load `install.ps1` and `AGENT_INSTALL.md` from that tag, so test both raw URLs after the tag is pushed. Do not push the tag before step 6 is green for that merge commit.
13
+ 9. A tag alone is not a GitHub Release. Publish one for the tag, with the CHANGELOG section as notes and the reviewed ZIP attached: `gh release create vX.Y.Z dist/<zip> --title vX.Y.Z --notes-file <notes.md>`. Read it back: `gh api repos/nowwcastle-sudo/optbrew/releases --jq '.[].tag_name'` must list the tag, and `npm view optbrew dist-tags` must show the same version as `latest`.
14
+ 10. The Claude marketplace and directory sync on a push to `main`, sent by the repository webhook. After the merge, confirm that the webhook got a push for `refs/heads/main` with the merge commit: `gh api repos/nowwcastle-sudo/optbrew/hooks/<id>/deliveries` lists the delivery, and `.../deliveries/<delivery id>` shows `request.payload.ref` and `request.payload.after`. A branch deletion is answered `ignored_delete` and does not sync. Then check that the claude.ai copy shows the merge commit.
15
+ 11. The Codex marketplace file is `.agents/plugins/marketplace.json`. After the merge, in a Codex that has the marketplace (`codex plugin marketplace add nowwcastle-sudo/optbrew` adds it), run `codex plugin marketplace upgrade`, then `codex plugin list --marketplace optbrew` and check that `optbrew` is listed as available (`--json` gives a machine-readable form). A listing shows that the marketplace file is readable. It does not show that a Codex task discovers the skill: start a new Codex task, invoke the skill, and record the Codex version used (`codex --version`).
11
16
 
12
17
  The bundle includes five pinned source bundles plus seven selected marketing guides. The Naver source articles under `references/guide/` (55 original bodies) remain excluded; the index links to official pages and full offline article lookup is unavailable. The published notice must retain upstream MIT/ISC permission texts and modifications. Optbrew's own code uses MIT. These code licenses do not grant service subscriptions or API data rights.
13
18
 
14
- The direct Anthropic adapter retains its v0.1.0 text-only scope and four model IDs in [API boundaries](../skills/optbrew/references/api.md). No live paid result, search indexing, traffic change, or customer adoption is established by a passing package check. See [platform paths](platforms.md) for update mechanisms after release.
19
+ The direct Anthropic adapter keeps its text-only scope and four model IDs in [API boundaries](../skills/optbrew/references/api.md). No live paid result, search indexing, traffic change, or customer adoption is established by a passing package check. See [platform paths](platforms.md) for update mechanisms after release.
20
+
21
+ ## Confirmation records
22
+
23
+ Values the code relies on that were confirmed from a primary source, with the date of confirmation. Re-confirm before changing the matching file.
24
+
25
+ ### Chrome locations and DevTools names (2026-10-16)
26
+
27
+ Confirmed for `skills/optbrew/references/chrome-paths.json` and `skills/optbrew/scripts/core/chrome.mjs`:
28
+
29
+ - Windows `\Google\Chrome\Application\chrome.exe` and `\Microsoft\Edge\Application\msedge.exe`, tried under `%ProgramFiles%`, `%ProgramFiles(x86)%` and `%LocalAppData%`; macOS `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` and `/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge`; Linux `/opt/google/chrome/chrome` and `/opt/microsoft/msedge/msedge`. Source: Playwright's channel table and Windows prefix list, https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/registry/index.ts (read 2026-10-16). The Windows prefixes (`LOCALAPPDATA`, `PROGRAMFILES`, `PROGRAMFILES(X86)`) also match Google's `chrome-launcher`, https://github.com/GoogleChrome/chrome-launcher/blob/main/src/chrome-finder.ts.
30
+ - Names searched on `PATH`: `google-chrome-stable`, `google-chrome`, `chromium-browser`, `chromium` (Google's `chrome-launcher`, same file); `microsoft-edge-stable` (Playwright's Edge install script, https://github.com/microsoft/playwright/blob/main/packages/playwright-core/bin/reinstall_msedge_stable_linux.sh); `chrome` and `msedge` (the executable names above).
31
+ - Playwright's Chromium: `<PLAYWRIGHT_BROWSERS_PATH>/chromium-<revision>/chrome-win64/chrome.exe`, `chrome-linux64/chrome`, `chrome-linux-arm64/chrome`, `chrome-mac-{arm64,x64}/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing`; the value `0` means a package-local directory and is ignored (same Playwright file). A Chromium path on macOS (`/Applications/Chromium.app`) was not confirmed and is not listed.
32
+ - `--remote-debugging-pipe`: messages are JSON texts ended by a NUL byte, Chrome reads fd 3 and writes fd 4, so the parent writes `stdio[3]` and reads `stdio[4]`. Sources: Puppeteer's `PipeTransport.ts` and `BrowserLauncher.ts` (https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core/src/node), and Chromium's `content/browser/devtools/devtools_pipe_handler.cc`.
33
+ - DevTools Protocol names (`json/browser_protocol.json` of https://github.com/ChromeDevTools/devtools-protocol, master, read 2026-10-16): `Network.ErrorReason` includes `BlockedByClient`; `Network.ResourceType` values `Document`, `Stylesheet`, `Image`, `Font`, `Script`, `XHR`, `Fetch`; `Fetch.enable` takes `patterns` and `handleAuthRequests`; `Fetch.requestPaused` carries `requestId`, `request`, `frameId`, `resourceType`, `redirectedRequestId`; `Fetch.failRequest` takes `errorReason`; `Fetch.authRequired` carries `authChallenge.source` (`Server` or `Proxy`); `Fetch.continueWithAuth` takes `authChallengeResponse.response` (`Default`, `CancelAuth`, `ProvideCredentials`) with `username` and `password`; `Target.createBrowserContext`, `createTarget`, `attachToTarget` (`flatten`), `closeTarget`, `disposeBrowserContext`; `Browser.close`; `Page.setLifecycleEventsEnabled` and the `networkIdle` lifecycle event.
34
+ - Auto-attach (same protocol JSON, 2026-10-16): `Target.setAutoAttach` takes `autoAttach`, `waitForDebuggerOnStart`, `flatten` and an experimental `filter` (`TargetFilter`: entries are matched in order, the first match wins, a last `{ exclude: true }` drops every other type); `Target.attachedToTarget` carries `sessionId`, `targetInfo` (`targetId`, `type`, `openerId`, `browserContextId`) and `waitingForDebugger`; a paused target runs after `Runtime.runIfWaitingForDebugger`. Observed with Chrome on 2026-10-16: a page-session auto-attach delivers iframes (cross-site ones run in their own process), dedicated workers and service workers, but not popups, which only a browser-level auto-attach delivers (so the render page claims them by `browserContextId`). A dedicated worker session answers `Fetch.enable` with "'Fetch.enable' wasn't found"; its requests are paused on the session of the frame that owns it.
35
+ - Unix socket path limit (Chromium `chrome/browser/process_singleton_posix.cc`, main, read 2026-10-18): the single-instance socket path must be shorter than `sizeof(sun_path)` (108 bytes on Linux; 104 on macOS) or Chrome aborts at start (`LOG(FATAL) << "Socket path too long"`); the socket sits in `<temp folder>/<org.chromium.Chromium.XXXXXX>/SingletonSocket`. `chrome-temp.mjs` therefore redirects Chrome's temp folder into the profile only while that folder path is at most 48 bytes, and otherwise leaves the user's own. First Ubuntu run (CI run 39049765483): every launch from a Hangul profile path and every render test exited at start; the cause was not read from Chrome itself, so the next failing launch prints Chrome's last stderr words in its error message.
36
+
37
+ ### Host resolver rules (2026-10-16)
38
+
39
+ Confirmed for `skills/optbrew/scripts/core/render.mjs`: Chromium `net/base/host_mapping_rules.h` (chromium/chromium main, read 2026-10-16) defines the rules as a comma separated list of `MAP <hostname_pattern> <replacement_host>[:<port>]` and `EXCLUDE <hostname_pattern>`; the replacement is a hostname or an IP address literal, and a rule that maps to `^NOTFOUND` yields an invalid URL, so the request fails. Observed with the installed Chrome: a host mapped to `^NOTFOUND` fails to load with `net::ERR_NAME_NOT_RESOLVED`. The header does not say how a bracketed IPv6 replacement is parsed, so IPv6 pinning is not covered by a test.
40
+
41
+ ### Harness signals (2026-10-17)
42
+
43
+ Confirmed for `skills/optbrew/references/harness-signals.json` and `skills/optbrew/scripts/core/probe.mjs`:
44
+
45
+ - Claude Code: `CLAUDECODE` is set to `1` in subprocesses Claude Code spawns (Bash and PowerShell tools, hooks, status line, stdio MCP servers; IDE extensions set it in their integrated terminals). `CLAUDE_CODE_REMOTE` is set automatically to `true` when Claude Code runs as a cloud session. Both rows are in https://code.claude.com/docs/en/env-vars (read 2026-10-17); the cloud session page, https://code.claude.com/docs/en/claude-code-on-the-web, is the cross-reference. A cloud session also has `CLAUDECODE`, so `CLAUDE_CODE_REMOTE` is tested first.
46
+ - Codex: `CODEX_SANDBOX_NETWORK_DISABLED` is set to `1` for a process spawned by a shell tool call when the network sandbox policy is restricted; `CODEX_SANDBOX` is set when the process runs under a sandbox (`seatbelt` on macOS, "may change" for other mechanisms). Source: openai/codex `codex-rs/core/src/spawn.rs`, https://github.com/openai/codex/blob/main/codex-rs/core/src/spawn.rs (read 2026-10-17, constants `CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR` and `CODEX_SANDBOX_ENV_VAR`; the file defines `CODEX_SANDBOX` but does not set it). The variable is marked experimental in that comment. The Codex docs page `docs/sandbox.md` names neither variable.
47
+ - Limits: a Codex run with full network access sets neither variable, so it is detected as `other` and gets the general runbooks. Only `CODEX_SANDBOX_NETWORK_DISABLED` makes a failed DNS lookup a `codex_sandbox` block; with only `CODEX_SANDBOX` set the same failure is `site_down`. No variable separates a Claude Code cloud network level from a down site, so a failed lookup or a refused proxy tunnel in a cloud session is `cloud_network_level`.