Skip to main content

Maintain a local, LLM-queryable corpus of an IETF Working Group's public record (drafts, mailing list, GitHub issues, meetings), with an MCP server, semantic search, and NotebookLM export.

Project description

ietf-llm

Maintain a local, queryable corpus of an IETF Working Group's public record — charter, drafts, RFCs, meeting agendas, minutes, slides, transcripts, mailing list archives, and GitHub issues — for use with LLM-based tools.

What it's for

A working group's history is spread across mailing list archives, Datatracker, GitHub, and meeting materials — too much to hold in your head, and too scattered to search well by hand. With the record gathered into one queryable corpus, an LLM can help you:

  • Get up to date with the state of discussions — what's open, what was recently decided, where a debate currently stands.
  • Summarise the arguments already made about an issue — every distinct position on a topic, who holds it, and how the chairs ruled.
  • Formulate a new proposal — surface the objections raised against similar ideas before, so you can anticipate them.
  • Fact-check assertions about what's happened so far — grounded in the actual list traffic and chair statements, not someone's recollection.

Three supported workflows:

  1. Use it as an MCP server — register ietf-llm-mcp with Claude, Codex, Gemini, Cursor, Zed, etc. and ask questions across any WG you've gathered.
  2. Use it with NotebookLM — export the gathered corpus as a directory of clean text files (or push directly to NotebookLM Enterprise) and ingest it as a notebook source set.
  3. Use it from the CLI — run semantic search over the cache directly with ietf-llm-search, no LLM client required.

Also works with IRTF Research Groups. Pass the RG's shortname (e.g. cfrg, hrpc, pearg) anywhere this README says <wg>.

Table of contents

Installation

pipx install ietf-llm

Behind a corporate firewall with TLS interception? Install with the certs extra:

pipx install ietf-llm[certs]

Shell completion

Optional. Add the line for your shell to its rc file to tab-complete commands, flags, and cached WG names:

# bash — in ~/.bashrc
eval "$(ietf-llm --completion bash)"
# zsh — in ~/.zshrc
eval "$(ietf-llm --completion zsh)"
# fish — in ~/.config/fish/config.fish
ietf-llm --completion fish | source

Gather a corpus

Each use mode below reads from a local cache. Gather it once per corpus; settings persist, so refreshing is a bare re-run (ietf-llm httpbis), and the semantic index updates incrementally each time.

ietf-llm httpbis --github httpwg/http-core --github httpwg/http-extensions

Everything lands in ~/.cache/ietf-llm/<name>/ — the single source of truth that the MCP server, NotebookLM exporter, and CLI search all read from.

First run: gathering a corpus also builds a local semantic-search index — this powers both the MCP search_corpus tool and ietf-llm-search. It uses BAAI/bge-small-en-v1.5 by default — ~130 MB, ~33M params, MPS-accelerated, runs entirely on your machine. Downloaded from Hugging Face on first use and cached; subsequent gathers reuse it. Override with --embed-model <id> for any model the llm package recognises. Pass --no-embed to skip the index (and the download) — useful for NotebookLM export or offline gathers.

A corpus doesn't have to be a Working Group — the name is classified automatically:

Command Corpus
ietf-llm httpbis a WG / RG / editorial WG / BoF: charter, drafts, meetings, ballots, list
ietf-llm last-call a standalone mailing list (any archived at mailarchive.ietf.org — IETF, IRTF, or RFC-Editor)
ietf-llm rfced --mailing-list rswg@rfc-editor.org a named list corpus (the address domain is optional)
ietf-llm new-ids --new-drafts --months 1 new Internet-Drafts in a rolling window
ietf-llm mnot --author mnot@mnot.net every draft a person has authored

See Gather options for the full flag set.


1. Use as an MCP server

ietf-llm-mcp is a stdio Model Context Protocol server that exposes the local corpus to any MCP-capable agent. Set up once, gather each WG you care about once, then ask questions indefinitely.

Register the server

Pick your client. The snippets below are correct as of writing — if your client has changed since, its own MCP docs are authoritative.

Gotcha (all clients): if ietf-llm-mcp was installed via pipx, the binary is on your shell PATH but may not be on the PATH inherited by a GUI app launched from Finder / Spotlight / Explorer. Use the absolute path (which ietf-llm-mcp) if the client can't find the command.

Claude Code

claude mcp add ietf-llm -- ietf-llm-mcp

Also install the bundled skill so Claude knows how to drive the tools well (digests before raw reads, search before slurping mailing-list files, etc.):

ietf-llm --install-claude-skill

Re-run after upgrading the package to pick up improvements.

Claude Desktop

Edit claude_desktop_config.json (create it if missing):

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
  • Linux: ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "ietf-llm": {
      "command": "ietf-llm-mcp"
    }
  }
}

Quit and relaunch Claude Desktop — the config is only read at startup.

Codex CLI (OpenAI)

~/.codex/config.toml:

[mcp_servers.ietf-llm]
command = "ietf-llm-mcp"

Gemini CLI

~/.gemini/settings.json:

{
  "mcpServers": {
    "ietf-llm": {
      "command": "ietf-llm-mcp"
    }
  }
}

opencode

~/.config/opencode/opencode.json (or opencode.json in your project root):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ietf-llm": {
      "type": "local",
      "command": ["ietf-llm-mcp"],
      "enabled": true
    }
  }
}

Cursor

In-app MCP settings panel, or ~/.cursor/mcp.json (global) or .cursor/mcp.json (per-project):

{
  "mcpServers": {
    "ietf-llm": {
      "command": "ietf-llm-mcp"
    }
  }
}

Zed

~/.config/zed/settings.json:

{
  "context_servers": {
    "ietf-llm": {
      "command": {
        "path": "ietf-llm-mcp",
        "args": []
      },
      "settings": {}
    }
  }
}

Tuning. Each tool call has a server-side deadline so a stuck call fails fast with a clear message rather than hanging to the client's timeout. It defaults to 120 seconds; override (or disable, with 0) by setting IETF_LLM_TOOL_TIMEOUT in the server's environment — e.g. add "env": {"IETF_LLM_TOOL_TIMEOUT": "180"} to the JSON config above.


2. Use with NotebookLM

NotebookLM ingests a corpus as a set of source files. ietf-llm-export turns the gathered cache into an upload-ready directory, or pushes straight to a NotebookLM Enterprise notebook.

Workflow note: export always produces a complete fresh dump. Create a new notebook on each refresh rather than trying to merge updates into an existing one.

Pass --no-embed when gathering if you only plan to use NotebookLM — it has its own index, so the local one is wasted work:

ietf-llm httpbis --no-embed \
    --github httpwg/http-core --github httpwg/http-extensions

Export to a local directory

ietf-llm-export httpbis --destination ~/notebooklm/httpbis

Drag the directory's contents into NotebookLM as sources. Per-thread mailing list conversations and per-issue GitHub records are bundled by year / repo to stay under NotebookLM's 50-source free / 300-source Plus limit.

Export to NotebookLM Enterprise

If you have Google Workspace Enterprise with NotebookLM enabled, ietf-llm-export can create the notebook and upload sources directly:

ietf-llm-export httpbis --create my-gcp-project-id

One-time setup:

  1. Google Cloud Project with the Discovery Engine API enabled.
  2. OAuth credentials: create an "OAuth 2.0 Client ID" (Desktop App) in the Cloud Console.
  3. Save the JSON as client_secrets.json in ~/.config/ietf-llm/ (or pass --credentials-file PATH).

First run opens a browser to authorise; the token is cached at ~/.config/ietf-llm/token.json.

Per-WG export settings are persisted at ~/.config/ietf-llm/<wg>/export.json — subsequent runs of the same mode need only ietf-llm-export <wg>.


3. Use from the CLI

ietf-llm-search runs semantic search over a gathered corpus and prints ranked excerpts to stdout — useful on its own, or as input to another tool.

ietf-llm-search httpbis "skepticism about cookie partitioning" -k 8

Chunks are content-aware: one chunk per mailing list message, one per issue comment, and a windowed slice of drafts/RFCs/transcripts. The index lives at ~/.cache/ietf-llm/<wg>/embeddings.db and updates incrementally on each gather — see Gather a corpus for the embedding model.


Reference

Commands

Command Job Reads Writes
ietf-llm Gather / refresh a corpus network cache
ietf-llm-export Mirror cache to dir, or push to NotebookLM Enterprise cache dir / NotebookLM
ietf-llm-search Semantic search over the cache cache stdout
ietf-llm-mcp Expose the cache to MCP clients cache stdio (MCP)

All four are independent. The cache (~/.cache/ietf-llm/<wg>/) is the single source of truth; everything else reads from it.

Gather options

ietf-llm [OPTIONS] <name>

<name> is the corpus to gather, classified automatically:

  • a Working Group / Research Group / editorial WG / BoF shortname (httpbis, cfrg, rswg) — gathered in full (charter, drafts, meetings, ballots, mailing list);
  • a mailing list archived at mailarchive.ietf.org — IETF, IRTF, or RFC-Editor (last-call, irtf-discuss, rfc-interest) — that list on its own;
  • any other label given explicit sources (--draft / --mailing-list / --github / --new-drafts / --author);
  • prefix with x- to skip the Datatracker group lookup entirely (a fully manual corpus).

A name that is none of these and has no configured sources is rejected as a likely typo.

Sources (what to gather; all repeatable / persisted):

  • --github OWNER/REPO — a GitHub repo whose issues to include.
  • --draft DRAFT-NAME — an extra Internet-Draft to track, beyond a WG's own documents. Version suffix stripped; every revision gathered.
  • --mailing-list LIST — an extra list to sync (any archived at mailarchive.ietf.org). A bare name or a full address; the domain is optional and ignored (rswg, rswg@rfc-editor.org).
  • --new-drafts — subscribe to new Internet-Drafts: every -00 submitted within --months (rolling window; drafts age out).
  • --author PERSON — every draft PERSON authored. PERSON is an email (mnot@mnot.net, recommended), a Datatracker person id, or an exact full name. Drafts only.
  • --add-mentioned-drafts — also pull drafts the corpus's threads/issues mention but don't already include. Sticky.

Scope & filtering:

  • --months N — months of mailing list / meeting / new-draft history (default 12).
  • --github-label LABEL / --exclude-github-label LABEL — include / exclude issues by label.

Digests & search index:

  • --summarize / --summarize-model MODEL — add LLM-generated one-liners to digests via the llm package.
  • --no-embed — skip the semantic search index (it backs ietf-llm-search and the MCP search_corpus tool). On by default, incremental.
  • --embed-model MODEL — embedding model id (default: a small local model).
  • --rebuild-embeddings — drop and re-embed everything instead of the incremental update.

Cache & config:

  • --list — list cached corpora (name, kind, status, last-gathered, and a one-line subject — the group name, list, or tracked author), then exit.
  • --clear-cache — wipe this corpus's cache and re-download.
  • --clear-config — clear this corpus's persisted config.
  • --quiet / --verbose.

Per-corpus settings are persisted at ~/.config/ietf-llm/<name>/gather.json.

GitHub auth. Set GITHUB_TOKEN on the gather invocation (a fine- scoped read-only token is plenty); without one you'll hit anonymous API rate limits quickly on large WGs. Prefer inline-passing over exporting in your shell rc so the token doesn't leak into every other subprocess:

GITHUB_TOKEN=ghp_... ietf-llm httpbis
# or, from a secret manager:
GITHUB_TOKEN=$(security find-generic-password -s github-readonly -w) \
    ietf-llm httpbis

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ietf_llm-0.7.2.tar.gz (324.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ietf_llm-0.7.2-py3-none-any.whl (259.3 kB view details)

Uploaded Python 3

File details

Details for the file ietf_llm-0.7.2.tar.gz.

File metadata

  • Download URL: ietf_llm-0.7.2.tar.gz
  • Upload date:
  • Size: 324.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ietf_llm-0.7.2.tar.gz
Algorithm Hash digest
SHA256 ee3ecf230db5cd8547b1dda7450f432e1258ae9f328777dcf9538946e6f203b8
MD5 79db70b2391d6580b33318092a90db0a
BLAKE2b-256 3e0c4ef9fc311029e01bfaf2abd3aa479193db11ecfd64fad1d6acb1506a776c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ietf_llm-0.7.2.tar.gz:

Publisher: publish.yml on mnot/ietf-llm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ietf_llm-0.7.2-py3-none-any.whl.

File metadata

  • Download URL: ietf_llm-0.7.2-py3-none-any.whl
  • Upload date:
  • Size: 259.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ietf_llm-0.7.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b6479f0cc32f417ebcf6bc799d8ba6199b84054aeeb810272a426155347c37a5
MD5 a771c414a67818f01959645225b7e120
BLAKE2b-256 8d2d90cc600a0e1a24a3e03c558e7965cbee9b7fc67516fdb29075033eb46334

See more details on using hashes here.

Provenance

The following attestation bundles were made for ietf_llm-0.7.2-py3-none-any.whl:

Publisher: publish.yml on mnot/ietf-llm

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page