feat(dometrain): add Dometrain course-content grounding plugin#961
Conversation
Approved plan for a new plugins/dometrain plugin (third-party remote Dometrain MCP server, native userConfig credential storage, and a vendored/sync-tracked grounding skill). Survived two stress-test rounds (plan-reviewer + devils-advocate) before approval. Co-Authored-By: Claude Sonnet 5 (Claude Code) <noreply@anthropic.com>
Phase 1 of the dometrain-mcp plan: native userConfig-secured Bearer auth against Dometrain's hosted remote MCP server, installs disabled. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
Phase 2: tool-inventory / ToolSearch-based connection check, per the plan's design correction — /mcp connection status has no callable-tool basis, so this skill never claims to read it directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
…kill Phase 3: grounding (model-invocable, no update action) and sync (disable-model-invocation: true, never model-reachable) split per the plan's devils-advocate CRITICAL fix, so the upstream-content drift fetch can never fire without a human explicitly running /dometrain:sync. vendor/SKILL.md holds the verbatim upstream baseline with an attribution comment placed after the frontmatter (not before, as the plan literally described) — a leading comment breaks YAML frontmatter recognition in markdownlint and would corrupt the verbatim snapshot on every format pass; update.sh's diff strips the comment before comparing so real drift detection stays accurate. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
Phase 4: documents the userConfig setup flow, tool surface, quota caveat, remote-vs-bundled rationale, the official-plugin collision warning, and the grounding/sync skill split. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
Phase 5: adds the dometrain entry after miro's, matching sibling field shape; installs disabled by default. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
Phase 6: corrects the now-stale "no plugin ships a remote MCP server" / "miro is the only plugin that ships one" sentence in criterion 2, and records dometrain's third-party trust-accept review across the 7-point checklist, mirroring the github record's shape. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
…ation Phase 7: real-key smoke test passed (human /mcp check + model-facing /dometrain:setup check both confirmed connected; all 6 tools exercised live). Two fixes fell out of it: - scripts/update.sh's --refresh-baseline path stripped the quotes around grounding/SKILL.md's synced: date on every stamp, turning a quoted YAML string into an unquoted date-like scalar. Caught by an independent fresh-context review. - No documented way to rotate or clear an already-set sensitive userConfig value: /mcp's "Clear authentication" is OAuth-only and silently no-ops for this plugin's static-header auth; the real mechanism is the undocumented-upstream /plugin configure <plugin>, confirmed live this session. Documented in this plugin's README and codified as a standing PLUGIN-PHILOSOPHY.md rule for every future sensitive userConfig option, not just a one-off fix here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
Pre-PR verify gate caught two mechanical gaps: the root README's auto-generated plugin catalog was stale (missing the new dometrain entry), and sync/scripts/update.sh was tracked without the executable bit, which the repo's exec-bit CI gate flags for any tracked shebang script. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
|
Claude finished @kyle-sexton's task in 4m 29s —— View job PR Review: feat(dometrain): add Dometrain course-content grounding pluginTodo list:
Overall assessmentThis is a well-engineered plugin with a strong security posture. The grounding/sync split, FindingsMedium — BSD sed portability in
|
|
Claude finished @kyle-sexton's task in 3m 12s —— View job Security Review — PR #961
|
|
Reply to the code-review findings:
Fixing all three now, will push and follow up with the commit SHA. |
|
Reply to the security-review findings:
Fixing #1 now alongside the review/review findings, will push and follow up with the commit SHA. |
- strip_attribution's ,+1d sed range is GNU-only; BSD sed (macOS)
can't parse it, silently producing no output and permanently
false-positive drift. Replaced with the POSIX-portable {N;d} form,
verified to produce identical output.
- Capture and surface curl's own error detail on fetch failure
instead of discarding it via 2>/dev/null.
- Restore the precise >=90% quota-note threshold in grounding's
SKILL.md — it's a fixed API behavior detail, not the volatile quota
total the Brief's no-hardcoding constraint was actually about.
- Pin update.sh's UPSTREAM_URL to a commit SHA instead of master
(supply-chain integrity), with the bump-then-refresh protocol
documented in context/update.md.
- README: add a security callout on both headless --config install
occurrences (key exposure via shell history / process table).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
|
Fixed in 9f70f91: BSD-portable |
|
Claude finished @kyle-sexton's task in 3m 18s —— View job Security Review — PR #961
|
|
Claude finished @kyle-sexton's task in 1m 55s —— View job Security & Code Review — Re-review after fixes (commit
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f70f91caf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
An independent second reviewer (Codex) caught a regression in the prior commit's fix: pinning UPSTREAM_URL to a fixed commit makes `check` compare the baseline against that same frozen commit forever, so /dometrain:sync can never detect real drift once Dometrain's master moves. The maintainer's diff review before running --refresh-baseline is already the integrity gate the original security-review suggestion was after; the pin added ceremony without adding protection while breaking the tool's actual purpose. Reverted to live master, matching context7's established precedent for the identical fetch pattern. Closed the fleet-wide follow-up item (#963) that would have ported this same regression to context7. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NP1zbEby6gRAQKK9guXFND
|
Claude finished @kyle-sexton's task in 2m 17s —— View job Re-review after
|
| Finding | Source | Status |
|---|---|---|
BSD sed portability in strip_attribution |
Code review | ✅ Fixed in 9f70f91 |
curl error suppressed on fetch failure |
Code review | ✅ Fixed in 9f70f91 |
≥90% quota threshold dropped |
Code review | ✅ Fixed in 9f70f91 |
API key exposed via headless --config install |
Security review | ✅ Fixed in 9f70f91 |
Unpinned master fetch (supply-chain) |
Security review | ✅ Applied in 9f70f91, correctly reverted in 89a7fa0 after Codex found the regression |
Doc drift: context/update.md/upstream-version reference master after pin |
Security re-review | ✅ Resolved as side effect of 89a7fa0 |
| Pin makes drift check compare frozen commit forever | Codex P2 | ✅ Fixed in 89a7fa0 |
Bare tool names in grounding/SKILL.md |
Codex P2 | ✅ Correctly dismissed — first-party tool reference, not cross-plugin |
|
Claude finished @kyle-sexton's task in 3m 3s —— View job Security Review — PR #961 (HEAD
|
|
Acknowledged — the re-opened supply-chain SUGGESTION is an accepted, documented trade-off (rationale in |
No related issue: scoped directly from an approved implementation plan (docs/topics/dometrain-mcp/PLAN.md), not a tracked issue.
Summary
plugins/dometrainplugin: Dometrain course-content grounding over a third-party remote MCP server (https://mcp.dometrain.com/mcp, Bearer auth), with the key entered once through Claude Code's native maskeduserConfigprompt and stored in secure credential storage — the one thing Dometrain's own official plugin (env-var auth) cannot provide.setupskill (tool-inventory/ToolSearch-based connection check —/mcpconnection status has no callable-tool basis, confirmed against official docs), agroundingusage skill (model-invocable, vendored from Dometrain's own official skill with a standing untrusted-data/prompt-injection defense), and a separatesyncskill (disable-model-invocation: true, never model-reachable — only a human's explicit/dometrain:syncfires the upstream drift check).docs/MIGRATION-PLAYBOOK.mdgets a new third-party ACCEPT review record and corrects a now-stale "no plugin ships a remote MCP server" sentence.docs/PLUGIN-PHILOSOPHY.mdgets a new standing rule (discovered during the real-key smoke test): everysensitive: trueuserConfigoption's README must document/plugin configure <plugin>as the rotation/clear path, since/mcp's "Clear authentication" is OAuth-only and no-ops for static-header auth.melodic-software/claude-code-plugins#954(context7:lookup'supdateaction has the identical model-reachable-sync gap this plan fixed for dometrain) andmelodic-software/claude-code-plugins#958(miro's README has the identical key-rotation documentation gap).Test plan
claude plugin validate plugins/dometrainandclaude plugin validate --strict .both exit 0scripts/validate-plugins.shequivalent run manually)skill-quality:checkPASS forsetup,grounding, andsync--plugin-dirinstall in a scratch repo, nativeuserConfigprompt,/mcpshowsconnected/authenticated,/dometrain:setup checkindependently reportsconnectedfrom tool-inventory presencelist_courses,get_usage,search_code,get_course,search_dometrain,get_lessonvia citation) — grounding skill triggers and citesdeep_linkvalues correctlycode.claude.com/docs/en/mcp: a rejected staticAuthorizationheader reportsfailed, confirming the setup skill'sfailed or unverifieddesign)README.mdcatalog regenerated (node scripts/generate-catalog.mjs) to include the newdometrainentryRelated
Refs #954 — fleet-wide context7:lookup model-reachable-sync gap, same fix pattern
Refs #958 — miro README key-rotation documentation gap, same fix pattern