Skip to content

[AI-58] llm: add bitwarden-planning-tools plugin with consulting-adrs skill - #177

Draft
SaintPatrck wants to merge 4 commits into
mainfrom
consulting-adrs-planning-tools
Draft

[AI-58] llm: add bitwarden-planning-tools plugin with consulting-adrs skill#177
SaintPatrck wants to merge 4 commits into
mainfrom
consulting-adrs-planning-tools

Conversation

@SaintPatrck

@SaintPatrck SaintPatrck commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

🎟️ Tracking

AI-58

📔 Objective

Adds bitwarden-planning-tools, a new plugin housing pre-implementation planning and preparation skills.

Its first skill is consulting-adrs: it checks a design, change, plan, or threat model against Bitwarden's Architecture Decision Records, or locates and summarizes the catalog, returning structured findings (conflict, gap, stale-reference, aligned) with cited ADRs. A cited URL is confirmed against the catalog index, so a finding never carries a link that does not resolve.

The skill runs as a forked subagent and blocks until it returns, so consulting the catalog never pulls untrusted public HTML into the calling conversation. The caller passes the subject in and gets findings back. Inside the fork, WebFetch is scoped to contributing.bitwarden.com alongside Read and Grep, while Write, Edit, NotebookEdit, and Agent are removed, the last of those because a forked agent otherwise delegates its way around its own tool scope.

Ships a full eval harness per the AI Review Guidelines (triggering, structure, behavior) with baselines on claude-opus-4-8, graded blind by claude-opus-5 and claude-sonnet-5, recorded in skills/consulting-adrs/evals/.

#178 wires bitwarden-security-engineer's ADR-alignment checks to this skill and is stacked on this PR, which must land first.

@SaintPatrck SaintPatrck added the ai-review Request a Claude code review label Jul 31, 2026
@github-actions

Copy link
Copy Markdown

Claude Code is validating plugin components and security...

If this comment does not update with results, check the Actions log.

@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Re-reviewed bitwarden-planning-tools and its consulting-adrs skill; no commits have landed since the previous review pass, so this is a verification of the existing state rather than new analysis. The skill runs as a forked subagent (context: fork, agent: general-purpose, background: false), takes its subject as an explicit input, scopes WebFetch to contributing.bitwarden.com, and carries the untrusted-fetched-content and no-fabrication rules. Version 1.0.0 is consistent across marketplace.json, the plugin manifest, the root README catalog, and CHANGELOG.md; no agents exist, so nothing further to sync. Eval artifacts are internally consistent — baseline.json counts match the 12 cases in trigger-eval.json, and benchmark.json now records equal run counts per arm.

Code Review Details
  • ⚠️ : Bash is absent from disallowed-tools, so the fork retains write and egress paths despite Write/Edit/NotebookEdit/Agent removal (still-open finding from a prior round; not re-posted)
    • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:5

No new findings this round. Prior threads were checked and not reopened: the em-dash re-escaping churn in .claude-plugin/marketplace.json is resolved, the eval run-count asymmetry is resolved (benchmark.json now records 3 runs per arm), and the dropped-negative-case and finding-template threads were answered as scope decisions by the author.

No dependency manifest files are touched by this PR.

Comment thread plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md Outdated
Comment thread plugins/bitwarden-planning-tools/README.md Outdated
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Claude Code validation

Result: Pass

Validated the new bitwarden-planning-tools plugin and its consulting-adrs skill against merge base 8bdc144 (main) at head 00f6b90. Three passes ran: plugin validation, skill review, and configuration & security review. No critical findings and nothing that weakens security — the items below are quality and correctness warnings, listed most consequential first.

Critical

None.

Major

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:3The skill's input contract is stated where the caller can never read it. With context: fork, the body becomes the subagent's prompt and the calling model sees only description. Lines 21–25 require the invocation to carry the full subject ("A one-line description is not a subject") and instruct the fork to emit one line and stop if it does not — but nothing in the description tells the caller to pass the design/diff/plan text through, so the hard-stop path is the likely default in real use. The evals cannot catch this: every prompt in evals.json embeds the change inline, so the harness does by hand exactly what a real caller was never told to do. Fix: move the contract into the description, e.g. append "Pass the design, diff, plan, or threat model text in the invocation — this skill runs in an isolated context and cannot see the conversation."

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:3The description omits the PR/diff vocabulary, and the skill's own baseline records the resulting miss. Verified in evals/baseline.json: the should-trigger case "Review my PR for alignment with our recorded architecture decisions." fires at trigger_rate: 0.333, failing silent on 2 of 3 runs rather than losing to a competitor — the signature of a description-coverage gap. evals/README.md:48 already books it as a known issue. The description says "design, change, plan, or threat model" and never says diff, PR, pull request, or "alignment"; only the body (line 13) mentions "diff", which is invisible at trigger time. Fix: add the missing surface to the description ("Check a design, diff, pull request, plan, or threat model …") and include "alignment with recorded architecture decisions" as a trigger phrase, then re-run trigger-eval.json.

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/evals/fixtures/adr/9001-result-types-for-expected-errors.md:1 (same for 9002, 9003, 9004, 9005) — Synthetic ADR fixtures carry no in-band marker, so they can be cited as real Bitwarden decisions. The five fixtures faithfully imitate the real catalog's frontmatter (adr/status/date/tags), heading form, and <AdrTable frontMatter={frontMatter}></AdrTable> line. Verified: nothing inside any fixture marks it synthetic — the only warning lives in evals/README.md:13-20 ("They are NOT real Bitwarden decisions"), a file the skill never reads. Meanwhile SKILL.md:15 tells the skill to Grep/Read local ADR files in preference to the site. The precondition is narrower than it first looks (line 15 is guarded on a bitwarden/contributing-docs checkout being present), but if the skill ever resolves evals/fixtures/adr/ as that catalog it will emit e.g. [CONFLICT] … ADR 9002 Adopt Vitest … superseded by ADR 9005 Adopt Jest in its authoritative finding format. That defeats the skill's own rule at SKILL.md:60 ("Never invent an ADR number, title, or URL"), because from the skill's point of view nothing was invented. Mitigation is partial: with no index.mdx in the fixtures directory the skill would cite the local path rather than a URL per SKILL.md:54, so the path is a tell — but the number, title, and decision text still read as real. Fix: mark the fixtures in-band, not just in the sibling README — add a fixture: true frontmatter key plus a first-body-line banner (> TEST FIXTURE — synthetic ADR for eval grading. Not a real Bitwarden decision.) to each of the five, and optionally add a rule telling the skill to ignore ADR files under an evals/fixtures/ path.

Minor

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:11 — The H1 "Validate against ADRs" mis-frames the skill's second mode. Catalog locate/summarize is a single parenthetical at line 17 under a heading and lead paragraph that both say "validate", and benchmark.json shows summarize-adr-catalog at 0.0 delta on both graders — no lift over baseline. Fix: retitle to a mode-neutral H1 (e.g. "Consulting ADRs", matching name:) and give the catalog mode its own section with its own output shape.

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:4 and :15 — The local-checkout path is instructed but not equipped or requested. Line 15 says to Grep/Read a local bitwarden/contributing-docs checkout; allowed-tools grants WebFetch(domain:…), Read, Grep but not Glob, so directory discovery is not pre-approved (still callable, just prompt-gated, which in a forked run is a stall). More basically, nothing asks the caller for the checkout path — the evals hand it over in the prompt (evals.json:4), real invocations will not, and the fork's cwd is the user's product repo. Fix: add Glob to allowed-tools and state in the description that a local contributing-docs path may be passed, otherwise the skill fetches the site.

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:5disallowed-tools does not fully close the write path it targets. Write, Edit, NotebookEdit, Agent are blocked but Bash is not, and Bash writes files (>, tee, sed -i). This is not a security weakening — Bash is absent from allowed-tools, so it stays permission-gated at its normal default rather than being widened by this changeset — but if the intent is a read-only advisory skill the block is incomplete. Fix: add Bash to disallowed-tools; consider listing Task alongside Agent if older runtimes are in scope, so the subagent block is not a silent no-op.

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:6-8 and plugins/bitwarden-planning-tools/README.md — Fork mode is undocumented and version-gated. context: fork / agent / background are all valid, honored keys, but background requires Claude Code v2.1.218+. On an older client they are ignored and the skill runs inline, at which point SKILL.md:21 ("This skill runs in its own context and sees nothing of the calling conversation") is factually wrong for that run. Neither the README nor the changelog mentions it, and this is the only skill in the repo using fork mode. Fix: add a one-line note to the plugin README and the changelog entry.

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:29-35 — Duplicates existing ADR-alignment doctrine with no cross-reference in either direction. plugins/bitwarden-security-engineer/references/adr-alignment.md already encodes the same rules (conflict = finding, undocumented significant decision = gap, verify status before citing) and is invoked by threat-modeling/SKILL.md:12 and reviewing-security-architecture/SKILL.md:133. Since this skill's description explicitly claims "threat model" as a subject, the two will drift and neither delegates. Fix: have the security-engineer reference point at consulting-adrs as the implementation, or note the relationship in the planning-tools README.

  • plugins/bitwarden-planning-tools/CHANGELOG.md:8 — Release date 2026-07-30 predates the work. Verified: the earliest commit on this branch is dated 2026-08-05 and head 00f6b90 is 2026-08-14; today is 2026-08-25. Peer plugins date entries at actual release. Fix: update to the merge date.

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/evals/README.md:12benchmark.json keying is easy to misread as model arms. The README describes it as "with-skill vs baseline" and says baselines were recorded on claude-opus-4-8, but every rate in benchmark.json is keyed by grader model (claude-opus-5, claude-sonnet-5) while model_runner is claude-opus-4-8. The dual-grader rationale at benchmark.json:6 is not mentioned in the README, so the keys read like runner arms. Fix: add a clause noting rates are per-grader, with claude-opus-4-8 as the single runner.

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:39 — Ambiguous referent in the output spec. "The roll-up is the last line: no preamble before it, no notes … after it" — "it" reads as the roll-up in the first clause and the whole output in the second. Fix: "Emit the findings, then the roll-up as the final line; no preamble, notes, or commentary."

  • plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md:3 — The description states no negative boundary. trigger-eval.json:39 expects no-fire on "Update ADR-0012's status to superseded…"; the description could make that structural. Fix: add "Reads and cites ADRs; does not author or edit them."

Notes (not findings)

  • Word count. The SKILL.md body is ~674 words, below the 1,000–3,000 guideline. No action recommended — the body is the fork's prompt, every section is load-bearing, and there is no detail worth pushing to references/. Recorded only so the under-count is not later read as an omission. Do not pad it.
  • No prompt injection found. Every changed file was checked for text attempting to direct this review or the agent (CWE-1427); nothing qualifies. Two candidates were considered and cleared: SKILL.md:63 instructs the skill to treat fetched ADR pages as untrusted data, which is defensive guidance for the skill's own future runs matching existing repo practice, not an attempt to steer a reviewer; and evals/fixtures/adr/9003-inline-sql-in-repositories.md:32 addresses a hypothetical ADR reader, which is the point of the deprecated-status test case.

Verified clean

  • Secrets: no credentials anywhere in the changeset. The only pattern hit is "skill_token": null in evals/baseline.json:4, an eval metadata field with no value. No settings.local.json added or modified; no settings, hooks, agents, commands, or CLAUDE.md changed, so there are no permission-scoping or auto-approval changes to assess.
  • Manifest and versioning: plugin.json is valid JSON, name is kebab-case and matches the directory, 1.0.0 is valid semver for a new plugin, and the field set matches peer manifests. Version is consistent across all required places — plugin.json:3, the .claude-plugin/marketplace.json entry (line 87), and the README.md:15 catalog row. No agents exist, so no AGENT.md version to sync. Changelog entry follows Keep a Changelog.
  • Structure: skills/consulting-adrs/SKILL.md sits at the discoverable path. No commands/, agents/, hooks/, or .mcp.json, so no hook-schema or MCP-transport concerns. No stray files.
  • Frontmatter: all six keys (name, description, allowed-tools, disallowed-tools, context, agent, background) are real, honored SKILL.md fields with valid values; WebFetch(domain:…) scoping syntax is valid; name matches the directory.
  • Referenced files exist: every path named in evals.json, benchmark.json, and evals/README.md resolves, including all five fixtures and fixtures_dir. SKILL.md references no in-repo paths.
  • Eval internal consistency: benchmark.json's four aggregates recompute correctly from the nine per-case rates; case names match evals.json; the README's "four cases do not discriminate" claim matches the four zero-delta cases exactly; the documented 1/3 under-trigger is genuinely recorded in baseline.json; 4/4 should-not-trigger cases sit at 0/3. Fixture numbering (9001–9005) is clear of the real ADR range.
  • URL-derivation rule: SKILL.md:52 claims docs/architecture/adr/0030-adopt-pnpm.md publishes at contributing.bitwarden.com/architecture/adr/adopt-pnpm. Checked live — that URL resolves and the number-prefixed form 404s, so the rule and the eval assertion anchored to it are correct.
  • Lint: prettier --check and cspell both pass on the added and modified files; no .cspell.json additions needed.

Checks run

Check Status
Plugin structure Not run here — dedicated workflow step; see the job log and check status
Marketplace Not run here — dedicated workflow step; see the job log and check status
Version bump Not run here — dedicated workflow step; see the job log and check status
Plugin validation (AI) Passed with findings — bitwarden-planning-tools
Skill review (AI) Passed with findings — consulting-adrs/SKILL.md
Configuration & security Passed — security scan clean; no agents, commands, hooks, settings, or CLAUDE.md in this PR

The three script checks are run by the workflow as dedicated steps before this review, so their absence from this report is not a pass — read their results from the job log.

Comment thread .claude-plugin/marketplace.json Outdated
SaintPatrck added a commit that referenced this pull request Aug 5, 2026
Comment thread plugins/bitwarden-planning-tools/skills/consulting-adrs/SKILL.md Outdated
SaintPatrck added a commit that referenced this pull request Aug 5, 2026
@SaintPatrck
SaintPatrck force-pushed the consulting-adrs-planning-tools branch from d4374e1 to 928b0d5 Compare August 5, 2026 18:54
SaintPatrck added a commit that referenced this pull request Aug 5, 2026
@SaintPatrck
SaintPatrck force-pushed the consulting-adrs-planning-tools branch from 928b0d5 to ab8303f Compare August 5, 2026 19:00
@SaintPatrck
SaintPatrck marked this pull request as ready for review August 5, 2026 19:03
@SaintPatrck
SaintPatrck requested a review from a team as a code owner August 5, 2026 19:03
Comment on lines +12 to +17
"should_not_trigger_pass": "4/4",
"reliability": {
"all_runs_agree_rate": 0.9166666666666666,
"should_trigger_reliable": "7/8",
"should_not_trigger_reliable": "4/4"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUESTION: The two negative cases that over-triggered were dropped and the reliability figures recomputed — scope decision or worth re-running?

Details

ab8303f removed "Help me write a new ADR documenting the token-rotation decision we just landed on." and "What's an ADR and when should our team bother writing one?" from trigger-eval.json, and adjusted this block to match: should_not_trigger_pass 6/64/4, all_runs_agree_rate 0.7860.917, should_not_trigger_reliable 4/64/4. Those were the only two negative cases that failed (each fired 1/3), and the _notes line disclosing them was trimmed at the same time.

The remaining 12 per-query records are self-consistent with the new totals, so nothing here misreports. Two things worth confirming:

  1. If the removal was a scope call (authoring and conceptual asks are arguably ambiguous labels rather than skill defects), a one-line note in evals/README.md under "Known issues / boundaries" would keep that reasoning with the artifact — the under-trigger case is documented there, this one now isn't.
  2. If they are still in scope, ADR-authoring is the nearest over-trigger boundary for this skill and now has only partial coverage via "Update ADR-0012's status to superseded...".

Either resolution is fine; the ask is that the recorded baseline carries the reasoning, since it's what the next refresh will be compared against.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scope decision. The dropped tests were flakey and not relevant until competing or complimentary skills are identified.

name: consulting-adrs
description: Check a design, change, plan, or threat model against Bitwarden's Architecture Decision Records (ADRs), or locate and summarize the ADR catalog. Use when assessing whether an approach conflicts with, is governed by, or lacks an accepted ADR, or when someone needs to find or summarize ADRs. Produces structured findings (conflict, gap, stale-reference, aligned) with cited ADRs, or an ADR summary when that is the ask.
allowed-tools: WebFetch(domain:contributing.bitwarden.com), Read, Grep
disallowed-tools: Write, Edit, NotebookEdit, Agent

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ IMPORTANT: Bash survives the fork's tool removal, reopening the write and egress paths the fork exists to close.

Details and fix

The commit message states the reason for the fork plainly: the catalog fetch pulls untrusted public HTML into the context, and line 63 codifies that contributing.bitwarden.com is not trusted-by-construction. disallowed-tools removes Write, Edit, NotebookEdit, and Agent — the last one, per the PR body, because a forked agent otherwise delegates its way around its own tool scope.

Bash does the same thing more directly. With agent: general-purpose, the fork starts from the full tool set, and allowed-tools is a pre-approval rather than a ceiling (claude-config-validator/skills/reviewing-claude-config/reference/claude-code-requirements.md:32) — which is exactly why disallowed-tools is needed here in the first place. A Bash-capable fork can write files (>), reach hosts outside the WebFetch domain scope (curl), and read anything under cwd, so removing Write/Edit alone does not hold the boundary against content injected into a fetched ADR page.

The skill needs WebFetch, Read, and Grep; it has no use for Bash.

disallowed-tools: Write, Edit, NotebookEdit, Agent, Bash

If forked skills do resolve allowed-tools as an exhaustive allowlist, this is belt-and-braces and costs nothing; if they don't, it closes the widest remaining hole in the isolation this commit builds.

Establish bitwarden-planning-tools as the pre-implementation planning home
(counterpart to bitwarden-delivery-tools' post-implementation mechanics), and
land consulting-adrs here as its first skill.

consulting-adrs checks a design/change/plan/threat-model against Bitwarden's
ADRs (or locates/summarizes the catalog) and returns structured
conflict/gap/aligned findings with cited ADRs. Ships the full eval harness
(trigger/structure/behavior) with baselines on claude-opus-4-8: triggering
7/8 should-trigger, 6/6 should-not; behavior with-skill 1.00 vs baseline 0.78
over 9 cases. WebFetch scoped to contributing.bitwarden.com.

Proposed as the future home for tech breakdowns, initiative-funnel navigation,
and architecting-solutions as planning tools consolidate here.
Treat fetched ADR pages as untrusted data, matching the sibling
architecting-solutions skill's rule for the same domain. Drop the
Cross-Plugin Integration table's consumer inventory rather than
correct its premature claim — a skill has no need to track which
plugins call it, and the table's only other row duplicated the
Overview's own counterpart framing.
The catalog fetch pulls untrusted public HTML into whatever conversation asks for
a validation, so the skill runs in its own context and returns only findings.
Isolation means the subject arrives as an explicit input rather than ambient
context, and a templated output keeps the roll-up terminal. A cited URL is
confirmed against the catalog index, because a derived URL that does not resolve
is worse than no URL.
@SaintPatrck
SaintPatrck force-pushed the consulting-adrs-planning-tools branch from d487c03 to 00f6b90 Compare August 25, 2026 14:32
@SaintPatrck
SaintPatrck marked this pull request as draft August 26, 2026 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant