文档智能服务

Hermes 是一款本地优先的文档智能服务,从邮件和本地文件夹摄取文档,利用 LLM 提取结构化知识,并通过 MCP 服务器与 Web UI 提供检索能力,适用于隐私敏感的个人与企业文档管理场景。

  • by johnazariah
  • F#
  • 混合部署
  • 1 星标
  • 更新于
在 GitHub 查看 johnazariah/hermes

使用说明

Hermes

Local-first document intelligence service.

Hermes ingests documents from email and local folders, understands them through LLM comprehension, and exposes structured knowledge via MCP server and web UI. Processing is local by default with Ollama and SQLite; optional cloud model providers require explicit configuration and may receive prompt content.

What It Does

  • Syncs email from Gmail and Outlook into the file-first archive, with keyword search over metadata, immutable bodies and current extracted content
  • Watches folders (Downloads, Desktop) for new files
  • Extracts text from PDFs, Excel, Word, CSV → structured markdown
  • Comprehends documents — LLM reads each document and produces structured JSON with document type, key fields, and summary
  • Searches through HTTP and MCP — keyword, semantic and hybrid modes share a typed contract with explicit missing-index/model outcomes and vector coverage
  • Reads persisted structured data — document-scoped fields, source provenance and effective corrections are available without regenerating comprehension; unattributed shared-thread enrichment is explicitly unavailable
  • MCP server — read-only tools by default, authenticated mutations by explicit opt-in, with loopback Host/origin checks
  • Canonical React UI — Home, Documents, Search, Settings, onboarding, Pipeline and Chat use the Service API; consumed chat SSE retains document identity and visible errors

Architecture

Gmail ───────┐                                ┌─→ REST / preview React UI
Outlook ─────┼─→ file-first archive → V5 DAG ┼─→ MCP / Osprey
Folder watch ┘                  │             └─→ FTS5 + vector indexes
                               └─ extract → triage → deep-comprehend
                                          └──────→ embed

Core primitives:

  • Declarative DAG — stages declare dependencies, output schemas, gates, and execution mode
  • stage_completions ledger — durable idempotency and restart recovery
  • File-first content — archive files hold readable content; SQLite holds metadata and indexes
  • Model-aware GPU scheduler — serializes constrained local model use

See Pipeline V5 Architecture for full design.

Technology

Component Choice
Runtime .NET 9, F#
Database SQLite + FTS5 + sqlite-vec
AI Local Ollama by default; optional Azure OpenAI; nomic-embed-text
Web UI React 19 + Vite + Tailwind
Testing xUnit + FsCheck (F#), Playwright (UI)

Development

npm ci --prefix src/Hermes.Web
npm run build --prefix src/Hermes.Web            # required before Service build/publish
dotnet build                                    # build all
dotnet test                                     # run all tests (867 currently discovered)
dotnet run --project src/Hermes.Service         # run service (prod)

# Dev mode (separate port, config, archive):
$env:HERMES_CONFIG_DIR = "$env:APPDATA\hermes-dev"
$env:HERMES_PORT = "21742"
dotnet run --project src/Hermes.Service -- --initial-sync-days 90

Canonical assets and browser checks

React builds into Hermes.Web/dist, with a deterministic manifest containing asset names and SHA-256 digests. Service build/publish copies that complete bundle into its output wwwroot. Startup validates only the deployed bundle; it never substitutes a checked-in bundle, source directory or Blazor route. Missing assets fail with an explicit npm build prerequisite. Unknown API and asset paths remain errors rather than returning the SPA shell.

npm run test:unit --prefix src/Hermes.Web
npm run lint --prefix src/Hermes.Web
npm run test:reproducible --prefix src/Hermes.Web
npm run test:discovery --prefix src/Hermes.Web
cd src/Hermes.Web
npx playwright install chromium
npm test

The browser runner starts its own Service, synthetic archive and fake model endpoint on separate test ports. It refuses the production/development ports and never reuses an existing server. The discovery guard rejects missing or unexpected suites. Historical Blazor promotion tests are explicitly excluded from the canonical React inventory.

Four Unix descriptor-admission cases carry Platform=Unix. Run the .NET suite on Windows with --filter "Platform!=Unix"; Mac runs include those cases. The Windows selection still executes its owned pipe/process tests and the separate native Tray suite. Native desktop/WebView2 smoke requires real Windows execution; cross-compilation is not that proof.

Service and Windows Tray ownership

Foreground Service operation uses normal host shutdown. When Tray launches a Service child, --control-stdin opts into an owner-only pipe: shutdown or owner EOF requests graceful shutdown. This is not a network administration endpoint. Health includes the actual Service process ID so Tray can verify the child it owns. Tray respects explicit HERMES_CONFIG_DIR/HERMES_PORT and the published sibling service/ and tray/ layout.

Manual sync returns HTTP 202 for queued/coalesced work, not completed synchronisation. An unsupported, starting or stopping producer returns an explicit unavailable response. The existing single producer owns both periodic and requested cycles. Saved configuration requires a Service restart to take effect.

Rebuild selected file-content search indexes

Use an existing archive and a configuration file with an explicit, nonblank archive_dir. The command defaults to a read-only preview:

dotnet run --project src/Hermes.Service -- reindex-files --config /path/to/config.yaml --document-id 123 --document-id 456

# Explicitly apply the selected index updates:
dotnet run --project src/Hermes.Service -- reindex-files --config /path/to/config.yaml --document-id 123 --document-id 456 --apply

Select 1–100 positive, distinct IDs; there is no implicit whole-archive mode. The command exits before starting providers, watchers or the web host. It reports JSON outcomes for every selected document, preserves source files and user metadata, and refuses documents with persisted processing attempts. Missing/empty operator configuration never falls back to a default archive. Exit codes: 0 success, 1 operational/document failure, 2 invalid arguments. This rebuilds derived search content, not a lost SQLite database.

Local MCP access

The Service exposes streamable HTTP at /mcp on port 21741 by default, or the explicit HERMES_PORT. hermes_search defaults to keyword mode and also accepts semantic and hybrid; vector modes require a configured query encoder and current indexed vectors. Missing or failed dependencies are reported rather than silently substituting keyword results. hermes_get_comprehension reads already-persisted document fields without invoking a generative model. The corresponding HTTP accessor is GET /api/documents/{id}/comprehension. Its source and canonical-publication digests identify the evidence; separate document/publication generations retain original provenance through reembedding.

Mutating tools are hidden and disabled by default. To enable them, explicitly set HERMES_MCP_MUTATIONS=true and provide HERMES_MCP_TOKEN as a 32–4,096 character non-whitespace secret. Send Authorization: Bearer <token> with each mutation request. Keep the token out of source, URLs and logs.

Browser origins must be explicit loopback HTTP(S) origins. Production 21741, development 21742 and the configured Service port are allowed; additional preview origins use the semicolon-separated HERMES_ALLOWED_ORIGINS variable. Foreign Host/origin requests are rejected. Local reads without an Origin remain available, but an absent Origin never authorises a mutation. This is MCP capability authentication; broader REST/browser/Tray session integration remains separate work.

Solution Structure

src/
├── Hermes.Core/          F# library — pipeline, extraction, comprehension, DB
├── Hermes.Service/       F# service — HTTP API, MCP server, pipeline host
├── Hermes.Web/           React 19 — canonical preview web UI
├── Hermes.Tray/          Windows tray — preview native shell
├── Hermes.UI/            Blazor components — excluded from support
└── Hermes.Shell/         MAUI Windows/macOS — excluded from support
tests/
└── Hermes.Tests/         xUnit + FsCheck
.project/
├── STATUS.md             Project dashboard
├── waves/                Active and completed work journals
├── design/               Current architecture references
└── archive/              Superseded design and planning material

Documentation

Doc Topic
STATUS.md Current state & roadmap
30 — Pipeline V5 Current DAG, file-first, and compatibility architecture
24 — Comprehension Triage and gated deep comprehension
01 — Vision Design principles
28 — File-First Archive Current storage boundary
04 — Data Model V4 Historical schema and config reference
17 — PDF Extraction PdfPig structural extraction

License

MIT