feat(feed-hermit): feed-to-brief pipeline plugin#612
Open
gtapps wants to merge 2 commits into
Open
Conversation
Extracts a self-contained briefing product into a new domain plugin: a curated source registry (sources.md/categories.md with a validate-sources hook), the 7-phase news-brief pipeline, weekly-digest synthesis, source curation skills (add-source/source-scout/source-health), story-arcs and deep-dive follow-ups, and a Haiku source-fetcher agent. Ships a plugin-local fetch-guard PreToolUse hook (WebFetch domain allowlist from sources.md) for prompt-injection containment rather than deferring the guard. reddit-fetch.ts is a zero-dependency TS port (unauthenticated by default, optional OAuth2 client-credentials path), exit 0/1. The pipeline skill is named news-brief to avoid trigger collision with core's status-summary brief skill.
Rename the still-unreleased plugin to feed-hermit (feed-to-brief identity): "briefing/news" mischaracterized what it ingests, and the operator-owned root files now take a collision-free feed- prefix so the validate-sources hook no longer trips on a foreign sources.md. Flagship skill news-brief becomes feed-brief; internal vocab, archive dir, config key, and prose move to the feed/brief voice. Folds in the earlier fetch-guard/validate-sources/reddit-fetch review fixes and the operator-doc-refs CI fix. No behavior change; unreleased, so no field migration.
gtapps
marked this pull request as ready for review
July 16, 2026 18:16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New domain plugin
feed-hermit(v0.1.0): a self-contained feed-to-brief pipeline — a curated source registry → fetch → score → write → deliver → archive → weekly-synthesis flow, with source-health analytics driven entirely by archive frontmatter. This is the seventh shipped plugin and the first "big pipeline" domain plugin, with the smallest dependency surface of the extraction series (core only).Changes
feed-brief(the 7-phase pipeline,--morning|--evening|--slot),weekly-digest,add-source,source-scout,source-health,story-arcs,deep-dive,hatch. Namedfeed-brief(notbrief) to avoid trigger collision with core's status-summarybriefskill.source-fetcherHaiku agent — raw web/RSS collection with an explicittmp/feed-source-items-<slot>.jsonoutput contract.reddit-fetch.ts(unauthenticatedhot.jsonby default, optional OAuth2 client-credentials path; exit 0 success / 1 error),validate-sources.ts(PostToolUse registry-table validator, keyed onfeed-sources.md).fetch-guard.tsPreToolUse hook — WebFetch domain allowlist scraped fromfeed-sources.md+ an infra list; blocks off-allowlist fetches (exit 2), fails open on unreadable registry. Prompt-injection containment shipped now rather than deferred.feed-sources.md/feed-categories.md/FEEDS.mdat the project root (opt-in generic starter pack), registers morning/evening/weekly routines and a monthlysource-scoutscheduled check, appends the Feed Workflow block, addstmp/to.gitignore.sources_skippedvssources_quietdistinction that powerssource-health.test-feed.ymlCI (path-filtered,bun test), README + root CLAUDE.md updated to seven plugins.Review + fixes folded in on this branch
fetch-guard.ts— block reason now written to stderr (so the model receives it on exit 2), case-insensitive/lowercased host matching (an uppercase domain in the registry no longer blocks a legitimate source), and aSOURCES_FILEconstant deduping the repeated filename literal.validate-sources.ts— colon-tolerant markdown separator regex, so alignment rows (:---:) no longer false-flag as invalid types.reddit-fetch.ts— clamp a non-positivelimitto the default (was silently dropping posts / returning empty).${CLAUDE_PLUGIN_ROOT}/docs/...instead of baredocs/..., satisfying core'soperator-doc-refsguard (this was the failing check).Corrections vs the original extraction spec
reddit_fetch.py's real contract is 0/1 (no exit-2 "unconfigured"); the TS port matches the live script, not its stale tests/docs.bin/hermit-chrome-startexists in core — Chrome availability is treated as a deployment concern; sources skip gracefully when it's down.launch_chrome.pynot ported.brief-blocks/template and nofetch_source_filesmeta key; both noted as planned core integrations. The fetch guard ships plugin-local until C5 lands.brief-feedbackproducer lives in the channel layer (not shipped here);weekly-digestconsumes it and degrades silently when absent.Test plan
cd plugins/feed-hermit && bun test→ 52 pass, 0 fail (reddit-fetch exit-code contract via spawn, validate-sources cases, fetch-guard allow/block/fail-open, schema-contract, skill-structure).plugins/claude-code-hermit) → green, incl. the marketplace↔dir bidirectional-sync invariant,operator-doc-refs, andskill-structure.bunx tsc --noEmit(repo-wide, strict) → 0 errors.briefing-hermit/news-brief/BRIEFING.md/ anybriefinginsideplugins/feed-hermit/→ zero (the only survivingbriefingin the repo is the generic core artifact-type, which is orthogonal).fetch-guard.tsblocks an off-allowlist URL against afeed-sources.mdallowlist;validate-sources.tsfires on afeed-sources.mdedit and passes through a foreignsources.md./feed-hermit:hatchsmoke on a real target project.