Quellgeist Logs

io.github.Rajeev-Shyam由 GitHub 帳號 Rajeev-Shyam 發布v0.1.0更新於 Oct 24, 2026

Read-only MCP server: query_logs over a structured JSONL incident log (Quellgeist triage).

已驗證STDIO僅桌面開發者工具安全與監控

概覽

AI 產生的概覽

唯讀 MCP 伺服器,提供 query_logs 工具查詢結構化 JSONL 事故日誌,支援附證據引用的故障排查。

可以做什麼
  • 查詢結構化事故日誌:對 JSONL 事故日誌執行 query_logs,取回帶穩定 id 的日誌列,可作為證據句柄引用。
  • 限制回傳筆數:單次觀測最多回傳 QG_MAX_ROWS 列(預設 200),避免大量日誌撐爆上下文視窗。
  • 支援排查流程:同一份日誌資料供本專案依信心排序的根因假設使用,每項結論引用日誌 id 或提交 sha,證據不足時直接棄答。
  • 唯讀:此伺服器被描述為唯讀,不會更動日誌。
適用情境
當助理需要在調查正式環境事故時查閱結構化事故日誌內容,或希望回答綁定可查核的日誌 id 而非轉述日誌文字時使用。它是只有單一工具的窄用途伺服器,適合日誌查閱,而非通用日誌搜尋或故障修復。
執行需求
以 stdio 在本機執行,透過 uvx 從 quellgeist 的 PyPI 套件啟動;README 指出需要 uv 與 Python 3.12 以上。環境變數 QG_LOG_PATH 指定要讀取的 JSONL 事故日誌,預設為相對於工作目錄解析的 demo/incident_logs.jsonl。未宣告任何驗證機制。
安裝前請注意
務必將 QG_LOG_PATH 指向目標檔案:預設路徑相對於工作目錄,目錄不對時會默默讀取示範日誌而非你的日誌。事故日誌可能含敏感維運資料,工具回傳的內容會交給助理及其模型供應商。此伺服器為唯讀,無法修改或刪除日誌。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Quellgeist Logs,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

Quellgeist

[ci] [security] [tuned 4B] [License: MIT] [Python 3.12+]

First-line incident triage you can trust: ranked root-cause hypotheses where every claim cites a real evidence handle — and the agent abstains rather than guess.

Quellgeist is a model-agnostic AI agent for first-line production-incident triage. It runs a legible JSON-action ReAct loop over read-only tools (structured logs + recent deploys + metric time-series), then emits a structured Diagnosis: confidence-ranked root-cause hypotheses, each backed by a structured evidence handle (LogRef.id / CommitRef.sha / MetricRef.id) the agent actually saw — never free text. Two ideas set it apart:

  • Cite-by-structured-handle. Evidence is a checkable handle, not a sentence, so a fabricated citation is measurable and deterministically rejected by a keyless fabrication check — not a matter of fuzzy string-matching.
  • Abstain-over-hallucinate. A confidently-stated wrong cause is the worst possible answer, so "insufficient evidence" is a first-class outcome.

Status: Wave 4 complete — the fine-tune works. The DR-0020 QLoRA fine-tune of the local reasoner (Qwen3-4B, served via Ollama) took it from the base's 0/16 holdout to 12/16 — zero fabrication, zero speculative-filtering, and cheaper than the base — while beating a 31B frontier (Gemma-4-31B, 10/16) on the same holdout at $0, fully offline. Non-memorisation is triangulated three ways (fixtures ≈ holdout; core-fresh ≥ core-overlap; structure probe 7/10). Two honest limits: the resource_exhaustion class didn't transfer (0/N; the frontier passes it), and adversarial-abstention recall is 6/12 at the system level — a ceiling the 31B frontier shares (also 6/12), not a fine-tune regression. When this agent misses it's incomplete or too cautious, never confidently fabricating. See Status & roadmap · fine-tune case study.

Why it's different

Evidence is a handleEach hypothesis cites a log row's source-stable id or a commit sha, copied verbatim from a tool result — the unit the deterministic fabrication check looks up. Prose lives in a display-only note. (DR-0009)
Abstention is a featureWhen signals are weak the agent returns abstained=true with a reason and an empty hypotheses list — enforced by the schema.
Model-agnostic by constructionThe loop parses JSON actions from plain chat text, so it's identical on Gemini's free tier and a local 4-bit Qwen — no dependence on any backend's native function-calling. Swap models with one config change. (DR-0008, DR-0010)
Reliability is gated, not assertedA keyless, deterministic CI gate (ruff + black + pytest, including the fixture-backed eval harness) runs on every push.

What it is / what it's NOT

  • It is: a first-line triage agent — ranked, evidence-cited root-cause hypotheses (or an honest abstention) from read-only logs/deploys/metrics, over a model-agnostic loop that runs on a hosted frontier model or a local 4B.
  • It is NOT: an autonomous remediator (it never mutates prod — resolution verification is a deferred, cut-first wave); a production-hardened service (the demo is a deliberate toy); or a general-purpose agent. The holdout it's measured on is out-of-vocabulary but in-structure — not a claim about unseen incident shapes or real production data.

Quickstart (~30 seconds to a broken service + structured logs)

Requires uv and Python 3.12+.

See a real-shaped diagnosis in one keyless command (no model, no API key):

bash
uv sync && uv run quellgeist diagnose --demo     # renders the demo incident's cited postmortem

Then run the full loop against the live toy service:

bash
uv run uvicorn demo.app.main:app          # 1. start the toy service (leave running)
# --- in a second shell, from the repo root ---uv run python -m demo.chaos.bad_deploy    # 2. inject a simulated bad deploycurl -s localhost:8000/login              # 3. trip /login -> 500s + structured error logsuv run quellgeist diagnose --show-trace   # 4. diagnose live (needs a model; see below)
uv run python -m demo.chaos.reset         # back to a green slate

The live step needs a reasoner — see Running the model. Without a key, quellgeist diagnose exits 1 with a one-line error + hint (never a traceback); --demo always works keyless and renders the same output shape deterministically from gold.

Architecture

A custom, legible loop is the orchestration layer; the three read-only tools are the evidence interface; the Diagnosis schema is the contract that the postmortem renderer and the eval judge both read.

mermaid
flowchart TD    trigger(["incident trigger - CLI"]) --> loop    model["reasoner via LiteLLM<br/>(Gemini or local Qwen, swappable)"] -. "chat completion" .-> loop
    subgraph loopbox["model-agnostic JSON-action ReAct loop"]      loop["run_loop()<br/>decide, call tool, observe, repeat"]    end
    loop -- "query_logs" --> logs["logs tool<br/>structured JSONL, stable ids"]    loop -- "get_recent_commits" --> commits["commits tool<br/>deploy_log.json, shas"]    loop -- "query_metrics" --> metrics["metrics tool<br/>time-series, named series"]    logs -- "rows + ids" --> loop    commits -- "commits + shas" --> loop    metrics -- "series + names" --> loop
    loop --> diag["Diagnosis (schema.py)<br/>ranked hypotheses citing<br/>LogRef.id / CommitRef.sha / MetricRef.id, or abstains"]    diag --> pm["postmortem renderer<br/>deterministic Markdown"]    diag --> judge["eval judge<br/>fixture scenarios, CI gate"]

All three tools are also exposed as MCP servers over stdio (python -m quellgeist.servers.logs_mcp, …commits_mcp, …metrics_mcp). The agent currently reuses the same tool functions in-process behind a ToolSpec registry; a stdio MCP-client path (the agent driving the servers over the wire) is on the roadmap (DR-0010).

Deep dive: docs/architecture.md walks the full pipeline (loop → tools → verifier → postmortem), a sequence diagram, the module map, and the cross-cutting design decisions.

The servers publish to the Official MCP Registry on each tagged release (see docs/publishing.md); once published each is runnable with uvx --from quellgeist quellgeist-logs-mcp (or …-commits-mcp / …-metrics-mcp).

Example session

Inject the bad deploy — it drops a marker that flips verify_token into a NoneType regression and writes a deploy_log.json whose offending commit landed just before the errors (illustrative stdout — the timestamp reflects when you run it; paths shown relative to the repo root):

text
$ uv run python -m demo.chaos.bad_deployinjected bad deploy a1b2c3d (touched demo/app/auth.py) at 2026-06-24T12:22:43Z  marker:     demo/.bad_deploy  deploy log: demo/deploy_log.jsonnext: hit /login to generate the 500s, then `quellgeist diagnose`

With a reasoner configured, quellgeist diagnose reads the logs + deploys and emits a postmortem. The CI environment has no validated model key (DR-0012), so the diagnosis below is rendered from gold — built deterministically from the fixture's labelled cause and evidence handles via render_postmortem, not live model output:

text
# Incident Postmortem (rendered from gold)
## Root-cause hypotheses
### 1. Bad deploy a1b2c3d (10:01:50Z) refactored auth.py and introduced a NoneType error in verify_token; /login 500s begin ~20s later at 10:02:12Z.  (confidence: 1.00)
Evidence:- log #2- commit a1b2c3d

Reproduce that render yourself (no model needed):

bash
uv run python - <<'PY'from evals.scenarios.generator import load_scenariofrom quellgeist.agent.schema import Diagnosis, Hypothesisfrom quellgeist.output.postmortem import render_postmortem
s = load_scenario("evals/scenarios/fixtures/bad_deploy_0001.json")gold = Diagnosis(hypotheses=[    Hypothesis(cause=s.gold_cause, confidence=1.0, evidence=s.gold_evidence_refs)])print(render_postmortem(gold, title="Incident Postmortem (rendered from gold)"))PY

The point isn't the prose — it's that log #2 and commit a1b2c3d are exact handles into the real signals, not paraphrases. A live run additionally fills in a one-line summary and suggested actions, and abstains outright when the evidence is too weak to name a confident cause.

Write the postmortem to a file with --out postmortem.md, or as a self-contained HTML page with --out postmortem.html (or --format html) — same deterministic render, no external assets.

Running the model

The reasoner is any LiteLLM model string, selected by --model or the QG_MODEL env var (default gemini/gemini-3.5-flash). Provider keys are read from the environment by LiteLLM; nothing is stored in the repo.

bash
export QG_MODEL="gemini/gemini-3.5-flash"export GEMINI_API_KEY="…"uv run quellgeist diagnose --show-trace

Or fully local and offline via Ollama — the intended home default (DR-0008; exact artifact pinned in DR-0019), no API key involved:

bash
ollama pull qwen3:4b-instruct-2507-q4_K_Mexport QG_MODEL="ollama_chat/qwen3:4b-instruct-2507-q4_K_M"uv run quellgeist diagnose --show-trace

Base vs tuned — important. The ollama pull above is the base Qwen3-4B: the honest safe floor — it scores 0/16 on the holdout and abstains on everything, never fabricating (DR-0019). The 12/16 headline is the DR-0020 fine-tune (quellgeist-qwen3-dr0020), which you build + serve via finetune/README.md (a free-Colab QLoRA run → ollama create). Until that tuned GGUF is published for a one-line pull, the base model is what a plain ollama pull gives you — safe, not yet useful. Use a hosted model (above) or the fine-tune to see live diagnoses.

Heads-up (DR-0012): a Gemini key on an unvalidated, no-billing project returns 429 limit: 0 on current models, so the shipped CI gate is deliberately keyless and model-driven evals are key-gated and run out-of-band (DR-0015). At home the intended default reasoner is a local Qwen3-4B via Ollama (DR-0008).

Running the eval (reasoner + verifier + LLM-judge)

The fixture eval scores the reasoner with a deterministic keyword judge + a zero-fabrication check (the keyless gate), and can additionally run two model layers (DR-0016): a verifier that confirms cited evidence supports each hypothesis (forcing abstention otherwise) and an advisory LLM-judge rubric.

bash
export GEMINI_API_KEY="…"export QG_MODEL="gemini/gemini-3.5-flash"QG_VERIFY=1 QG_JUDGE_LLM=1 \QG_MIN_CALL_INTERVAL_S=6 \      # pace calls under the free-tier RPM (avoids 429 bursts)  uv run python -m evals.run_evals

QG_VERIFIER_MODEL / QG_JUDGE_MODEL override the model per layer (default QG_MODEL). An unreachable backend (quota/503/timeout) or a rejected credential (missing/invalid/stale key) is reported as a skip, not a failure (DR-0015/DR-0017), so the out-of-band eval never reddens on a free-tier hiccup. The LLM-judge's scores are advisory (they never gate). On a human-labelled gold subset it agreed with human verdicts at Cohen's kappa 0.81 using an independent judge (groq/llama-3.1-8b-instant ≠ the reasoner) — validated on that subset (DR-0018); still self-grading whenever QG_JUDGE_MODEL equals the reasoner.

CI's out-of-band eval runs on Groq (groq/llama-3.3-70b-versatile, gated on GROQ_API_KEY): Gemini's free tier proved unusable from cloud CI (429 → 503 → timeout → invalid-key), so the reasoner was swapped with one env var — the model-agnostic thesis in action (DR-0017). The intended home default remains a local Qwen3-4B (DR-0008).

Using it on your real data

The demo eats three canonical files; your production signals don't look like that. quellgeist ingest is the adapter — point it at real sources and it writes the canonical files the tools read:

bash
quellgeist ingest \  --logs    /var/log/myapp/     # file or directory; JSONL, JSON, plain text, or mixed  --deploys deploys.json        # JSON array, GitHub payload, or `git log` text  --metrics prom.json           # a Prometheus response or a canonical array  --out-dir ./signals# prints the `export QG_*` lines; then:quellgeist diagnose --show-trace --strict-citations   # add --model / a provider key

It tolerates messy real data (foreign field names are aliased onto the schema, timestamps normalised to UTC, a malformed line coerced rather than crashing the run), and query_logs caps how many rows one observation returns (QG_MAX_ROWS, default 200) so a large log can't blow the context window. The deterministic cite-or-abstain guarantee runs at real-use time: diagnose verifies every cited handle against your real signals and warns on a fabrication (--strict-citations exits non-zero for CI). Full guide: docs/ingestion.md.

Run the live service (v2)

v2 wraps the same frozen core in a live, concurrent, observable incident-response service: a signed webhook triggers an investigation, a worker pool runs the unchanged loop over an isolated per-incident snapshot, every run is persisted to SQLite with its trace and cost, an operator approves / steers / rejects before it posts to Slack + a self-contained HTML page, and after a sandbox fix the agent re-reads signals to confirm recovery. Everything additive; the frozen measurement surface is untouched. The whole stack runs from one file:

bash
cp .env.example .env            # set QG_WEBHOOK_SECRET, QG_OPERATOR_TOKEN, QG_VERIFIER_MODEL…docker compose up --build       # demo service + agent service + Ollamadocker compose exec ollama ollama pull qwen3:4b-instruct-2507-q4_K_M   # first run only
# break it, trigger an investigation, review, then confirm the fix in the sandbox:docker compose exec demo python -m demo.chaos.bad_deploy#   … POST a signed incident to :8000/incidents, approve it on the HTML page …docker compose exec demo python -m demo.chaos.fix_deploy   # heal without wiping the log#   … POST /incidents/{id}/verify-resolution → recovered | not_recovered | inconclusive

Secrets stay env-only (public repo); the service is fail-closed — no webhook secret rejects every request, no operator token closes the operator surface, and it never posts a fabricated or unverified diagnosis. Design: DR-0023 + spec.

Status & roadmap

Built in rolling waves — only the current wave is implemented in detail (see docs/quellgeist-plan-rolling-wave.md). The full decision history lives in the ADR log.

WaveScopeStatus
0De-risk the model bet (4B can orchestrate the loop)✅ done — default = Qwen3-4B (DR-0008)
1Bad-deploy slice: demo → break → diagnose → postmortem; eval harness + CI✅ done — spine built & unit-tested
2Reliability core: verifier pass, deterministic fabrication check, abstention, LLM-as-judge✅ built — keyless deterministic gate + opt-in verifier/judge; first real run passed with zero fabrication (DR-0016/DR-0017). Judge validation + a reliability rate carry into Wave 3
3Breadth: config/env + resource-exhaustion classes, metrics, ~50 scenarios✅ done — 3 classes across a 65-scenario suite; first full run 61/65, 0 fabricated; judge validated (kappa 0.81). See the reliability + judge case studies
4Cost / fine-tune: QLoRA Qwen3-4B vs base vs frontier, with/without verifier✅ done — base 0/16 → tuned 12/16 holdout (0 fabricated, 0 speculative-filter, cheaper than base); frontier-competitive vs Gemma-4-31B (beats it 10/16 on capability, ties 6/12 on abstention); resource_exhaustion unlearned + adversarial abstention a shared 6/12 ceiling (case study, DR-0019/DR-0020)
5Polish & ship: HTML render, security pass, MCP registry, launch🚧 engineering complete — release-gated (HTML render + security scanners + threat model + registry/OIDC scaffolding done; the release tag + launch are the remaining steps)
6Resolution-verification loop⤳ folded into v2 (Wave 9)
v2 (7–9)Live incident-response service (webhook → concurrent workers → persisted runs → HITL review → Slack/HTML → sandbox resolution re-check) + Dockerfile/compose✅ built — Waves 7–9 shipped: signed webhook → concurrent workers → persisted cited runs → fail-closed HITL review gate → Slack/HTML → deterministic sandbox resolution re-check; non-root Docker + compose; 339 keyless tests, frozen diff empty (DR-0023/0027/0028, spec)
v2 Track B (10)Reliability track: timing-aware verifier + structure-varied / out-of-structure generalisation eval🚧 scoped — DR-0024–0026

The wave boundary is deliberate, not unfinished: only the current wave is built in detail, and later waves are scoped but intentionally unimplemented. v2 is additive over the proven v1 core — the frozen fine-tune measurement surface is never touched (DR-0023; guarded by tests/frozen/).

Reliability gate

The deterministic CI gate is the reliability contract: 339 tests (ruff + black via pre-commit, then pytest — covering the loop's never-crash / graceful-abstention behaviour, the deterministic fabrication check and cite-based judge gate, the verifier and advisory LLM-judge, parameterised scenario generation, the judge-validation harness, the server filters, the postmortem renderer, the fixture-backed eval harness, the real-data ingestion + robustness layer, an end-to-end real-incident harness, and the v2 live service — signed webhook, concurrent per-incident isolation, HITL review gate, and the deterministic sandbox resolution check) on Python 3.12 and 3.13.

Out of band, the model-driven eval runs the reasoner over the 65-scenario suite. The latest full run scored 61/65 passed, 0 fabricated evidence (Cerebras Gemma-4-31B) — per-class breakdown + the failure analysis in the reliability case study.

bash
uv run pytest tests/ -quv run pre-commit run --all-files

Development & contributing

See CONTRIBUTING.md for the dev setup, conventions, and the wave model; SECURITY.md for reporting and the no-secrets / toy-demo policy; and CODE_OF_CONDUCT.md for community expectations. Bug reports and feature requests use the issue templates; PRs follow the PR template.

License

MIT © Rajeev Shyam Kumar.

來源:README.md,提交 63c0260

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

1
  1. v0.1.0最新Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分