Eru.Tool
0.16.0
See the version list below for details.
dotnet tool install --global Eru.Tool --version 0.16.0
dotnet new tool-manifest
dotnet tool install --local Eru.Tool --version 0.16.0
#tool dotnet:?package=Eru.Tool&version=0.16.0
nuke :add-package Eru.Tool --version 0.16.0
<p align="center"> <img src="docs/images/eru-logo.svg" alt="eru" width="280"> </p>
<h3 align="center">Targeted context for AI agents, from any git repo.</h3>
<p align="center"> <code>eru</code> pulls just the knowledge an agent needs from local or remote git sources, makes it searchable, gives humans a themed site to read it, and lets agents turn a pile of raw notes into a curated knowledge source. </p>
<p align="center"> <a href="https://github.com/dburriss/eru/actions/workflows/build.yml"><img src="https://github.com/dburriss/eru/actions/workflows/build.yml/badge.svg" alt="Build and test"></a> <a href="https://www.nuget.org/packages/Eru.Tool"><img src="https://img.shields.io/nuget/v/Eru.Tool?logo=nuget" alt="NuGet"></a> <a href="https://github.com/dburriss/eru/releases"><img src="https://img.shields.io/github/v/release/dburriss/eru?logo=github" alt="GitHub release"></a> </p>
<p align="center"> <img src="docs/reference/images/themes/terminal-dark.png" alt="The eru generated site in the terminal theme, dark mode" width="900"> <br> <sub>The generated site in the <code>terminal</code> theme. See all <a href="docs/reference/theme-list.md">themes</a>.</sub> </p>
Get started
Install the tool (.NET 10 and git required; self-contained binaries are on the releases page):
dotnet tool install --global Eru.Tool
Or install a self-contained binary with mise, which needs neither .NET nor a separate download:
mise use --global github:dburriss/eru
Install the skill with skills.sh:
npx skills add dburriss/eru
Then ask your agent to set eru up. The skill knows how to add sources, pull files, build a site and run an inbox, so you don't need to learn the commands.
What it does
Targeted context for agents
Point eru at one or more git repos, local or remote, and pull only what a project needs: single files, named collections, or everything with a tag. Every pulled file is recorded in a lock file, so it stays in sync and you can see where it came from.
Search is powered by Ferret: ranked lexical (BM25), semantic and hybrid search, running locally over your knowledge. eru mcp exposes that search and retrieval to Claude, Copilot, Cursor and any other MCP client, so agents ask for context instead of reading whole repos.
OKF or an eru manifest
A knowledge source can be an OKF bundle, or any repo with an eru .eru/manifest.json that declares the files it offers. eru can validate and repair OKF trees, and check that a manifest resolves.
A site for humans
eru site generate builds a self-contained, searchable site from your knowledge, with five built-in themes and room for your own. eru site serve adds live reload, and the output publishes straight to GitHub Pages.
Agent workflows: from inbox to curated knowledge
Drop raw text into an inbox, which can be a local folder or a remote git repo. An ingestor agent processes each item into well-formed, linked, validated notes in your knowledge source. Run it locally while you work, or in CI so that pushing a raw capture is enough.
- Use send and watch locally
- Process the inbox with a GitHub Agentic Workflow
- Process the inbox with a plain GitHub Action
How it fits together
git repos (local / remote) inbox (raw text)
OKF bundle or eru manifest │
│ ▼
│ ingestor agent ──▶ curated knowledge
▼ │
eru cache + lock file ◀─────────────────────────────────┘
│
┌─────┴───────────────┐
▼ ▼
agents (search, MCP) humans (generated site)
Documentation
Full documentation lives under docs/, organised by Diataxis: tutorials, how-to guides, reference and explanation. The complete command list is in the CLI reference.
Contributing
Run mise install for the toolchain, then dotnet build and dotnet test --solution eru.slnx. CI builds and tests every push and PR; pushing a v* tag publishes the NuGet package and GitHub release binaries. See AGENTS.md for the project layout, conventions and release flow.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.16.1 | 93 | 11/7/2026 |
| 0.16.0 | 80 | 11/7/2026 |
| 0.15.1 | 89 | 11/5/2026 |
| 0.15.0 | 83 | 11/5/2026 |
| 0.14.0 | 116 | 11/2/2026 |
| 0.13.1 | 143 | 10/12/2026 |
| 0.13.0 | 124 | 10/12/2026 |
| 0.12.0 | 131 | 10/9/2026 |
| 0.11.1 | 124 | 10/8/2026 |
| 0.11.0 | 125 | 10/8/2026 |
| 0.10.0 | 131 | 10/5/2026 |
| 0.9.1 | 146 | 10/2/2026 |
| 0.9.0 | 137 | 10/2/2026 |
| 0.7.1 | 350 | 5/29/2026 |
| 0.7.0 | 273 | 5/29/2026 |
| 0.6.0 | 269 | 5/29/2026 |
| 0.5.1 | 266 | 5/29/2026 |
| 0.5.0 | 262 | 5/29/2026 |
| 0.4.0 | 264 | 5/29/2026 |
| 0.3.0 | 264 | 5/28/2026 |
GitHub releases include a native `eru-osx-arm64` binary for Apple Silicon, so `mise use github:dburriss/eru` and similar installers find a matching asset instead of falling back to the Rosetta-only `eru-osx-x64`
A `brand` layout slot on the generated site: the logo in the nav is now markup (`brand-mark`, `brand-name` and `brand-cursor` spans) that `site.layout.brand` can replace with `html` or `text` items, or remove with `false`. `{{root}}` in the markup is the relative path back to the site root
Footer `text` and `html` items on the generated site: `{ "text": "markdown" }` renders Markdown with raw HTML escaped, `{ "html": "<b>raw</b>" }` is emitted as is, and both accept `{ "file": "path" }` to read a repo-relative file (watched by `eru site serve`). They are footer-only
Table views on the generated site have visible sort controls on every column header. Headers are keyboard-operable buttons that expose `aria-sort`, and sorting uses the same keys as the `sort` page option (dates, trust tiers, sync status) instead of the displayed text, with blank cells last
Search can be limited to specific sources: `eru search <terms> --source <name>` (repeatable, `-s`) and a `sources` parameter on the `search_knowledge` MCP tool. Names match case-insensitively and any of them may match; `local` selects local `knowledge/` files. An unknown source name is an error that lists the valid ones
`mcp.idleTimeoutMinutes` (and `ERU__MCP__IDLETIMEOUTMINUTES`) pauses an `eru mcp` server's background refresh after that many minutes without a request. The server keeps answering and the next request resumes it. `0`, the default, never pauses
A plain local folder (not a git repo) can be a source: `eru source add ~/second-brain --scan`. The folder is read in place — nothing is cloned or copied into the cache, so `eru cache prune` and `eru cache clear` never touch it. Folder sources are OKF-only: markdown files under registered `okf` bundles are indexed, skipping dot-directories and `okf.ignorePatterns` directories. Sync stats the tree and re-reads only files whose modified time or size changed, and drops entries for files that were removed or renamed. A missing or unmounted folder keeps the old index and reports an error. `--branch`, `--basepath`, manifests and collections do not apply to folder sources
`eru okf init <path> --update` regenerates the catalog (folder list and concept table) of existing `index.md` files, so indexes no longer go stale. Catalogs now sit between `<!-- eru:catalog -->` and `<!-- /eru:catalog -->` markers, and only that block is rewritten; prose around it is kept. `--force` (with `--update`) adopts indexes that have no markers yet: it replaces an eru-shaped table (and `## Folders` list), or appends a block. `--force` only touches genuine OKF indexes (inside a bundle whose root `index.md` has `okf_version`, index-shaped frontmatter, a folder with concepts or subfolders); foreign `index.md` files are skipped with the reason. Lone or duplicated markers are never rewritten. `eru okf fix` also refreshes marked indexes and lists unmarked ones as skipped
`eru okf validate` warns with `missing-catalog-markers`, `stale-index` and `malformed-catalog-markers` for catalog indexes (warnings never change the exit code)
Site themes follow the mocks more closely: filter values (row tags and sources) are bordered buttons, and they fill when their token is in the query line. The `source`/`status`/`tag` key button fills while its values are being completed. Both use a `q-on` class (and `aria-pressed` on the value buttons), which themes recolour. `smiley` now defaults to the cards view with a facet sidebar on Browse and fills orange, `cyberpunk` magenta and `ledger` with a soft tint. `ledger` now turns the query line off (its facet sidebar does the filtering) and keeps the plain search box; row tags and sources are plain links on a page with no query line, not dead filter buttons. The brand mark moved from CSS pseudo-elements to markup, so a `custom.css` that styles `.nav-brand::before` or `::after` should target `.brand-mark` and `.brand-cursor`
**Breaking:** the sync-state glyph (`●`/`◐`/`○`) and badge no longer show in site listings by default. Set `site.showSyncStatus` to `true` (or `ERU__SITE__SHOWSYNCSTATUS=true`) to show them. The `sync:` filter and an explicit `syncStatus` table column are unchanged.
**Breaking:** the `top` layout slot is renamed `nav`. A config that puts page ids or links in `top` now fails with a message pointing to `nav`; rename the key (also `ERU__SITE__LAYOUT__TOP__*` to `ERU__SITE__LAYOUT__NAV__*`). `top` is now a full-width widget band.
**Breaking:** the `query` widget is no longer valid in `main`; it goes in `toolbar`, `left` or `right`. Browse now shows `title` in `top`, the query line in `toolbar` and `list` in `main`.
**Breaking:** the generated site has a new terminal look: monospace type, square corners, hairline borders and an orange accent. The CSS variable names are unchanged, so a `custom.css` that sets `--color-*`, `--font-family` or `--radius` still applies, but overrides of component classes may need a second look.
**Breaking:** Browse is now a query line above a table of name, source and tags, with no sidebar. Set `layout.left` to `["facets"]` to bring the sidebar back, or `defaultView` to `cards` for the old cards.
`eru source disable <name>` and `eru source enable <name>` switch a source off and on without removing it. A disabled source is not synced, searched, served over MCP or shown in the site, and collection files pointing at it are skipped. It is also the `enabled` field of a source entry and `ERU__SOURCE__<NAME>__ENABLED`, and `eru source list` shows its status. `-g` edits the global config; otherwise a url-less local entry is used so only the current repo is affected.
Site themes: `site.theme` (`terminal` by default, or `ledger`) switches the look of the generated site. A theme is a folder with a `theme.json` (default `site` settings) and a `theme.css`; custom themes go in `.eru/themes/<name>/` or `~/.config/eru/themes/<name>/`. Your config and `custom.css` still win. `ERU__SITE__THEME` and `eru config set site.theme` work too. See [themes](docs/reference/site-generation.md#themes).
`eru theme list` shows the built-in and installed themes and which one is active.
A `matrix` site theme: the terminal layout in phosphor green, with a faint glow and scanlines in dark mode. Select it with `eru config set site.theme matrix`.
A `smiley` site theme: the terminal layout in blue and orange, with a blue header, sans-serif type and rounded pills. Select it with `eru config set site.theme smiley`.
A `cyberpunk` site theme: the terminal layout in neon magenta, cyan and yellow, with a grid and glow in dark mode (pale lavender in light), angular display type and clipped corners. Select it with `eru config set site.theme cyberpunk`.
A `rows` view: one bordered row per document with its description, source, tags and sync state. It is the `ledger` theme's default.
New layout slots `top`, `toolbar` and `footer`: full-width bands above and below the columns. Every page footer links to the eru docs by default; set `footer` to replace it or `"footer": false` to remove it. Widgets are valid in more slots (`breadcrumbs`, `title`, `stale` in `top`; `meta`, `verified`, `generated`, `description`, `tags`, `cli`, `links` in `top` and `footer`).
The query line can be moved: `query` is valid in `toolbar`, `left` and `right` (once per page), and any page can opt in.
A `query` widget: type `tag:`, `source:` or `status:` to filter with a completion list and live counts, exclude with `-tag:x`, click a source or tag in the table to add it, and share the filtered view through `?q=` in the address. Press `/` to focus it and `j`, `k` and enter to move through rows.
The sync state of each file shows as a glyph before its name (`●` pulled, `◐` cached, `○` index-only), and rows carry a `data-sync` attribute.
Servers left running from an older install no longer undo newer state: an `eru mcp` started before an upgrade used to keep syncing with old code and overwrite `index.json` (for example back to 0 entries). `index.json` records the eru version that wrote it and an older eru refuses to overwrite it (the server logs that it is stale and stops syncing). Index writes are atomic, so a reader never sees a half-written file. Each server registers in `~/.cache/eru/mcp/` and exits when it finds a newer eru running; servers of the same version are left alone. Servers started before this change have no such check, so after upgrading stop them once with `pkill -f 'eru mcp'` and run `eru sync`
Several `eru mcp` servers used to each run their own background sync. Now only one runs at a time across all `eru mcp` servers and `eru sync`: an exclusive lock on `~/.cache/eru/sync.lock` plus a throttle (a timer sync is skipped if another process synced less than half a refresh interval ago). `refresh_knowledge` bypasses the throttle but still waits for the lock; `eru sync` waits up to a minute and then reports that another sync is running
A `--color-*` override under `:root` in `custom.css` now takes effect. The theme colours were set on `body`, which shadowed any `:root` rule; they now sit on `<html>` with no extra specificity, and the theme class is stamped on both `<html>` and `<body>`. Per-theme overrides under `body.theme-light` and `body.theme-dark` keep working.
A `pages.browse` override with a `table` block no longer needs `"view": "table"`. Browse renders as a table by default, but validation judged it as cards and rejected the block.