SKILL.md
SKILL.mdBrowse 5 files
3,038 tokens
12,652 bytes
Token encoding: o200k_base
Snapshot 24fd22b
1---2name: grounded-citations3description: "Ground answers and documents in cited, verifiable sources."4version: 1.2.05author: Hermes Agent + Teknium6license: MIT7platforms: [linux, macos, windows]8metadata:9 hermes:10 tags: [Research, Citations, Grounding, Sources, Web, Reports]11 category: research12 related_skills: [arxiv, pdf, reddit-reading, rss-feeds, youtube-content]13---14 15# Grounded Citations16 17Every claim taken from an outside source gets an inline numbered citation and a18`Sources:` list, Perplexity-style. A ledger script owns the `url → [n]` mapping19so the numbers and URLs come from retrieval, never from memory — the model only20ever emits small integers it was handed.21 22For high-stakes work the same ledger doubles as a fact-checking chain: verbatim23quotes are attached to each source (rejected unless they literally appear in24the fetched page text), claims from model knowledge are flagged `[unverified]`,25and `verify --evidence` fails any draft whose cited sources carry no evidence.26 27This skill covers answers in chat, written documents (markdown, PDF, docx,28slides), and research reports. It does not cover academic BibTeX pipelines —29for conference papers use the `arxiv` skill, which this skill30feeds (see `references/citation-formats.md`).31 32## When to Use33 34Use whenever an answer or artifact rests on information you fetched rather than35knew:36 37- Research, comparisons, news summaries, "what is the current state of X"38- Any deliverable you write to disk that quotes, paraphrases, or reports39 outside facts — reports, briefs, docs, decks, wiki pages40- Fact-finding where the user will want to check your work41- Multi-source synthesis where conflicting sources must be attributed42 43Skip inline citations when the retrieval is incidental to another task — a44quick syntax/version lookup mid-coding, casual conversation, creative writing.45Mention a URL only if the user would plausibly want the link.46 47## Prerequisites48 49None beyond the standard toolset. `scripts/sources.py` is stdlib-only Python 3.50Retrieval comes from whatever is configured: `web_search`, `web_extract`,51`browser_navigate`, or `terminal` (curl, CLIs).52 53Ledger location: `$HERMES_HOME/cache/citations/ledger.json` (profile-aware).54Override per task with `--ledger <path>` or `HERMES_CITATION_LEDGER`.55 56## How to Run57 58```bash59S=~/.hermes/skills/research/grounded-citations/scripts/sources.py60 61python "$S" reset # start a clean ledger62python "$S" add https://example.com/a --title "A" # prints: [1]63python "$S" add https://example.com/b --title "B" # prints: [2]64python "$S" list # ledger table65python "$S" render # Sources: block66python "$S" verify draft.md # catch bad citations67```68 69`add` is idempotent and URL-normalized: the same page always returns the same70id within a ledger, so ids stay stable across many search/extract rounds.71 72## Quick Reference73 74| Action | Command |75|---|---|76| Fresh ledger for a new task | `sources.py reset` |77| Register a source, get its id | `sources.py add <url> [--title T]` |78| Register several at once | `sources.py add <url1> <url2> ...` |79| Register from JSON tool output | `sources.py ingest results.json` |80| Attach verbatim evidence to a source | `sources.py quote <id> --text "exact wording" --from page.txt` |81| Show ledger | `sources.py list [--json]` |82| Render the Sources block | `sources.py render [--style markdown\|plain\|footnotes\|bibtex\|evidence] [--only 1,3]` |83| Render only what a draft cites | `sources.py render --cited-in draft.md` |84| Rewrite a draft's Sources block in place | `sources.py render --replace-in draft.md` |85| Check a draft's citations | `sources.py verify draft.md [--strict] [--min-coverage 0.6] [--evidence]` |86 87## Procedure88 89① **Reset the ledger** at the start of a task that will produce a grounded90answer or document. Skip the reset when continuing work whose ids are already91in a draft — reusing the ledger keeps the numbering stable.92 93② **Register every source at retrieval time.** After each `web_search` /94`web_extract` / `browser_navigate` / fetch, pass the URLs to `sources.py add`95(or pipe the raw JSON through `sources.py ingest`). Do this *before* writing96prose. Registering later, from memory, is the failure mode this skill exists to97prevent.98 99③ **Write cite-while-drafting.** Place the bracketed id(s) immediately after100each sentence the source supports:101 102```103Ice floats because it is less dense than liquid water.[1][2]104```105 106- No space before the bracket; each id in its own brackets.107- Max 3 ids per sentence. Cite per sentence, not one dump at the end.108- Only ids the ledger returned. Never invent an id or a URL.109- Claims from your own knowledge get no citation.110- Conflicting sources: present both readings, each with its own id.111- Quote exact figures, dates, and names as the source states them; flag gaps112 explicitly ("no source found for X") instead of smoothing them over.113 114④ **Append the Sources block** with `sources.py render --cited-in <draft>` so115the id → URL mapping is generated mechanically from the ledger, not retyped.116For non-markdown targets pick the matching `--style` and follow117`references/citation-formats.md` for placement (footnotes in docx, endnotes in118PDF/LaTeX, a Sources slide in decks, per-page source lists in wiki output).119 120⑤ **Verify before delivering** — `sources.py verify <draft>` exits non-zero on121unknown ids, on a Sources block that disagrees with the ledger, or (with122`--min-coverage`) on prose that is too thinly cited. Fix and re-run.123 124⑥ **Chat answers** follow the same steps with the draft in your reply: register125sources, cite inline, end with the rendered `Sources:` list. For a short answer126you may render the block from `sources.py render --only <ids>` instead of127writing to a file.128 129## Multi-Platform Sweeps130 131"What are people saying about X" / "research X across the web" is not one132`web_search`. Fan out across source types, collect in parallel, then synthesise133with every claim attributed to the platform it came from:134 135| Source type | Route | What it adds |136|---|---|---|137| Open web | `web_search` → `web_extract` | official docs, articles, announcements |138| Community discussion | `reddit-reading` (`search`, `thread`) | real user experience, complaints, workarounds |139| Blogs / releases / changelogs | `rss-feeds` (`read`, `discover`) | dated primary posts, version history |140| Video | `youtube-content` | walkthroughs, demos, talks |141| Code | `terminal` with `gh search repos` / `gh search issues` | implementations, open bugs |142| X/Twitter | `xurl` (needs API access) | announcements, developer chatter |143 144The `reddit-reading` and `rss-feeds` skills are optional. If absent, install with145`hermes skills install official/social-media/reddit-reading` or146`hermes skills install official/research/rss-feeds` before using them.147 148Register every URL from every route in the ledger as it arrives (step ②). Keep149opinion and measurement apart: a Reddit thread is evidence that users *report*150something, not that it is true; pair it with a primary source or label it as151sentiment. Report per-platform coverage gaps ("Reddit search returned nothing152newer than March") rather than silently narrowing to what worked.153 154## Fact-Checking Mode155 156For work where the reader must be able to check the chain — medical, legal,157financial, safety, disputed claims, or when the user asks for fact-checking —158upgrade from citations to evidence:159 160① **Attach a verbatim quote per source.** After extracting a page, save its161text to a file and attach the sentence(s) that carry each claim:162 163```bash164python "$S" quote 1 --text "Ice is about 9% less dense than liquid water." --from page1.txt165```166 167The quote is rejected unless it appears verbatim in the evidence text168(insensitive to whitespace, case, and markdown markup — inline links like169`_[ERAP1](https://…)_` in extracted text match the plain prose a reader sees),170so a paraphrase or misremembered figure cannot masquerade as evidence.171Copy-paste from the fetched text; never retype. Quote the sentence as the172reader sees it — the matcher sees through the extractor's markup for you, so173you don't have to reproduce link syntax or escaped asterisks in your quote.174 175② **Flag model-knowledge claims with `[unverified]`.** A load-bearing claim176you could not source gets an explicit marker instead of a citation:177 178```179The refactor likely predates the 2.0 release.[unverified]180```181 182`verify --min-coverage` counts `[unverified]` sentences as covered — the goal183is declared provenance for every claim, not a citation on every sentence.184If a key claim can be checked, check it; `[unverified]` is for what genuinely185cannot be, and a fact-check deliverable dominated by `[unverified]` markers186should say so in its summary.187 188③ **Cross-check disputed facts against a second independent source.** When two189sources disagree, cite both readings with their own ids and quotes, and say190which you weight and why. One source is reporting; two independent sources are191corroboration.192 193④ **Verify with the evidence gate and render the evidence block:**194 195```bash196python "$S" verify report.md --evidence --min-coverage 0.5197python "$S" render --style evidence --replace-in report.md198```199 200`--evidence` fails the draft if any cited source has no attached quote. The201`evidence` render style prints each source's quotes beneath its URL, so the202deliverable shows claim → source → exact supporting text with nothing taken on203faith. Use `--replace-in <draft>` to rewrite an existing Sources block in place204(idempotent — safe to re-run after attaching more quotes); `--cited-in` prints205to stdout instead. Both emit the heading `## Sources` (`--style plain` emits206`Sources:`).207 208**What `--min-coverage` counts.** Coverage is209`sentences with declared provenance / prose sentences`. A prose sentence is a210non-empty line fragment of 4+ words after the Sources block, headings (`#`),211table rows (`|`), and fenced code are dropped; blockquote markers are stripped.212Provenance is declared by either a `[n]` citation or an `[unverified]` marker,213so a sentence carrying both counts once. Run `verify` without a threshold first214and read the `info: stats:` line to see the counts before picking a number.215 216## Pitfalls217 218- **Registering after writing.** The ledger must be populated from tool output,219 not reconstructed from the draft — that reintroduces exactly the hallucinated220 -URL risk the numbering removes.221- **Renumbering mid-task.** Never hand-edit ids in a draft. Ids are ledger222 identities; if a draft cites `[4]`, `[4]` must stay that source. Run `reset`223 only between tasks.224- **Retyping URLs into the Sources block.** Always `render`. A hand-typed URL225 is an unverified claim.226- **Citing a search snippet as if you read the page.** A `web_search`227 description supports only what it literally says. Cite the extracted page228 when the claim needs the body — `web_extract` it first.229- **Over-citing.** Three ids on a sentence is the ceiling; a citation on every230 clause makes text unreadable and hides which source carries the load.231- **Citing the ledger in code/config artifacts.** Source comments belong in232 prose deliverables and doc headers, not inside generated code.233- **Parallel subagents.** Each subagent has its own working directory; point234 them all at one ledger with `--ledger` (or `HERMES_CITATION_LEDGER`) if their235 outputs get merged, otherwise their ids will collide.236- **Quoting from a snippet instead of the page.** Evidence quotes must come237 from the extracted page text, not a search-result description — `web_extract`238 first, save the text, then `quote --from` that file.239- **Paraphrasing into `quote --text`.** The verbatim check will reject it; the240 fix is to find the actual sentence, not to reword until something matches.241- **Using `[unverified]` as an escape hatch.** It marks the rare claim that242 genuinely cannot be sourced; if most sentences carry it, the task needed more243 retrieval, not more markers.244- **Hand-editing the Sources block.** Use `render --replace-in <draft>`; slicing245 the file yourself risks a stale or duplicated block that `verify` then flags.246 247## Verification248 249```bash250python "$S" verify report.md --strict --min-coverage 0.5251```252 253Green means: every `[n]` in the draft exists in the ledger, the Sources block254lists exactly the cited ids with the ledger's URLs, and the cited share of255source-bearing sentences meets the threshold. Read the warnings even when the256exit code is 0 — uncited registered sources usually mean a claim lost its257attribution during editing.258 Discovery context
Discovered by repository scan. No exact path reference found in the snapshot’s root AGENTS.md.