When a user comments on a Paperclip issue, the built-in automation wakes
the assigned agent directly, bypassing the CEO. This meant user instructions
(like "read the uploaded draft and route to the right agent") were ignored.
Changes:
- Plugin: add issue.comment.created event handler that wakes the CEO agent
with the comment context (plugin-legal-ai, separate repo)
- HEARTBEAT: add steps 2b (read recent user comments) and 2c (check
attachments) before agents start working
- CEO agent: add comment-routing section — read, check attachments, route
- Writer agent: add step 0 — check for uploaded DOCX drafts before writing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The old legal-ai-web app (my85gabx...) was deleted — consolidated into
a single ezer-mishpati-web (a99ivjv...) serving both domains.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The drafts panel now checks for עריכה-v* files and shows the correct
draft number (e.g. "טיוטה 2 (מתוקנת) מוכנה לעיון") instead of always
displaying "טיוטה ראשונה מוכנה לעיון".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Deleted from Coolify (was exited:unhealthy since Apr 7)
- Updated CLAUDE.md service table: Paperclip is now pm2/local
- Removed Docker skills path fallback in app.py (always use local)
- Removed old paperclip-bug-report.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add DELETE /api/cases/{case_number}/exports/{filename} endpoint
- Add useDeleteDraft hook in exports API
- Add trash icon + confirmation dialog in drafts panel UI
- Final files (סופי-) cannot be deleted as a safety measure
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Install git in Docker image and wrap all subprocess git calls in
try/except so a missing or failing git binary never kills an upload
that already succeeded.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a case is created, a Paperclip project is now automatically created in
the correct company based on the appeal_subtype tag. Tag-to-company mappings
are managed via a new Settings page that pulls companies from Paperclip DB.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move draft management (export DOCX, download, upload revised version, mark
final) and chair feedback into a new "טיוטות והערות" tab on the case detail
page. Remove the standalone /feedback page and its nav link since feedback
is now case-scoped.
Also fix /api/admin/skills 500 error when Paperclip DB is unreachable by
adding a connection timeout and graceful fallback to disk-only skills.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added analyst_verified, research_complete, analysis_enriched, and
ready_for_writing statuses across all UI components: status-badge,
workflow-timeline, status-donut, status-changer, status-guide, and
kpi-cards. Also changed qa_review label from "QA" to "בדיקת איכות".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After Dafna fills her positions in the analysis document, the analyst
now runs a second pass to: verify cited case law against corpus and
case documents, deepen factual findings based on the chosen direction,
close open questions, and strengthen CREAC preparation.
Pipeline flow updated: direction_approved → analyst pass 2 →
analysis_enriched → CEO creates writer issue → ready_for_writing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The merge of ui-rewrite removed these parameters from db.search_similar()
and db.create_case() but left the callers passing them, causing TypeError
on any corpus search. Restores the parameters and adds schema migration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PUT /api/cases/{n}/research/analysis/upload accepts a markdown file and
validates: UTF-8 encoding, parseable structure, at least one threshold
or issue section, matching case number. Backs up existing file before
replacing. UI adds "העלה ניתוח מעודכן" button with status feedback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Curl was installed to download Node.js setup script then purged.
Coolify needs it for HTTP health checks inside the container.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every push to main tags with latest + build-N (run number).
Pushing a git tag like v1.0.0 also tags the image with that version.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New GET /api/cases/{n}/research/analysis/download endpoint returns the
raw markdown file. UI adds a "הורד ניתוח" button next to "חזרה לתיק"
on the compose page, visible only when analysis data is loaded.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Four functions were called by tools/precedents.py but never implemented
in services/db.py: create_case_precedent, list_case_precedents,
delete_case_precedent, search_precedent_library. This caused 500 errors
on the /api/cases/{n}/precedents endpoint.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Job containers were on isolated network, couldn't reach Coolify API.
Now runner config sets container.network=coolify and curl targets
http://coolify:8080 (internal container name).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On push to main, the workflow builds a Docker image, pushes to
Gitea Container Registry, then triggers Coolify to pull and redeploy.
Replaces the old Dockerfile-build-on-deploy approach.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ScrollArea (Radix) injected display:table on viewport, preventing
scroll — replaced with plain div + overflow-y-auto. Preview dialog
never loaded text because onOpenChange doesn't fire on initial mount —
replaced with useEffect that fetches on open.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documents tab was limited to ~9 visible items due to fixed max-height
without overflow-hidden. Now uses 70vh with proper overflow. Added
click-to-preview (shows extracted text in dialog) and delete button
with confirmation dialog + backend DELETE endpoint.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- StatusBadge: added icons (lucide-react) and Hebrew descriptions for all 13 statuses
- WorkflowTimeline: added phase icons and current-status description display
- StatusGuide: new collapsible component showing all statuses grouped by phase with explanations
- StatusChanger: new dropdown for manual status override on the case detail sidebar
- Case detail page: merged action buttons into overview tab, removed separate actions tab
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
uvicorn was running in background with no output capture,
making it impossible to debug crashes. Now redirects stderr
to stdout and checks if uvicorn started successfully.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pymupdf and other native deps need compilation on Alpine.
Switch to Debian-based python:3.12-slim which has pre-built
wheels available, avoiding the need for gcc/build-essential.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Next.js app was proxying /api/* to the old Flask/FastAPI server
at legal-ai.nautilus.marcusgroup.org. When that server went down,
the Next.js app's API calls failed with 503.
Now both services run in the same container:
- FastAPI (uvicorn) on :8000 — the API backend
- Next.js (node) on :3000 — proxies /api/* to localhost:8000
Changes:
- Dockerfile: multi-stage build with Python 3.12 + Node.js
- next.config.ts: default proxy target is now 127.0.0.1:8000
- start.sh: launches uvicorn in background + node in foreground
- pyproject.toml: add fastapi + uvicorn as explicit deps
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The status map was using informal descriptions ("מסמכים הוגהו")
instead of actual DB values. Now each row shows:
- The exact status string in cases.status
- Which agent sets it
- What the CEO should do next
New statuses added: proofread, analyst_verified, research_complete,
qa_passed, qa_failed, exported. Removed ambiguous conditions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every agent now has explicit instructions in its own definition file,
not just in HEARTBEAT.md. An agent following only its own step-by-step
instructions will do the right thing on any new case.
All 6 non-CEO agents: explicit wakeup CEO block in completion step
(curl API + psql fallback, with agent name customized)
legal-ceo.md: issue template for analyst with 5 mandatory items
(document mapping table, no-extract list, split large docs,
wakeup CEO, blocked if failed)
legal-writer.md: explicit Read of decision-methodology.md as step 1
(before case_get, not just "read before starting")
legal-qa.md: methodology_compliance severity → critical
(was warning — decisions without syllogisms/steel-man now blocked)
legal-proofreader.md: added case_update tool + status='proofread'
(was missing entirely — CEO couldn't know proofreading was done)
legal-researcher.md: added case_update + mail notification
(was missing — CEO couldn't know research was done)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major changes from ui-rewrite branch:
- Decision-writing methodology (decision-methodology.md) based on FJC, Garner, Posner
- 5 source books downloaded and processed (341K words)
- Methodology integrated into block-yod prompt
- All 8 Paperclip agents updated for methodology compliance
- DB schema V4: claim handling, standard of review, precedent hierarchy
- 15 pipeline gaps identified and fixed after test run on case 1130-25
- Negative checks layer added to CEO and QA agents
- HEARTBEAT: wakeup CEO on completion + blocked status
- Flexible claim handling (bundle/skip via chair_directions)
Conflicts resolved: all 5 files use ui-rewrite version (the latest).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documents >15K chars must be split by chapter/section and extracted
in parts. If extract_claims times out, retry with chunks or extract
manually. This prevents the Matmon document issue (108K chars, 4x timeout).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Test run on case 1130-25 revealed critical gaps. This commit fixes:
HEARTBEAT.md (#1, #11):
- Agents MUST wake CEO after completing any task (wakeup request)
- New "blocked" status option — agents cannot mark "done" if something failed
- Fallback: direct DB insert if API wake doesn't work
legal-analyst.md (#2):
- New step 6: completeness checks BEFORE finishing
- Verify all appeal/response documents extracted successfully
- Verify all extracted documents produced claims
- Verify classification is correct (no claims from committee)
- If any check fails → status = "blocked", not "done"
legal-ceo.md (#3, #6, #7, #12, #13, #14, #15):
- Step A rewritten with 3 sub-checks:
A1: extraction completeness (no missing documents)
A2: negative checks (wrong classification, abnormal counts, missing parties)
A3: methodology compliance (syllogisms, CREAC prep, steel-man, etc.)
- Any failure blocks progress to step B
legal-qa.md (#6 reinforcement):
- New step 2b: negative checks on the written decision
- Missing issues, bare quotes, empty formulas, mixed findings/conclusions
Also:
- Synced all agent files to /home/chaim/legal-ai/ (Paperclip reads from there)
- Synced methodology + lessons + corpus docs
- Fixed claim classification in DB: 20 committee/applicant claims → response (#5)
Remaining gaps (3):
- #4: Paperclip cache may need restart to pick up new definitions
- #7: Matmon document retry (25K words, 0 claims extracted)
- #9: 53 appellant claims may need synthesis (high but not blocking)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New columns for methodology-aware decision pipeline:
claims table:
- claim_handling (address/bundle/skip) — per-claim handling mode
- bundle_group — group name for bundled claims
- handling_reason — explanation for skip/bundle
cases table:
- standard_of_review — review standard (independent discretion / etc.)
- subject_categories — JSONB array of topics in the appeal
case_law table:
- precedent_level — hierarchy (supreme/administrative/national/district)
- is_binding — binding holding vs. obiter dictum
- creac_role — how it serves reasoning (rule/explanation/analogy)
decisions table:
- issue_order — JSONB array of ordered issues with type
- claim_handling — JSONB overrides from chair_directions
Migration tested and applied successfully on production DB.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
"בית ספר להחלטות" Phase 2 — the system now has formal analytical
methodology for building quasi-judicial decisions, separate from
Dafna's writing style (SKILL.md) and content checklists.
What was done:
- Downloaded 5 authoritative sources (~341K words): FJC Judicial
Writing Manual (1991+2020), Garner Legal Writing in Plain English,
Posner How Judges Think, Scalia/Garner Making Your Case
- Extracted principles from all sources into intermediate docs
- Synthesized into docs/decision-methodology.md (3,400 words,
12 sections, 10 guiding principles)
- Integrated methodology into block-yod prompt via {methodology_guidance}
- Restructured legal-writer agent workflow to follow analytical stages
- Made "answer all claims" flexible (bundle/skip via chair_directions)
- Added methodology compliance check (#7) to legal-qa agent
- Updated all knowledge files (CLAUDE.md, SKILL.md, lessons, corpus)
Three-layer architecture:
1. Methodology (decision-methodology.md) — universal, how to think
2. Content checklists (lessons.py) — specific per appeal subtype
3. Style (SKILL.md) — Dafna's personal writing patterns
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend changes cherry-picked from ui-rewrite branch to enable
feedback API endpoints for the Next.js staging UI.
- chair_feedback DB table + API endpoints (GET/POST/PATCH)
- Content checklists by appeal subtype injected into block-yod prompt
- MCP tools for recording and listing chair feedback
- Corpus analysis documentation (24 decisions)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses Dafna's observation that licensing decisions lack comprehensive
planning discussion. Systematic corpus analysis of all 24 training decisions
revealed the system learned writing style but not substantive content.
Changes:
- Corpus analysis of all 24 decisions (docs/corpus-analysis.md)
- 5 content checklists by appeal subtype injected into block-yod prompt
- chair_feedback DB table + API endpoints + MCP tools
- Feedback management page in Next.js UI (/feedback)
- Navigation updated with "הערות יו״ר" link
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The analysis-and-research.md content has markdown tables (ציר דיוני)
and inline formatting like **label:** strong runs, which were
rendering as raw pipes and dashes because the compose page used
whitespace-pre-line on plain text.
Add a reusable <Markdown> component backed by react-markdown +
remark-gfm with a custom `components` map that styles paragraphs,
lists, blockquotes, strong runs, and especially GFM tables for RTL
+ aligned columns:
- table: table-auto + border-collapse, wrapped in overflow-x-auto
so very wide tables don't push the parent card out
- th: whitespace-nowrap so the header row sets column widths and
every row border lines up row-to-row
- everything text-right + the whole block gets dir="rtl" at the root
Use it in three places on the compose screen:
- ProseSection (represented_party, procedural_background,
agreed_facts, disputed_facts)
- Conclusions card
- SubsectionCard field content — threshold_claims and issues have
the same markdown shape in their fields[]
react-markdown + remark-gfm added (~30KB gzipped).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop the max-w-4xl wrapper so the compose cards fill the available
width of the AppShell main (which is already capped at 1400px
upstream). Threshold claim / issue cards with long Hebrew prose
now get the room they need without horizontal dead space.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The right sidebar with "רקע לניתוח" and "מסקנות" was stealing
horizontal space and forced the editable cards (threshold claims,
issues, chair positions, now precedents) into a narrow column. Move
both cards into the main stack, after the issues list, so the chair
sees the decision points first and the surrounding context after.
Collapse the lg:grid-cols-[1fr_320px] layout into a single max-w-4xl
stack since there's no longer a sidebar. Bump the moved cards from
px-5 py-4 to px-6 py-5 to match the rest of the compose page's
card padding.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop the defaultOpen={i===0} on the first threshold_claim — when a
case has a lot of material already on screen (research background
+ chair positions + now precedents), auto-opening the first card
creates a wall of text on page load. All cards now start collapsed,
same as the issues list already did.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Surface the new POST/GET/DELETE /api/cases/{n}/precedents endpoints
in the compose screen as two insertion points:
1. A new case-level card "פסיקה כללית לדיון" at the top of the
main column, for precedents that support the discussion intro
rather than a specific threshold_claim / issue.
2. An inline "פסיקה תומכת" section inside each SubsectionCard,
below the ChairEditor.
Both insertion points render a `<PrecedentsSection>` which shows a
list of `<PrecedentCard>` (citation + blockquote + optional chair
note + 📄 chip if a PDF was archived) followed by a `<PrecedentAttacher>`
popover trigger.
The Attacher is a Popover with cross-case typeahead: typing 2+
characters into the citation field hits /api/precedents/search and
shows distinct library matches; picking one prefills quote + chair
note but leaves them editable so customizing the quote for this
case doesn't mutate the library. An optional PDF/DOCX/DOC file can
be attached — it uploads first via POST .../upload-pdf and the
returned document_id is passed into the precedent create call.
The parent compose page issues a single useCasePrecedents query
and partitions the result by section_id into a Map so each
SubsectionCard renders its own slice without re-fetching.
shadcn Popover installed as a new primitive. sonner toasts wired
for success/error in both attach and delete flows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New self-contained table + MCP tools + FastAPI endpoints for letting
the chair attach external case-law quotes (quote + citation מראה מקום,
optional chair note, optional archived PDF) to either a specific
threshold_claim / issue or the case as a whole.
Data model
- case_precedents (SCHEMA_V5_SQL) — case_id, section_id NULL/
"threshold_N"/"issue_N", quote, citation (free-text), chair_note,
pdf_document_id FK to documents, denormalized practice_area for
cross-case library filtering.
- Deliberately NOT linked to the existing case_law table — that one
has UNIQUE(case_number) which would force parsing the free-text
citation into a structured key. A backfill pass into case_law is
a later follow-up once the UI stabilizes.
- db.py gains 4 helpers: create_case_precedent, list_case_precedents,
delete_case_precedent, search_precedent_library. The last uses
DISTINCT ON (citation) for the cross-case typeahead so each
precedent appears once even if reused across many cases.
MCP tools (legal_mcp/tools/precedents.py)
- precedent_attach, precedent_list, precedent_remove,
precedent_search_library — registered in server.py.
FastAPI (web/app.py)
- POST /api/cases/{n}/precedents — create, with PrecedentCreateRequest
- POST /api/cases/{n}/precedents/upload-pdf — one-shot PDF upload to
a dedicated documents/precedents/ subdirectory, creates a
documents row with doc_type="precedent_archive" and no text
extraction (archive only)
- GET /api/cases/{n}/precedents — list
- DELETE /api/precedents/{id} — uses path param since precedent_id
is a UUID (slash-safe, unlike case numbers)
- GET /api/precedents/search?q=...&practice_area=... — library
typeahead
Block-writer integration into _build_precedents_context is a deferred
follow-up — Phase 1 surfaces the feature in the compose UI only.
Plan: ~/.claude/plans/woolly-cooking-graham.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Force the title + meta column to the inline-start (visual right in
RTL) and the doc_type badge to the inline-end (visual left). The
previous layout used justify-between with an ambient dir="rtl"
inherited from <html>, but the Radix ScrollArea Viewport was eating
the direction context and flipping the row to LTR.
Fix: set dir="rtl" explicitly on both ScrollArea and the inner ul,
drop justify-between, and use ms-auto on the badge so it grows its
inline-start margin regardless of ambient direction. Title column
gets an explicit text-right for good measure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three user-reported bugs on /cases/[caseNumber]:
1. Documents tab showed "9 מסמכים" in the count but rendered nothing —
DocumentsPanel was reading filename/category/status/size_bytes/uploaded_at,
but the real FastAPI payload (case_get → db.list_documents) returns
title/doc_type/extraction_status/page_count/created_at. Rewrote the
panel against the actual document row shape, added a CaseDocument
type alias in lib/api/cases.ts, mapped doc_type to Hebrew labels
(כתב ערר / כתב תשובה / ...) and extraction_status likewise.
2. The "פעולות" tab showed a debug-flavoured paragraph "עריכת פרטי התיק
נשמרת מיד דרך PUT /api/cases/1033-25" — that was internal wording,
not user copy. Removed.
3. Overview tab showed the raw enum value "full_acceptance" in the
expected-outcome line. Mapped through the existing expectedOutcomes
label array so it now reads "קבלה מלאה".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>