feat(ai-briefing): publish generic engine plugin with named-profile seam - #122
Conversation
Author a repo-agnostic ai-briefing engine plugin from the medley in-repo skill:
multi-wave collection, dedup/rank, retro/search/drift actions, per-profile runner,
and the slides/html/pdf build pipeline — engine only, no employer/personal layers.
- Named-profile seam (profiled-folder convention): curated following-list, brand
overlay, and stack lens resolve from .claude/ai-briefing/[<profile>/], falling
back to a bundled neutral seed. Runtime state (seen-items, runs, generated decks)
persists per profile under ${CLAUDE_PLUGIN_DATA}; config never does.
- Neutral default brand (no employer logos); pragmatic-use ranking lens and
apolitical filter ship as documented, overridable defaults; the impact tag is
profile-provided and optional.
- Re-runnable /ai-briefing:setup action scaffolds a profile and persists runtime
deps under ${CLAUDE_PLUGIN_DATA} (plugin cache is read-only).
- Decoupled from medley paths; validated with claude plugin validate --strict and
loaded via --plugin-dir in a clean repo. Scripts + build unit tests green.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_65eb402d-8dcb-446f-ae57-cf22aa18a6eb) |
|
Claude finished @kyle-sexton's task in 3m 46s —— View job PR Review: feat(ai-briefing): publish generic engine plugin with named-profile seamTasks:
SummaryThis is a large but coherent plugin. The architecture (engine-only, no employer layer; state vs. config split; plugin-cache isolation; named-profile seam) is well-designed and correctly implements the CLAUDE.md plugin-form rules. The atomic-write pattern, Zod validation on all structured I/O, and the clean Several issues are worth addressing before merge, ranging from a data-quality bug in state management to a model-ID hard-coding that will cause future failures. Findings🔴 Correctness —
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 286a345c04
ℹ️ 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".
- MD049: use asterisk emphasis in the SKILL.md data-file table. - typos: invokable -> invocable; reword incidental "Canva"/"mis-parsed"/"Nd"; wrap the creator-handle list in providers.md with spellchecker off/on. - exec-bit: mark scripts/per-profile-runner.js executable (it has a shebang).
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_2d85c513-dd9b-48c4-b337-e1b4b3d526d4) |
|
Claude finished @kyle-sexton's task in 4m 7s —— View job PR Review: feat(ai-briefing): publish generic engine plugin with named-profile seamTasks:
SummaryThe engine architecture (state vs. config split, plugin-cache isolation, named-profile seam, atomic writes, Zod validation throughout) is well-designed and the CLAUDE.md plugin-form rules are correctly followed. However, reading the code reveals several correctness gaps, two of which are blocking at runtime rather than merely latent. 🔴 Blocking — ESM scripts ignore
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 85e25bfc8f
ℹ️ 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".
…ture deferred
Address blocking review findings before publish:
- ESM ignores NODE_PATH, so a persisted node_modules beside the read-only plugin
cache is unreachable. setup now stages a runnable copy of the scripts/build
trees into ${CLAUDE_PLUGIN_DATA}/runtime with node_modules installed as a
sibling and runs from there, so the standard ESM walk resolves zod. Re-stages
on a plugin-version bump. Verified in a plugin-form simulation (zod resolves;
runner test suite passes from the staged copy).
- grok-capture is documented but not registered in the runner's buildSubcommands()
dispatch, so it would error. Marked NOT-YET-WIRED in the standing default and
the runner-architecture reference; --grok-preload is a planned flag until a
follow-up wires it. Chrome Wave 1 remains the full, canonical path.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_aafe2a95-8418-4167-bdf3-d7a955aa8551) |
|
Claude finished @kyle-sexton's task in 3m 47s —— View job PR Review (follow-up): feat(ai-briefing): publish generic engine plugin with named-profile seamTasks:
What the latest commit (
|
| Priority | Finding | File |
|---|---|---|
| 🔴 | partial → complete promotion hides failed stages |
per-profile-commands.js:346 |
| 🔴 | Named profile skips default curated follow-list | per-profile-following.js:15 |
| 🟡 | Profile branding never applied to deck output | emit-slides-data.js:14 |
| 🟡 | source_type always "twitter" |
state.js:137 |
| 🟡 | Unsanitized JS template injection | chrome-extract.js:343 |
| 🟡 | Model ID hard-coded | synthesize-agent.js:189, categorize-agent.js:133 |
|
Thanks — verified each finding at the source. Resolutions: 🔴 ESM ignores 🔴 🟡 Positives noted — thanks for the thorough read. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f2c826d2b
ℹ️ 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".
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_bfc6f25f-1354-4cca-b261-7dc83778508b) |
|
Claude finished @kyle-sexton's task in 4m 24s —— View job PR Review (follow-up): feat(ai-briefing): publish generic engine plugin with named-profile seamTasks:
What
|
| Priority | Finding | Status |
|---|---|---|
| 🔴 | partial → complete promotion hides failures |
Open, not tracked |
| 🔴 | Named profile skips default curated follow-list | Open, not tracked |
| 🟡 | cutoff_reached always false (extractor past not propagated) |
New finding |
| 🟡 | active_profile userConfig not wired to AI_BRIEFING_PROFILE |
New finding |
| 🟡 | Profile branding static import | Tracked in #1457 |
| 🟡 | source_type always "twitter" |
Tracked in #1457 |
| 🟡 | Unsanitized JS template injection | Tracked in #1457 |
| 🟡 | Model ID hard-coded | Tracked in #1457 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff8fa99d41
ℹ️ 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".
# Conflicts: # .claude-plugin/marketplace.json # README.md
…eat/publish-ai-briefing
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c0f2db98-669b-485e-bec6-bd717710a26f) |
|
Claude finished @kyle-sexton's task in 3m 33s —— View job PR Review (follow-up): feat(ai-briefing): publish generic engine plugin with named-profile seamTasks:
What changed since the last review (
|
| Finding | Status |
|---|---|
Profile branding static import (emit-slides-data.js:14) |
Tracked in #1457 |
source_type always "twitter" (state.js:137) |
Tracked in #1457 |
Unsanitized handle/cutoff in JS template (chrome-extract.js:343) |
Tracked in #1457 |
Model ID hard-coded (synthesize-agent.js:189, categorize-agent.js:133) |
Tracked in #1457 |
Summary
No plugin code changed since the last review cycle. Six issues remain open across correctness, security, and doc consistency:
| Priority | Finding | File |
|---|---|---|
| 🔴 | partial → complete promotion hides stage failures |
per-profile-commands.js:346 |
| 🔴 | Named profile skips default curated follow-list | per-profile-following.js:15 |
| 🟡 | cutoff_reached always false (extractor past not propagated) |
per-profile-validate.js:8, chrome-extract.js |
| 🟡 | active_profile userConfig not wired to AI_BRIEFING_PROFILE |
SKILL.md:104 |
| 🟡 | EXTRAS (Robotics) heading misroutes to real-world bucket |
emit-slides.js:56 |
| 🟡 | Reference docs use bare runner path (contradicts staged setup) | execution-flow.md:16, runner-architecture.md |
The two 🔴 items (status promotion and follow-list fallback) are functional correctness gaps that affect every named-profile run. The EXTRAS bucket misrouting and cutoff_reached always false are newly confirmed. Recommending these six be addressed or explicitly deferred before merge.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23838f2dd9
ℹ️ 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".
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c7325684-a492-4abd-af8c-9008b45fb91f) |
PR Review (follow-up): feat(ai-briefing): publish generic engine plugin with named-profile seamTasks:
|
There was a problem hiding this comment.
Stale comment
Risk: medium. Did not approve because Cursor Bugbot completed with skip status, so the required automated review did not complete successfully. Human review is needed before merge; no reviewers were assigned because the PR author is the sole human repository contributor.
Sent by Cursor Approval Agent: Pull Request Router and Approver
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a526b9d4-29ed-4597-94f4-d956b6723b97) |
|
Claude finished @kyle-sexton's task in 2m 29s —— View job PR Review (follow-up): feat(ai-briefing): publish generic engine plugin with named-profile seamTasks:
What
|
| Finding | File |
|---|---|
| Profile branding static import | emit-slides-data.js:14 |
source_type always "twitter" |
state.js:137 |
| Unsanitized handle/cutoff in JS template | chrome-extract.js:343 |
| Model ID hard-coded | synthesize-agent.js:189, categorize-agent.js:133 |
Summary
No plugin code changed in 729c19a. Six issues from prior review cycles remain open. The two 🔴 items are correctness gaps that affect every run (status accounting, follow-list fallback). The remaining four are functional or doc gaps worth resolving before this lands in the public marketplace.
| Priority | Finding | File |
|---|---|---|
| 🔴 | partial → complete promotion hides stage failures |
per-profile-commands.js:346 |
| 🔴 | Named profile skips default curated follow-list | per-profile-following.js:15 |
| 🟡 | cutoff_reached always false |
per-profile-validate.js:8 |
| 🟡 | active_profile userConfig not wired to AI_BRIEFING_PROFILE |
SKILL.md:104 |
| 🟡 | EXTRAS (Robotics) misroutes to real-world bucket |
emit-slides.js:56 |
| 🟡 | Reference docs use bare runner path | execution-flow.md:16, runner-architecture.md:41 |
There was a problem hiding this comment.
Risk: medium. Did not approve: Cursor Bugbot did not complete (check skipped due to usage limit), so the required automated review signal is unavailable. Human review is needed before merge; no reviewers were assigned because the PR author is the sole human repository contributor.
Sent by Cursor Approval Agent: Pull Request Router and Approver
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 729c19ab48
ℹ️ 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".
…findings (#156) Post-publish behavior fixes for the `ai-briefing` plugin, surfaced by bot review on the publish PR (#122). All were pre-existing engine characteristics carried over in the migration; none block plugin load/validate. ## Ships - **Wire `grok-capture` (Wave 0 S0).** Registered `cmdGrokCapture` in the runner dispatch (thin adapter over `grok-capture-agent.js`). `init --grok-preload` now probes the Grok CLI and sets `config.grok_preload` / `grok_preload_requested` — degrades to `grok_degraded` on a missing/unsigned CLI, or hard-fails with `--require-grok`. `next-handle` surfaces `grok_preload`; S3 `synthesize` merges Grok captures with Chrome (`mergeTweetLists`, Chrome URLs win on dedup). Non-blocking: preload-disabled or a capture error records `S0_grok_capture: skipped` and exits 0 so Chrome Wave 1 always proceeds. Added `grok-wave0-orchestration.test.js` to the `scripts` test script and un-deferred the docs (SKILL.md standing default #20, `references/runner-architecture.md`). - **`source_type` no longer hard-coded `"twitter"`** in `state.js` `appendToSeenItems` — honors `item.source_type ?? "twitter"`. This runner is the Wave-1 X (twitter) loop, so the default stays correct for its own items; the change generalizes the writer so the main-session-driven RSS/Perplexity/GitHub waves (which append to the same store per the documented `twitter|blog|changelog|github` schema) can record their own source. No other in-plugin caller sets a non-twitter source today — the threading is the forward-compatible fix, deliberately, not a missed one. - **Single model constant.** `lib/models.js` `BRIEFING_AGENT_MODEL`; `synthesize-agent.js` + `categorize-agent.js` route through it (one edit to bump). - **`output/build/validate.js`** wraps `loadSlidesData()` in try/catch — prints "run `emit-slides-data.js` first" and exits non-zero instead of a raw dynamic-import stack. - **JS-string injection hardening** in `chrome-extract.js` `buildExtractorJs`: `handle` + `cutoffIso` are escaped for single-quoted JS-string context (`\` then `'`) before substitution, via function replacers so a `$` in the value can't form a replacement pattern. Bumps plugin `version` 0.2.0 → 0.3.0 (behavior change → consumers receive it on `/plugin marketplace update`). ## Verification - `scripts` suite: `npm test` — all green incl. new `grok-wave0-orchestration.test.js` (env-isolated from leaked `CLAUDE_PLUGIN_DATA`). - `output/build` suite: `node --test` — 2 pass. - S3 Chrome-wins merge verified directly (dry-run skips the merge path). - Escaping verified against a malicious `evil'];window.__pwned=1;//` handle; backslash-doubling confirmed. - `validate.js` diagnostic path exercised (no `slides-data.js` → clean message, exit 1). - `claude plugin validate plugins/ai-briefing --strict` — passed. Refs melodic-software/medley#1457 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches browser-injected extractor JS and optional external Grok CLI orchestration; failures are designed to degrade without blocking Chrome Wave 1, but S3 merge semantics and seen-items `source_type` affect dedup and downstream briefing content. > > **Overview** > **ai-briefing 0.3.0** wires optional **Grok Wave 0** into the per-profile runner and folds in several publish-review fixes. > > **Grok Wave 0** registers `grok-capture` in the runner. `init --grok-preload` probes the Grok CLI, sets `config.grok_preload` / `grok_degraded`, and supports `--require-grok` for hard failure. `cmdGrokCapture` is non-blocking (skip + exit 0 on disabled preload or errors). S3 **synthesize** merges Grok and Chrome posts via `mergeTweetLists` (Chrome wins on URL dedup). Docs and CLI usage drop the “not yet wired” deferral; tests add `grok-wave0-orchestration.test.js`. > > **Other behavior changes:** `appendToSeenItems` uses `item.source_type ?? "twitter"` for forward-compatible RSS/GitHub waves. **`BRIEFING_AGENT_MODEL`** in `models.js` centralizes the S3/S4 `claude -p` model. **`buildExtractorJs`** escapes handle/cutoff for single-quoted JS literals. **`validate.js`** fails clearly when `slides-data.js` is missing. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c602645. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->



Summary
Publishes a generic, repo-agnostic
ai-briefingengine plugin, migrated from the medley in-repo skill. Ships the engine only — no employer/personal layers.retro/search/driftactions, plus the per-profile runner and the slides/HTML/PDF build pipeline.following-list.json, an optionalbrand.jsoverlay, and an optional stack lens resolve from.claude/ai-briefing/[<profile>/], falling back to a bundled neutralseed/following-list.jsonof public vendor accounts.${CLAUDE_PLUGIN_DATA}; curated config never does. In-repo runs fall back to the skill tree so the engine and its tests work outside a plugin install./ai-briefing:setup— re-runnable action that scaffolds a profile and installs runtime dependencies under${CLAUDE_PLUGIN_DATA}(the plugin cache is read-only).Verification
claude plugin validate --strictpasses on both the plugin and the catalog manifest.--plugin-dirin a clean non-source repo; both/ai-briefing:ai-briefingand/ai-briefing:setupare discovered.Notes
node_modulesand runtime-state paths are gitignored; deps install at runtime under${CLAUDE_PLUGIN_DATA}.Refs melodic-software/medley#1442
Note
Medium Risk
Large new surface (browser scraping, external APIs, Playwright/PPTX build) and reliance on
${CLAUDE_PLUGIN_DATA}for deps/state; behavior is skill-orchestrated rather than a single hardened service boundary.Overview
Adds the
ai-briefingmarketplace plugin — a repo-agnostic engine for aggregating AI-industry news into ranked briefings and optional presentation decks.Catalog & packaging: Registers
ai-briefinginmarketplace.jsonand documents it in the rootREADME. Shipsplugin.jsonwith anactive_profileuser option and.gitignorerules so runtime deps and per-run state stay out of git.Skills:
/ai-briefing:ai-briefingdrives multi-wave collection (Chrome/X, Perplexity, RSS, GitHub releases, optional Grok), dedup, 13-bucket categorize/rank, meeting-window merge, andretro/search/driftactions./ai-briefing:setupscaffolds a consumer profile under.claude/ai-briefing/and installs runtime Node deps under${CLAUDE_PLUGIN_DATA}.Named-profile seam: Curated
following-list.json, optionalbrand.js, and stack lens live in the project profile (with bundled neutral seed); machine state (seen-items, runs, decks) persists per profile in the plugin data directory.Build pipeline: In-tree Node ESM flow — parse briefing markdown →
slides-data.js→ PPTX (pptxgenjs), single-file scroll-snap HTML, and PDF (Playwright), with Zod validation, provider logos, and overridable default brand/ranking defaults.Reviewed by Cursor Bugbot for commit 729c19a. Bugbot is set up for automated code reviews on this repo. Configure here.