Changelog — Lawyer Assistant
Recent feature history, derived from the git history and the current working tree. This document exists so agents (and humans) can answer "what changed recently?" without digging through
git log.Conventions: date groups are newest-first; within a group, commits are listed oldest-first (chronological). Items marked Unreleased (working tree) are implemented but not yet committed. Cross-references go to the knowledge base.
Unreleased (working tree)
Work completed on top of the latest commit (52a822a). Mostly the documentation set and the pipeline-editor feature pack.
Documentation set (this session)
- Full knowledge base added under
docs/:README.md(index),QUICKSTART.md,TROUBLESHOOTING.md,ARCHITECTURE.md,BACKEND.md,FRONTEND.md,PIPELINE_EDITOR.md,GLOSSARY.md,AGENT_KNOWLEDGE_BASE.md, and thisCHANGELOG.md— every doc fact-checked against the source. AGENTS.mdat the repo root: read order, topic → source-file table, known traps, and answering etiquette for AI agents.- Root
README.mdrewritten as the current non-technical user guide (install + use via the launcher), replacing the old CLI-era content. - Docs aligned with the unified repo layout — every structure reference in
docs/now matches the current tree: the whole Python side underbackend/, the whole frontend + Electron shell underfrontend/, plus thelauncher/(setup page),assets/(screenshots) anddocs/. Stale CLI/Flask-era path claims removed.
Pipeline editor feature pack
- Sub-node split: the Search Documents and Scan Document nodes were decomposed into sub-nodes (
dense,sparse,rerank,ingest,scan) so users can remove individual stages (e.g. disable reranking). - Bypass removal: removing a sub-node auto-wires a tagged bypass edge (
bypass-<nodeId>-…) so the remaining nodes still connect. - Per-node toggle re-enable: re-enable a removed sub-node from the palette without clearing the layout; the original edges are rewired automatically.
- Persistence: node/edge layout saved to
localStorage(pipeline-layout-v1) with debounced saves, so removals/edges survive reloads; a Reset to default button restores the original flow. - Export/import: the layout can be exported/imported as a JSON file (versioned format) to share retrieval configurations across machines.
- Zero-node guard: validation prevents committing an empty pipeline.
- Backend runtime config:
POST /api/pipeline/configapplies the layout JSON to retrieval at runtime — rerank on/off from thereranknode,search_mode(hybrid/dense/sparse) + fusion weights from the dense/sparse nodes, andtop_k/top_k_retrieval/weight overrides. Runtime-only (resets on restart);GETreads it,DELETEresets. SeePIPELINE_JSON.md§10.
Workspace folders (working tree)
- Select a folder = select the workspace. The "Work in a folder" button now opens a native Electron directory dialog (
folder:selectIPC, absolute path) instead of only reading the folder name from awebkitdirectoryinput. - New backend workspace API:
POST/GET/DELETE /api/workspaceandPOST /api/workspace/ingest. Setting a workspace re-points storage — raw uploads land directly in the folder, andprocessed/chroma_db/bm25_indexlive under it — so search & ingestion are isolated per workspace instead of the static projectdata/. - Frontend wiring:
App.tsxsets the workspace on pick, refreshes the discovered file list, and passes workspace file absolute paths on send (no byte re-upload);WorkspacePanelshows a workspace card with an Ingest all files action. Browser fallback (no Electron bridge) keeps the oldwebkitdirectorybehavior. - Runtime-only: the override resets on restart / DELETE.
UI fixes (this session)
- Chat input container height reduced ~50%.
- Attachment (+) button wired to the upload backend, and drag-and-drop of files onto the composer added (committed as
fe7e13a).
Citation integrity & retrieval warnings (working tree)
- Citation schema validation (
sanitize_citationsinbackend/legal_retrieval/utils.py, applied on both routers' done events and inchat.py/pipeline.py): a citation marker must be an integer in[1, len(sources)]. Malformed markers like[18](no such source) and[1.9]/[14]/[10.2](in-document section numbers leaking into citation output) are stripped before reaching the UI. - Citation content verification: each
[N]is checked against the cited chunk's actual text — the chunk must share enough of the claim's distinctive content words (lexical-entailment heuristic). A chunk that does not support the sentence loses its citation marker, so one top-ranked chunk can no longer be cited for five unrelated clause types. - Answer prompt hardened (
prompts_intent.py"answer" +router.pysystem prompt): explicit rules against leaking section numbers into[N]markers, against reusing one source for unrelated clauses, and a document-scope rule — when results span multiple unrelated companies/entities, section the answer by document instead of blending into one false "this Agreement" narrative, and state the ambiguity. - Retrieval-quality caveats (
derive_retrieval_warning): done events now carryretrieval_warningwhen the top score is below 70% (weak match) or results span multiple documents; the UI renders it as a visible banner above the answer (client-side fallback for legacy messages).
Answer-transparency & trust fixes (this session)
- Abstain signal shipped end-to-end: the backend now emits
answer_found: falseon the done event (both routers +/api/chatresponse) whenever the pipeline abstains. The UI trusts this signal and:- hides the confidence percentage bar and the real citation chips on abstained answers,
- shows a muted "Closest match found (not used)" row instead of a real citation when chunks were retrieved but rejected,
- shows the three-state
ConfidenceBadge(Found / Partial / Not Found) instead of a raw percentage on real answers.
- Step counts moved to a debug view: "Process (27 steps, 0 tools)" and "Pipeline (N steps)" labels no longer appear in the default user-facing view; step/tool counts live inside the collapsible process section only.
- Temp/lock files filtered (
~$…Word locks,.~lock…#LibreOffice locks,.tmp/.temp/.bak/.swp/.part): excluded from directory ingestion (ingestion.py,retrieval.py), fromVectorStore.list_files(retroactive — already-indexed junk no longer lists), and from the workspace file listing.
Security hardening & CI (this session)
- Content-Security-Policy injected into the renderer HTML by a Vite plugin (
contentSecurityPolicy()infrontend/vite.config.ts): production shipsscript-src 'self'(no inline scripts, nounsafe-eval), development allows'unsafe-inline'+ the HMR websocket — both modes silence Electron's insecure-CSP warning. webkitdirectorywarning fixed — the folder-picker input passes the Chrome-only attribute as a string with a properreactmodule type augmentation instead of@ts-ignore.- CSP regression guard in CI —
frontend/scripts/check-csp.mjsfails the build (exit 1) whendist/index.htmlis missing its CSP meta tag or any policy containsunsafe-eval. Wired intonpm run build(frontend self-check) and added as a standalonecheck:cspscript + a GitHub Actions workflow (.github/workflows/ci.yml) that installs, builds, and verifies the CSP on push/PR — the security posture can't regress silently. - Electron renderer security guard —
frontend/electron/scripts/check-electron-security.mjsstatically scans the main-process sources (frontend/electron/src/main) and fails the build when anyBrowserWindowdoes not setsandbox: true,contextIsolation: true, andnodeIntegration: falseexplicitly (or uses an unverifiable spread/variablewebPreferences), or when theno-sandboxcommand-line switch is used anywhere.window.tsnow setssandbox: trueexplicitly. Wired intonpm run build(electron self-check), acheck:securityentry, and a dedicatedelectron-securityjob in the CI workflow — CSP covers what the renderer may load, these flags cover what it can do.
2026-07-31 — light mode & drag-and-drop
| Commit | Change |
|---|---|
4d59014 | Light/dark mode fixes — hard-coded colors corrected so text never matches its background |
fe7e13a | Drag-and-drop file upload — drop documents onto the chat input area (in addition to the picker) |
52a822a | Default to light mode — app opens in light mode; html.light class bridged with the theme store |
2026-07-30 — pipeline editor, chain of thought, retrieval tuning
| Commit | Change |
|---|---|
1482664 | Pipeline editor — custom nodes added; nodes can be removed on the canvas |
0733f80 | Chain of thought — agent reasoning steps surfaced to the user |
4a188e4 | Procedure visible — the agent's procedure persists and is shown to the user |
b57ba86 | Ranking optimized |
fb84828 | Playbook and agent combined — compliance scanning integrated with the agent loop |
7828f6a | Router logic enhanced |
7cd76b9 | Full paragraph save to ChromaDB — paragraphs stored as retrieval units |
0455021 | UI improved with more confidentiality terms |
2093a26 | UI enhanced |
c167f93 | Animation enhanced |
2026-07-29 — streaming, approval dashboard
| Commit | Change |
|---|---|
76886c5 | UI enhanced |
c60ee4a | Loop state mismatch solved |
de43a6f | Approval & processing dashboard added (human-in-the-loop UI) |
82f0825 | Streaming reply added — SSE token streaming to the chat |
2026-07-28 — pipeline loop & centralized prompting
| Commit | Change |
|---|---|
da0bc85 | Dense + sparse results mixed before reranking |
7667190 | Centralized prompt — pipeline restructured with verify / generate / post-generate nodes |
1ae9603 | Pipeline loop added + UI |
2026-07-27 — benchmarking
| Commit | Change |
|---|---|
2a8af23 | Benchmarking added to the docs (backend/benchmark/ harness, golden eval) |
2026-07-26 — initial release
| Commit | Change |
|---|---|
4fd5ee7 | First commit — project scaffold |
How to keep this file accurate
- When a new feature ships, add an entry at the top (Unreleased → dated block on commit).
- If you are an agent answering "what changed recently?", read this file first, then verify against
git logand the feature docs linked above. - Deep dives:
PIPELINE_EDITOR.md(editor),BACKEND.md(engine),FRONTEND.md(UI),TROUBLESHOOTING.md(known failures).