Uh oh!
There was an error while loading. Please reload this page.
Trim the skill set; move what the skills summarized into the CLI - #436
Conversation
The two skills split one job in half and had already drifted into contradicting each other on the question users care about most. The scan declared "Retroactive purge is out of scope", while hypaware-privacy is required by LLP 0100 R7 to offer `hyp purge` for every directory marked ignore. A user who found a credential in the cache was told cleanup was impossible by one skill and offered it by the other. hypaware-privacy keeps the consent protocol (LLP 0100 R3-R9), the three usage classes, and the purge offer. The scan's ad-hoc framing and its regex class table are dropped rather than folded in: privacy's step 3 already directs the reviewer to sample for credentials and personal material, and adding a detection table to a consent flow would work against its shape. No LLP referenced the scan, so this removes cleanly. Also fixes adjacent rot in the Codex plugin's JSDoc, which advertised three report skills (adoption/spend, improvement, security) that no longer exist. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…evel epilogue Seven commands rendered as title-and-usage only, with no help body at all. Five of them were exactly the commands whose behaviour was documented nowhere but a client skill, which is the wrong place for it: the skill is Claude/Codex-only, drifts silently, and is invisible to anyone reading --help in a terminal. Adds bodies for attach, detach, status, init, and sync, covering what the skill's command map carried: attach is idempotent and reversible and covers Codex Desktop (LLP 0141), unattach is an alias, status is the "is it working?" entry point whose diagnostics carry repair: lines, init runs the walkthrough or --yes, and sync releases the first-sync hold all-or-nothing (LLP 0101). The top-level help gains three facts a bare command list cannot convey: that `hyp` and `hypaware` are the same binary, that the list is install-specific because inactive plugins contribute nothing (with a pointer to the LLP 0098/0099 miss path that names the plugin and prints a repair line), and that `hyp status` answers whether the install works. Two corrections found while verifying rather than transcribing the skill: `hyp claude-desktop install` does not exist (the subcommands are profile, install-helper, status), and `hyp init --yes` was real but missing from its usage string. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The skill's own preamble declared `hyp --help` authoritative over anything it summarized, and then summarized it anyway across a 45-line command map. That map had drifted exactly as predicted: it omitted seven live commands (leave, plugin, policy, purge, report, skills, sync), listed `smoke`, which is internal, and pointed at four report skills that no longer exist. Content moves to whichever source can keep it true: - the command map to `hyp --help` / `hyp <command> --help` - "what is recording here" to `hyp status` (per-client configured/attached plus the syncing/local-only line) and `hyp policy list` - Codex Desktop specifics to `hyp attach --help` What stays is what no command prints: the data-flow invariants, the HYP_HOME path layout, and the local-versus-opt-in boundary. Also corrects the enrollment story. `hyp join` is not superseded by `hyp remote login`; per LLP 0063 they are two doors to the same enrolled state, attended versus unattended/MDM, and neither is deprecated. The emphasis now leads with `hyp remote login` because LLP 0134 settled that the wizard wraps it and the token join never surfaces. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five Claude skills are things a person triggers, not things Claude should decide to do: stopping and resuming recording, publishing a report to the whole org, editing this machine's skills and CLAUDE.md, and building a site in a git repo. Claude Code's docs recommend disable-model-invocation for exactly this class, alongside /commit and /deploy. Setting it removes each skill's description from context entirely while leaving /name in the user's slash menu, so the affordance is unchanged and the context cost goes to zero. Descriptions shrink to one line each, because with the skill out of context that text is no longer doing routing work; it is just the label in the menu. hypaware-ai-usage-report stays visible on purpose: it is the read-only front door to the report pipeline, and hiding it would break asking for a usage report in plain language. Left to the Codex tree deliberately. disable-model-invocation is a Claude Code extension to the Agent Skills standard, and a strict parser could reject the file outright rather than ignore the key, so it needs testing against Codex before being applied there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
philcunliffe
commented
Jul 29, 2026
neutral review - PR #436 @ |
philcunliffe
left a comment
There was a problem hiding this comment.
Requesting changes. Full review record with evidence: #436 (comment)
Three blocking items, each a place where the PR removes information on a premise that does not survive checking:
hyp claude-desktop installdoes exist. It is registered athypaware-core/plugins-workspace/claude-desktop/src/index.js:109-121(the LLP 0135 pickerconfigure_command) and tested intest/plugins/claude-desktop-install.test.js. The PR description presents its nonexistence as a verified correction; the effect in the diff is that the concrete command a Claude Desktop user needs is replaced by a vaguer pointer athyp claude-desktop --help. Also,src/core/cli/core_commands.js:272-273asserts Claude Desktop "exposes no user-writable settings file", which is the premise LLP 0133 retires (see theactivate()docblock at.../claude-desktop/src/index.js:41-45).Deleting
hypaware-sensitive-scandrops a surfacehypaware-privacydoes not cover.hypaware-privacy/SKILL.mdis unmodified by this PR, and both its description (:3) and body (:11) are gated on the pre-first-sync enrollment review. A local-only, never-enrolled user asking "did I record anything sensitive?" now matches no skill, and the deleted skill's remote-server scan target has no replacement.docs/PRIVACY.mdwas updated; the frontmatter that actually triggers the skill was not.disable-model-invocation: trueonhypaware-ignore/hypaware-unignoreremoves the natural-language opt-out. The deleted descriptions were exactly the utterances LLP 0066 is written around ("don't record this", "ignore this session");llp/0066-session-opt-out.spec.md:10-13,28treats those skills as the contract and says the spec closes the gap without changing the skills. "The affordance is unchanged" holds for the slash menu only. For a privacy opt-out, discovery is the feature. No objection to the same key on the three report skills, but nothing inllp/records the decision and no@refwas added.
Plus two low (hyp init now carries two disagreeing usage strings; a Unicode ellipsis that also misquotes the syncing: ... - local-only: ... line it cites) and three nits, detailed in the record comment.
The mechanical work is clean and verified: manifest / index.js / on-disk skill parity holds in both trees (10/10/10 and 8/8/8), no dangling hypaware-sensitive-scan reference survives, no em dash is introduced, dispatch tests pass 32/32 at this SHA, and the package_bin_boot smoke only prefix-matches the header line the PR edits.
The attach help pointed at `hyp claude-desktop --help` on the premise that `hyp claude-desktop install` did not exist. It does: it is registered in `activate()` (claude-desktop/src/index.js) as the LLP 0135 picker's `configure_command`, alongside `claude-desktop verify`. Also drops the "exposes no user-writable settings file" clause, which is the LLP 0115 premise LLP 0133#plist-surface retires: Desktop does have a real local surface, the root-owned managed-preferences plist. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The six steps always ran any time (the skill's own closing note says re-running later is safe and idempotent), but the description gated every trigger clause on the deferred first sync, and it carried none of the vocabulary the retired hypaware-sensitive-scan used to answer: secrets, credentials, PII, "did I record anything sensitive", "what should I hypignore". A never-enrolled machine is the default state, so that left the most common way to ask for this review matching nothing. Rewrites the description around the audit itself and keeps the enrollment triggers as what they are: the standard time to run it, not a gate. Also reframes the title, intro, Step 2 and the closing notes so an unenrolled reader is not told about a deadline that does not apply to them. No step changes. States the local-cache-only scope explicitly. Scanning a remote server's rows, which hypaware-sensitive-scan offered, has no replacement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Records two decisions this branch was making implicitly. One privacy surface: hypaware-sensitive-scan shipped without an LLP and contradicted LLP 0100 R7 on purge (it promised prospective opt-outs only; 0100 requires purge be offered for every `ignore`). Retiring it needed no supersede or tombstone since nothing in llp/ referenced it, but the resulting scope does need recording: hypaware-privacy is local-cache only, and dropping the remote-server scan is deliberate. Scanning an org server from a member's laptop is impractical and the remedies are machine-local anyway; server-side review belongs behind an operator surface. Model invocation: mark a bundled skill user-invoked only when invoking it publishes, mutates, or spends. That holds for the three report pipeline steps. It does not hold for hypaware-ignore / hypaware-unignore, so this restores their descriptions and drops the key: LLP 0066 is written around the spoken "don't record this conversation", and LLP 0107#gating already says hypaware-ignore is useful unenrolled and that per-skill carve-outs lose to one rule. For a privacy opt-out, discovery is the feature. Also refs the ungating in 0142#any-time back to 0107#gating, which had already decided it, and notes the any-time framing in docs/PRIVACY.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The registry usage string said `hyp init [preset] | hyp init --yes [--client <name>] [--source <name>] [--force]`, which states two false things: that --yes is a required prefix for the non-interactive path, and that four flags exist. Neither holds. INIT_FLAG_NAMES routes to the non-interactive path on any of ten flags, so `hyp init --dry-run` needs no --yes, and six flags were invisible to anyone reading --help. `hyp init` states its interface in three reachable places: this registry entry, the non-TTY/unknown-flag hint (init.js:123,139), and the parser's own usage, which fires when --help is not the first token because dispatch intercepts only rest[0] while parseCommandArgv matches --help anywhere. The other two were already accurate; only this one was wrong. Shortens usage to `hyp init [preset] [flags]` and moves the full list into the help body the PR had just given this command, checked flag by flag against the parser (--from-file takes a v2 config, not answers; --force backs up before replacing; --yes supplies claude + otel only when no --source is given). Exports INIT_FLAG_NAMES and pins both properties in a test, so the help body cannot drift from the dispatcher again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The sentence quoted a `syncing: ... local-only: ...` line three ways wrong: a Unicode ellipsis where the repo wants ASCII, whitespace where status.js:358 emits ` - `, and, worst, flatly as something `hyp status` prints. That write is guarded by `if (report.clientSync)`, which is null on a solo host (LLP 0132 #never-silent), so the line never appears for the default install. A reader was being sent to look for output that is not there. Describes what the command does instead of reproducing its output, which is the drift this PR is otherwise about, and avoids re-encoding the ` · ` list separator the real line also carries. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two nits from review. The epilogue cited `(LLP 0098)` in prose, which /ref-check cannot validate and which no longer resolves: llp/ holds two 0098s (dispatch-miss and scancolumn-where-pushdown), pre-existing duplicate numbering. An anchor was the obvious fix, except both docs also have a `## Decision` heading, so the `#decision` slug dispatch.js:250 already used was ambiguous too. Adds an explicit `unavailable-not-unknown` anchor to the dispatch-miss doc (purely additive; no wording touched on an Accepted doc) and points both refs at it. The epilogue itself stacked three bare nouns before its verb: "running a command a disabled plugin provides names that plugin". Rewritten as a conditional the reader can follow on one pass. Nothing asserts this text; package_bin_boot only prefix-matches the header line, and it passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
bgmcmullen
commented
Jul 29, 2026
Thanks, this was a good catch list. All seven findings are addressed at 1. |
philcunliffe
commented
Jul 29, 2026
neutral re-review - PR #436 @ |
| # | Finding (@ 357f55c) | Status @ 3a78567 |
|---|---|---|
| 1 | [Med] hyp claude-desktop install does exist; "no user-writable settings file" restates a retired premise | ADDRESSED |
| 2 | [Med] Deleting hypaware-sensitive-scan drops a surface hypaware-privacy does not cover | ADDRESSED (one residue, see New/L1) |
| 3 | [Med] disable-model-invocation on hypaware-ignore / hypaware-unignore | ADDRESSED |
| 4 | [Low] hyp init carries two disagreeing usage strings | ADDRESSED |
| 5 | [Low] Unicode ellipsis that also misquotes the syncing: ... - local-only: ... line | ADDRESSED |
| 6 | [Nit] Bare LLP 0098 citation, ambiguous and not in @ref form | ADDRESSED |
| 7 | [Nit] Help epilogue garden-paths | ADDRESSED |
| 8 | [Nit] PR body test arithmetic | ADDRESSED |
1 - ADDRESSED (9deaac7)
The command exists, and it still exists on today's master: hypaware-core/plugins-workspace/claude-desktop/src/index.js:118 (claude-desktop install) and :132 (claude-desktop verify), both registered unconditionally in activate(). PR #445 (74aea66) removed only the manifest attach_probe; it did not touch these registrations, so the finding's premise is intact against current master.
src/core/cli/core_commands.js:284-295 now names both commands. Rendered:
Claude Desktop has no
such settings file: its configuration surface is a root-owned
managed-preferences plist. Set it up with hyp claude-desktop install
(attended, with a sudo prompt) and check it with hyp claude-desktop
verify, when that plugin is active.
The retired premise is gone and what replaces it matches the plugin's own account line for line: index.js:41-50 gives the managed-preferences plist as the real surface per LLP 0133, and "the plist is placed only via the explicit claude-desktop install command, attended, with its own sudo prompt". The help is now strictly more actionable than the hypaware-reference text it replaced, which was the ask. It also does not claim attach-on-join for Claude Desktop, so it reads correctly against #445's landed state (llp/0115#no-attach-on-join, restored at index.js:54-60).
2 - ADDRESSED (77d42fd, 4711975), with one residue
hypaware-privacy/SKILL.md:3 (both trees) now leads with the audit and carries the deleted skill's vocabulary verbatim: "did I record anything sensitive", "scan my logs for secrets", "what should I hypignore", plus an explicit "Runs any time". The first sync is retained as the standard occasion rather than the gate, which is the shape llp/0107#gating asks for, and I confirmed that anchor and both quoted sentences are real: llp/0107-skills-ride-attach.decision.md:75 is - **Enrolled-ness gates behavior, not presence** {#gating}: and :79-81 carries "the skill's deadline framing simply does not arise without a pending first sync" and "hypaware-ignore are useful unenrolled, and one install rule beats per-skill carve-outs". So the claim that the description had been out of step with an Accepted decision holds; it is not a retrofit.
The body follows the description rather than lagging it: the intro, the Step 2 settlement note, and both "After the review" bullets now branch on enrolled vs not. The remote-server drop is stated in the description's last clause and reasoned in llp/0142#local-cache-scope, so it is a visible boundary. That satisfies the ask as written ("or state in the PR that the local-only and remote-scan cases are deliberately dropped") and does better by stating it in the artifact rather than only in the PR.
Not a regression, for the record: the privacy skill body contains no newest-rollout-by-mtime session resolution, so this PR is neutral to issue #452 and to PR #450's CODEX_THREAD_ID change.
3 - ADDRESSED (4711975)
Fully reverted. git diff <merge-base>..HEAD on hypaware-ignore/SKILL.md and hypaware-unignore/SKILL.md shows the descriptions byte-identical to master, the key gone, and the net change reduced to an added @ref (plus one em dash removed from hypaware-unignore). llp/0142#user-invoked-only records the policy with the test stated as publishes / mutates / spends, names all three skills it does cover and why it does not cover these two, and calls out the Claude-only nature of the key. @refs are on all five files.
4 - ADDRESSED (3e159cd)
usage is now hyp init [preset] [flags] and the flag list moved into the help body. I checked all ten descriptions against the parser rather than against the old string:
--yes"captures claude + otel when no --source is given" matchesinit.js:247-251(the push happens only whensources.length === 0 && flags.yes).--client"claude, codex" matches the enum atinit.js:179.--exportchoices matchinit.js:181.--from-file"write a v2 config read from this JSON file" matchesrunInitFromFileatinit.js:303-325(read,JSON.parse,validateConfig), not "the answers".--force"backed up first" matchesprepareLocalConfigWrite/guard.backupPathatinit.js:356-362.
The help body's framing sentence is precise about the routing rather than overclaiming: "the non-interactive path is chosen by the presence of a flag, so --yes is a way to ask for it with no other options, not a prefix the other flags need". That is exactly hasInitFlags (init.js:145-153). The two new tests in test/core/cli/init-help-flags.test.js both ran and passed in my run (ok 297, ok 298), and the second one is a real property test, not a string echo. The registry usage no longer disagrees with the init.js:123,139 hint (which carries a trailing ... and so claims nothing exhaustive) or with init.js:188.
5 - ADDRESSED (9f47389)
The quote is gone in both trees. The replacement at hypaware-reference/SKILL.md:22-25 is accurate: "on a fleet-managed host also splits them into what the fleet forwards and what stays local, so a local addition is never invisible" is the report.clientSync branch at src/core/commands/status.js:349-360, including the guard the author found, and "them" correctly refers to clients, which is what that block splits. No · re-encoding, and no exact-output reproduction to go stale.
Whole-diff character check: git diff <merge-base>..HEAD introduces zero non-ASCII bytes of any kind, so no em dash, no Unicode ellipsis, no middle dot. That is stronger than the PR body's claim and I verified it directly.
6 - ADDRESSED (3a78567)
llp/0098-inactive-not-unknown-dispatch-miss.decision.md:22 gains <a id="unavailable-not-unknown"></a>, purely additive above the existing ## Decision. <a id=...> is established convention here (29 files in llp/ use it). Both refs repoint: dispatch.js:250 and the new dispatch.js:645. The author's extra point is correct and was worth making: an anchor of #decision would not have disambiguated, because 0098-scancolumn-where-pushdown.decision.md also has a ## Decision.
I validated every anchored @ref in the repo at this head and at master with the same checker (<a id> plus {#anchor} plus heading slugs). Head: 1075 anchored refs. Master: 1118. Set difference of broken refs, head minus master, path-normalized: empty. This PR introduces no broken @ref, and all nine of its new ones resolve.
7 - ADDRESSED (3a78567)
Rendered from a real hyp --help run in the worktree:
This list reflects the plugins active in your config. If a command you
expect is missing, run it anyway: hyp names the plugin that provides it
and prints how to enable it.
8 - ADDRESSED
2786 tests, 2783 pass, 2 fail, 1 skip is self-consistent. Different numbers here for environment reasons, also self-consistent: 2785 tests, 2776 pass, 8 fail, 1 skip, and all eight failures are the known pre-existing test/core/leave-command.test.js baseline (not ok 803, 804, 805, 807, 808, 809, 810, 811). Nothing this PR touches fails.
New findings
L1 [Low] The hypaware-reference hand-off still gates hypaware-privacy on the first sync, contradicting llp/0142#any-time that this PR lands
hypaware-core/plugins-workspace/claude/skills/hypaware-reference/SKILL.md:82-83 and the codex copy at the same lines:
- Review captured history before it first syncs to an org server - use the
**hypaware-privacy** skill.
This line is added by this PR (2acca60); master's hypaware-reference has no hypaware-privacy hand-off at all. Three commits later, 77d42fd / 4711975 removed exactly that gating from the privacy skill's own description and wrote the reason into llp/0142#any-time: "only the description and the surrounding prose stop implying the flow is unavailable to an unenrolled machine, which is the default state".
Two reasons this is worth one more line of work rather than a follow-up:
- It is the residue of finding 2, in the surface that finding was about. With
hypaware-sensitive-scandeleted, this hand-off is the only cross-skill pointer from the orientation skill to the privacy audit, and it points there only for the pre-sync case. A model readinghypaware-referenceto route "did I record anything sensitive?" on an unenrolled machine, which is the default state, is told this is the enrollment skill. - The sweep was done and this spot was missed, which shows the intent.
docs/PRIVACY.md:124-127got the correction in77d42fd: "The first sync is the moment this matters most, but it is not a precondition: runhypaware-privacywhenever you want to know what has been captured here, enrolled or not." The reference skill did not.
I swept every other hypaware-privacy mention in the tree and this is the only inconsistent one. src/core/cli/wizard/index.js:330, src/core/cli/remote_commands.js:229, src/core/commands/status.js:385 and README.md:124 are all inside enrollment flows, where llp/0142#any-time explicitly keeps the framing ("the enrollment framing is retained where it applies").
Ask: reword that bullet to lead with the audit, in both trees. Something like "See what was captured here, and mark or purge it - use the hypaware-privacy skill (also the review before an enrolled machine's first sync)."
Also checked, no finding
- Merges cleanly. The branch is 8 commits behind
master(merge base6a64273). The only file both sides touch ishypaware-core/plugins-workspace/claude/src/index.js, in disjoint regions:master(fix(init): stop pinning the gateway listen port so LLP 0114's default applies #433) edits the preset's gatewaylistenat:345, this PR drops'hypaware-sensitive-scan'from the registration list at:252. No textual or semantic conflict. - No stale claim against the eight commits that landed since. The
attach/detach/status/synchelp bodies are consistent with Attach declares the gateway first-party so Claude keeps its real context window #438, detach: report every externally-overridden managed key, not just the last (issue #440 finding 2) #441, hyp init: show the user where they are in the onboarding flow #434 and fix(init): stop pinning the gateway listen port so LLP 0114's default applies #433; I rendered each one frombin/hypaware.jsunder a tempHYP_HOMEand read it against the code paths. hyp initsources copy lists five of the parser's seven--sourcevalues (openclawandhermesare absent). Carried over verbatim frommaster's list, not introduced here, and not part of what this PR set out to fix.hypaware-ignore/hypaware-unignorebodies still carry embeddedcurland the127.0.0.1:8787fallback. Identical tomaster, declared out of scope in the PR body, tracked in Collapse the session opt-out skills ontohyp sessionand update LLP 0066/0067 (blocked by #432) #435. Now actionable, since Give the session opt-out a reader: hyp session ignore/unignore/status, fail-closed #439 landedhyp session ignore/unignore/status.- Pre-existing Unicode ellipses survive in
hypaware-report-to-html's reference files (authoring.md,components.md,example-enrichment.md). Untouched by this PR.
Review-only rung (LLP 0032): no push to skills/trim-and-cli-help, no ready, no merge. Remote head is unchanged at 3a78567. L1 is the only blocker; it is a one-line prose fix in two files.
philcunliffe
left a comment
There was a problem hiding this comment.
Re-reviewed at 3a78567. Full record with evidence: #436 (comment)
All eight prior findings are addressed. All three mediums are properly closed, and in three places the fix is better than what I asked for because you found a further error while making it: the if (report.clientSync) guard, the shared ## Decision heading that made an #decision anchor no better than a bare 0098, and the two wrong flag descriptions in the first-pass init help. llp/0142 is a real decision doc rather than a rubber stamp: it states the test, records the Claude-only asymmetry it creates, and says what a future reinstatement would have to be. I also verified your llp/0107#gating citation rather than taking it: the anchor is real (llp/0107-skills-ride-attach.decision.md:75, {#gating} form) and both quoted sentences are verbatim at :79-81, so the "this was already Accepted" framing holds.
Verification I ran independently: every anchored @ref in the tree resolves, and the set of broken refs at this head minus the set at master is empty, so the PR introduces none (1075 anchored refs checked). The whole diff introduces zero non-ASCII bytes, which is stronger than the PR body's em-dash claim. Both new init-help-flags tests ran and passed, and all ten flag descriptions check out against the parser, not against the old string. All eight test failures in my worktree are the known pre-existing leave-command.test.js baseline. The branch merges cleanly against today's master: the only shared file is claude/src/index.js, in disjoint regions. And finding 1's premise still holds after #445, which removed only the manifest attach_probe and left claude-desktop install / verify registered at index.js:118,132.
One thing left, and it is one line in two files.
[Low] The hypaware-reference hand-off still gates hypaware-privacy on the first sync
hypaware-core/plugins-workspace/{claude,codex}/skills/hypaware-reference/SKILL.md:82-83:
- Review captured history before it first syncs to an org server - use the
**hypaware-privacy** skill.
This bullet is added by this PR (2acca60); master's hypaware-reference has no privacy hand-off at all. Three commits later 77d42fd / 4711975 removed exactly that gating from the privacy skill's own description and wrote the reason into llp/0142#any-time: "only the description and the surrounding prose stop implying the flow is unavailable to an unenrolled machine, which is the default state."
Two reasons I would rather see it fixed here than tracked:
- It is the residue of finding 2, in the surface finding 2 was about. With
hypaware-sensitive-scangone, this is the only cross-skill pointer from the orientation skill to the privacy audit, and it points there only for the pre-sync case. A model readinghypaware-referenceto route "did I record anything sensitive?" on an unenrolled machine, the default state, is told this is the enrollment skill. - The sweep was done and this is the one spot it missed.
docs/PRIVACY.md:124-127got the correction in the same commit: "The first sync is the moment this matters most, but it is not a precondition."
I swept every other hypaware-privacy mention in the tree; this is the only inconsistent one. The wizard, remote_commands.js, status.js and README.md mentions all sit inside enrollment flows, where llp/0142#any-time explicitly keeps the framing.
Suggested reword, both trees: "See what was captured here, and mark or purge it - use the hypaware-privacy skill (also the review before an enrolled machine's first sync)."
No other objection. Fix that bullet and I will approve.
Review-only rung (LLP 0032): no push to skills/trim-and-cli-help, no ready, no merge.
… sync The bullet added in 2acca60 gated the hypaware-privacy hand-off on the first sync to an org server, which is exactly the framing 77d42fd and LLP 0142#any-time removed from the skill itself. Reword it to lead with the any-time audit and keep the pre-first-sync review as the parenthetical occasion, in both trees. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
philcunliffe
commented
Jul 29, 2026
Neutral review record - round 3, head |
philcunliffe
commented
Jul 29, 2026
Verdict at Round 2's single outstanding Low is addressed: the Review-only per LLP 0032: nothing pushed to |
Uh oh!
There was an error while loading. Please reload this page.
Trims the HypAware skill set and moves what the skills were carrying into the CLI, where it can stay true.
The through-line: a skill that summarizes something the CLI already knows will drift, and then mislead. Every deletion here is paired with the command that now answers the question.
1. Remove
hypaware-sensitive-scan(11 → 10 Claude, 9 → 8 Codex)The scan and
hypaware-privacysplit one job in half and had already drifted into contradicting each other on the question users care about most:hypaware-sensitive-scan: "Retroactive purge is out of scope."hypaware-privacy: "Step 6 - Apply only viahypverbs, and offer purge for every ignore (R6, R7)."hyp purgeexists (LLP 0104) and LLP 0100 R7 mandates offering it, so a user who found a credential in their cache was told cleanup was impossible by one skill and offered it by the other.hypaware-privacykeeps the consent protocol (LLP 0100 R3-R9), the three usage classes, and the purge offer. No LLP referenced the scan, so it removes cleanly. Both client trees, both manifests, both registration lists, anddocs/PRIVACY.md.Review follow-up (77d42fd, 4711975). Removing the scan exposed that
hypaware-privacy's own description gated every trigger clause on the deferred first sync, so a never-enrolled machine - the default state - had no way to ask this question in plain language, and none of the scan's vocabulary (secrets, credentials, PII, "what should I hypignore") survived anywhere. The description is now written around the audit itself, with the first sync as the standard occasion rather than a gate. The six steps are unchanged.That is not a new decision: LLP 0107#gating already held that "enrolled-ness gates behavior, not presence" and that the skill's deadline framing "simply does not arise without a pending first sync". The description had been out of step with it.
The scan's remote-server scan target is dropped on purpose, with no replacement. Scanning an org server's whole recorded history from one member's laptop is not practical: unbounded row volume, and the remedies (
hyp policy set,hyp purge) are machine-local and cannot reach rows already forwarded. Server-side review is an operator concern and belongs behind an operator surface, not a client skill. The skill's description states the boundary so the gap is visible rather than assumed.Both are recorded in LLP 0142, which also carries §4's policy.
2. CLI help gets bodies (
attach,detach,status,init,sync)Seven commands rendered as title-and-usage only. Five were exactly the ones whose behaviour lived nowhere but a client skill: invisible to anyone reading
--helpin a terminal, and Claude/Codex-only.Top-level
hyp --helpalso gains three facts a bare command list cannot convey:hypandhypawareare the same binary; the list is install-specific because inactive plugins contribute nothing (pointing at the LLP 0098/0099 miss path); andhyp statusanswers whether the install works.One correction found by verifying rather than transcribing:
hyp init --yesis real but was missing from its usage string.Review follow-up (3e159cd). Fixing that surfaced a worse problem in the same line.
hyp initstates its interface in three reachable places: this registry entry, the non-TTY/unknown-flag hint (init.js:123,139), and the parser's own usage, which fires when--helpis not the first token because dispatch intercepts onlyrest[0]whileparseCommandArgvmatches--helpanywhere in argv. The other two were accurate; the registry string this PR wrote was not. It put--yesoutside the brackets, implying it gates the non-interactive path (INIT_FLAG_NAMESroutes on any of ten flags, sohyp init --dry-runneeds no--yes), and listed four flags with no ellipsis, so it read as exhaustive while six were invisible.usageis nowhyp init [preset] [flags], with the full list in the help body this PR had just added, checked flag by flag against the parser (--from-filetakes a v2 config, not answers;--forcebacks up before replacing).INIT_FLAG_NAMESis exported andtest/core/cli/init-help-flags.test.jspins both properties, so the help body cannot drift from the dispatcher again.- retracted, this claim washyp claude-desktop installdoes not existwrong (caught in review). It is registered unconditionally in the plugin's
activate()(hypaware-core/plugins-workspace/claude-desktop/src/index.js) asthe LLP 0135 picker's
configure_command, withclaude-desktop verifyalongside it, and it has its own test file. Only the statically declared
commands in
hypaware.plugin.jsonwere checked, which is where the falsenegative came from. Fixed in 9deaac7: the
hyp attachhelp body now nameshyp claude-desktop installandhyp claude-desktop verifydirectly, so theCLI is at least as actionable as the skill text it replaced. The same commit
drops the "exposes no user-writable settings file" clause, which restated the
LLP 0115 premise that LLP 0133#plist-surface retires.
3. Shrink
hypaware-reference(169 → 95 lines, 44%)The skill's own preamble declared
hyp --helpauthoritative over anything it summarized, then summarized it anyway in a 45-line command map. That map had drifted exactly as you'd predict: it omitted seven live commands (leave,plugin,policy,purge,report,skills,sync), listedsmoke(internal), and routed to four report skills that no longer exist.hyp --help/hyp <command> --helphyp status,hyp policy listhyp attach --helpAlso corrects the enrollment story:
hyp joinis not superseded byhyp remote login. Per LLP 0063 they are two doors to the same enrolled state (unattended/MDM vs attended), and neither is deprecated; the emphasis now leads withremote loginbecause LLP 0134 settled that the wizard wraps it and the token join never surfaces.Review follow-up (9f47389). One surviving sentence quoted
hyp status's output, and got it wrong three ways: a Unicode ellipsis where the repo wants ASCII, whitespace wherestatus.js:358emits-, and, worst, flatly as somethinghyp statusprints. That write is guarded byif (report.clientSync), which is null on a solo host (LLP 0132 #never-silent), so the line never appears on the default install: a reader was being sent to look for output that is not there. It now describes what the command does instead of reproducing its output, which is the drift this PR is otherwise about, and avoids re-encoding the·list separator the real line also carries.4. Hide user-triggered skills
disable-model-invocation: trueon the three Claude skills where invoking the skill is itself the consequential act:hypaware-publish-report(makes a report org-visible),hypaware-apply-report-changes(mutates this machine's config),hypaware-report-to-html(rewrites a git working tree). Each is a step a person takes on purpose after reading something; none is an answer to a question. This removes their descriptions from context entirely while leaving/namein the slash menu.Revised in review:
hypaware-ignore/hypaware-unignorekeep model invocation. The original argument here was that/namein the slash menu leaves the affordance unchanged. That holds for the three above; it does not hold for these two, where being reachable in the user's own words is the product. LLP 0066 is written around the utterance "don't record this conversation" and treats those skills as the contract the gateway implements, and LLP 0107#gating separately noteshypaware-ignoreis useful unenrolled and that per-skill carve-outs lose to one rule. For a privacy opt-out, discovery is the feature. Their descriptions are restored.The test is now written down in LLP 0142#user-invoked-only: mark a bundled skill user-invoked only when invoking it publishes, mutates, or spends.
@refs on all five skill files.hypaware-ai-usage-reportstays visible on purpose: it is the read-only front door to the report pipeline, and hiding it would break asking for a usage report in plain language.5. Review nits (3a78567)
(LLP 0098)in prose, which/ref-checkcannot validate and which no longer resolves:llp/holds two 0098s. An anchor was the obvious fix, except both docs also carry a## Decisionheading, so the#decisionslugdispatch.js:250was already using had the same defect. Adds an explicitunavailable-not-unknownanchor to the dispatch-miss doc (purely additive, no wording touched on an Accepted doc) and points both refs at it. The duplicate numbering itself is pre-existing and left alone.Deliberately not in this PR
disable-model-invocationis a Claude Code extension to the Agent Skills standard; a strict parser could reject the file outright rather than ignore the key, so it needs testing against Codex first.hypaware-ignore/hypaware-unignorebodies are untouched beyond the frontmatter. They still carry embeddedcurland a stale127.0.0.1:8787fallback. Both collapse to a one-line CLI call once Session opt-out fails open and cannot be checked: restart and session-resume both silently resume recording; addhyp session ignore/unignore/status#432 lands; tracked in Collapse the session opt-out skills ontohyp sessionand update LLP 0066/0067 (blocked by #432) #435.report-to-html72,ai-usage-report46,authoring.md42,query19), which CLAUDE.md forbids. Pre-existing; worth its own sweep.Verification
3a78567: 8/8 checks, test and typecheck on Node 22 and 24.npm testreports 2786 tests, 2783 pass, 2 fail, 1 skip. Neither failure is this PR's and neither reproduces in CI, so both are local-environment artifacts:blob-store.test.js(all 14 subtests pass, the file itself exits nonzero, and it fails identically on a cleanmasterworktree) and thequery-sql-budget.test.jsheap-growth test (7/7 in isolation across three runs, flaky under full-suite memory pressure).test/core/cli/init-help-flags.test.js, 2 tests, both verified non-vacuous against the pre-fix strings.package_bin_bootonly prefix-matches the header line, and it passes at this SHA.git diff master...HEADintroduces zero em dashes and zero Unicode ellipses.package_bin_boot,cli_bundled_plugins_activated,status_diagnostics,client_attach_idempotent(the last materializes skills at attach).index.jsregistration lists (two separate lists that can drift): 10 and 8, matching.Related
#431 (gateway port pin), #432 (
hyp sessionverbs), #435 (collapse the opt-out skills onto them)🤖 Generated with Claude Code