Until now changing a document's doc_type required a manual SQL update.
Adds an inline editor on the document badge so the chair can retag
without leaving the case page, and threads an appraiser_side tag
(committee / appellant / deciding) through the appraisal pipeline so
betterment-levy cases — which usually have 2-3 appraisers — render
conflicts with the deciding appraiser's view marked as governing.
Backend
- New appraiser_facts.appraiser_side column (V5.1) populated from
documents.metadata.appraiser_side at extraction time.
- extract_appraiser_facts now returns status='sides_missing' with the
list of untagged appraisals instead of running with empty side
labels — chair must tag every appraisal first via the UI.
- Conflict detection orders entries committee → appellant → deciding so
the deciding appraiser appears last; block-tet's prompt instructs the
writer to phrase the deciding appraiser's view as the governing
factual finding ("ואולם, השמאי המכריע קבע...").
- New PATCH /api/cases/{n}/documents/{doc_id} (Pydantic model with
whitelist validation) and matching document_update MCP tool. Both
merge appraiser_side into metadata JSONB instead of touching the
schema.
UI
- New shared doc-types module exports the canonical 11 doc_type
options plus the 3 appraiser-side options; both upload-sheet and
the document badge now read from it instead of duplicating Hebrew
labels.
- New DocumentTypeEditor renders a Popover off the doc-type Badge
with two Selects. The save button stays disabled while doc_type is
appraisal but no side has been picked, mirroring the backend
enforcement so the user finds out before triggering extraction.
- usePatchDocument React-Query mutation invalidates the case detail
on success so the badge updates without a manual refresh.
The backend (app.py, documents.py, models.py) already maps appraisal→שומה
but the frontend DOC_TYPE_LABELS and upload DOC_TYPES dropdowns were
missing the entry, so appraisal documents rendered as the raw English
string instead of the Hebrew label.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Paperclip auto-blocks any in_progress issue without a live execution path
within ~1 minute of the run finishing. When the CEO ends a run with an
@chaim question pending, the main case issue was staying in_progress and
getting auto-blocked, flooding the case timeline with "automatically
retried continuation" system comments (7 occurrences on 2026-04-16).
Add an explicit status protocol to the CEO instructions:
- in_review at the end of any run that leaves a pending @chaim question
- in_progress when resuming from user_commented (also at start of comment routing)
- done only after final export
Applied at all three @chaim waiting points (stages B/C) and at the top
of comment routing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lets the chair generate a partial decision DOCX before the discussion-and-
ruling block is decided. Same template, skill and DOCX styling as the final
decision (David, RTL, bookmarks) — only the block selection and order differ:
רקע (ו) → תכניות+היתרים (ט) → טענות (ז) → הליכים (ח). The opening (ה),
ruling (י), summary (יא), and signatures (יב) are omitted.
- New appraiser_facts table + CRUD + conflict detection in db.py (V5 schema).
Conflict = same plan/permit identifier reported differently by 2+ appraisers.
- New appraiser_facts_extractor service: per-appraisal Claude extraction of
plans + permits with raw quotes and page numbers.
- block-tet prompt extended with a permits sub-section sourced from the
extracted facts, plus an explicit instruction to flag inter-appraiser
conflicts in neutral wording without resolving them (deferred to block-yod).
- block-chet prompt extended with a post-hearing materials context sourced
from documents.metadata.is_post_hearing.
- docx_exporter.export_decision now accepts mode='interim' which reorders
the blocks per the chair's mental model and writes
טיוטת-ביניים-v{N}.docx (versioned independently of regular drafts).
- 3 new MCP tools: extract_appraiser_facts, write_interim_draft,
export_interim_draft. write_interim_draft auto-runs extraction if the
appraiser_facts table is empty for the case.
- Remove "מסמכים" tab; render DocumentsPanel at the bottom of the Overview tab
- Move "פתח בעורך ההחלטה" and "עריכת פרטי תיק" into the top row, right of tabs, before "העלאת מסמכים"
- Drop the redundant document count from the quick-summary grid (list is visible below)
- Add flex-wrap to the header row so the extra buttons flow onto a second line on narrow screens
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Missing entries added:
- product-specification.md (business/product spec)
- new-company-setup-guide.md (CMPA setup)
- audit-report.md
- case-migration-tracker.md
- decision-block-mapping.md
All 14 files in docs/ are now indexed in CLAUDE.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The old architecture.md was out of date (mentioned n8n which isn't used,
wrong embedding dimensions, missing multi-tenancy, no edit loop).
The rewrite documents the full process end-to-end:
1. Document upload + OCR + embedding
2. Analysis (proofreader, researcher)
3. Outcome + direction decision (CEO + human)
4. Deep analysis (pass 2)
5. Drafting (writer writes 12 blocks)
6. QA
7. Initial DOCX export (with bookmarks for future revisions)
8. Edit loop with Track Changes — the new architecture:
a. User downloads + edits in Word + uploads עריכה-v{N}.docx
b. Backend auto-retrofits bookmarks + registers as active_draft
c. User asks CEO for specific change in Paperclip comment
d. CEO stage G: calls writer in revision mode → builds revisions JSON
e. docx_reviser applies <w:ins>/<w:del> preserving user's template
f. User Accept/Reject from Word Review tab
g. Repeat until marked final
Plus MCP tool reference, API endpoints, DB schema, multi-tenancy,
technology stack.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The analysis DOCX exporter loads skills/docx/decision_template.docx at
runtime, but .dockerignore was excluding the entire skills/ tree and
Dockerfile didn't COPY it — so the deployed container returned
'Template not found at /app/skills/docx/decision_template.docx' on
every /export-docx request.
.dockerignore Re-include the one file we need at runtime.
Dockerfile COPY that single file into /app/skills/docx/.
Documentation and SKILL.md stay outside the image.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Documents the rules and decisions behind building DOCX files from דפנה's
decision template (טיוטת החלטה.dotx). The implementation lives in
mcp-server/src/legal_mcp/services/analysis_docx_exporter.py; this skill
captures the "why" so future improvements don't need to rediscover it.
Contents:
SKILL.md 5 critical rules, style mapping table,
export flow, line classification,
dash policy, placeholder handling,
troubleshooting, future TODOs
references/dotx-to-docx.md why python-docx can't open .dotx +
the conversion recipe
references/rtl-runs.md why <w:rtl/> is required on every run
(otherwise Hebrew falls back to
Times New Roman)
references/style-mapping.md XML dump of every template style,
with the Title-via-theme gotcha
references/line-classification.md the 7 regex categories in
_classify_line() with real examples
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes critical bug in 1033-25: user-uploaded עריכה-*.docx files were
orphaned on disk while exports kept rebuilding from stale DB blocks.
New architecture:
- User-uploaded DOCX becomes the source of truth (cases.active_draft_path)
- System edits via XML surgery with real Word <w:ins>/<w:del> revisions
- User can Accept/Reject each change from within Word
Components:
- docx_reviser.py: XML surgery for Track Changes (15 tests)
- docx_retrofit.py: retroactive bookmark injection with Hebrew marker
detection + heading heuristic (9 tests)
- docx_exporter.py: emits bookmarks around each of the 12 blocks
- 3 new MCP tools: apply_user_edit, list_bookmarks, revise_draft
- 4 new/updated endpoints: upload (auto-registers active draft),
/exports/revise, /exports/bookmarks, /exports/{filename}/retrofit,
/active-draft
- DB migration: cases.active_draft_path column
- UI: correct banner using real v-numbers, "מקור האמת" badge,
detailed upload toast with bookmarks_added/missing_blocks
- agents: legal-exporter (3 export modes), legal-ceo (stage G for
revision handling), legal-writer (revision mode)
Multi-tenancy:
- Works for both CMP (1xxx cases) and CMPA (8xxx/9xxx cases)
- New revise-draft skill added to both companies
- deploy-track-changes.sh syncs skills CMP ↔ CMPA
- retrofit_case.py: one-off retrofit of existing files
Tests: 34 passing (15 reviser + 9 retrofit + 4 exporter bookmarks + 6 e2e)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- legal-analyst: opus 4.6 → opus 4.7
- legal-proofreader: opus 4.6 → opus 4.7
- legal-writer: sonnet 4.6 → opus 4.7 (complex block writing benefits from stronger model)
- block_writer MODEL_MAP: updated opus ID to 4.7
Opus 4.7 brings: high-res images (2576px), better file-based memory,
improved DOCX generation, and task budgets for agentic loops.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New issues created by the CEO via curl were missing plugin_state records,
causing them to be invisible in the legal-ai UI. Added iron rule: after every
POST to create an issue, INSERT into plugin_state with the case number.
Also fixed 8070-25 CMPA issues directly in DB (3 records added).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Agent status widget now checks heartbeat_runs + wakeup_requests to determine
if an agent is running on *this* case. Agents running on other cases show as idle.
Added "running" to STATUS_DOT/STATUS_LABEL maps so it displays in Hebrew.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New /methodology page with 3 tabs for viewing and editing decision
writing methodology. Uses DB override pattern: hardcoded Python
constants serve as defaults, edits saved to appeal_type_rules table,
delete restores default.
Backend: 3 generic endpoints (GET/PUT/DELETE /api/methodology/{category}/{key})
with validation per category type.
Frontend: methodology.ts hooks, GoldenRatiosPanel (number inputs per
outcome/section), DiscussionRulesPanel (accordion with textarea per
rule), ContentChecklistsPanel (markdown editor with preview toggle).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add strip_nevo_preamble() to extractor.py — auto-removes Nevo database
headers (bibliography, legislation, mini-ratio) during training upload
- Add appeal_subtype column to style_patterns table — patterns are now
stored per subtype instead of globally mixed
- Update clear_style_patterns() to support subtype-scoped deletion
- Pass appeal_subtype through analyze_corpus → store → upsert pipeline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Support ingestion of betterment levy (היטל השבחה) decisions into a
separate training corpus (CMPA). Key changes:
- Add .doc file extraction via LibreOffice conversion in extractor
- Add practice_area/appeal_subtype columns to style_corpus table
- Route training files to cmp/ or cmpa/ subdirs based on appeal subtype
- Fix derive_subtype to handle ARAR-YY-NNNN format (was matching year digit)
- Expose practice_area/appeal_subtype params in MCP upload_training tool
- Add appeal_subtype filter to analyze_style for per-type style analysis
- Update betterment levy methodology in lessons.py: checklist (from generic
to corpus-based), opening/closing strategies, and discussion rules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UUID and datetime objects from PostgreSQL RETURNING * were not
serializable. All other tool files already used default=str.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Created 7 agents in CMPA (betterment levy) company, mirroring
the CMP agents with same config and hierarchy. CEO_AGENTS dict
maps company_id to the correct CEO for wakeup routing.
wake_ceo_agent and post_comment now resolve the correct CEO
based on company_id. create_workflow_issue returns company_id.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Role labels: ceo→מנהל, researcher→חוקר, engineer→מהנדס, qa→בודק איכות
Issue status: in_progress→בביצוע, done→הושלם, todo→לביצוע, etc.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New "Agents" tab in case detail shows all Paperclip agent comments,
issue status, and agent status for each case — eliminating the need
to switch between Legal-AI and Paperclip UIs.
Backend: 4 new DB query functions in paperclip_client.py (issues,
comments, agents, post_comment) + 2 new API endpoints (GET/POST
/api/cases/{case_number}/agents). Comment posting uses Board API
with DB+wakeup fallback to ensure CEO routing.
Frontend: agents.ts hooks (10s polling), AgentActivityFeed component
(markdown timeline + comment input), AgentStatusWidget (sidebar),
4th tab in case detail page.
Also includes new-company-setup-guide.md documenting the process
for setting up the betterment levy (CMPA) company.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CEO agent was reverting case status from "processing" to "new" when
updating metadata fields. Added ordered status list — case_update now
silently ignores status changes that would move backwards.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These are source extractions that fed into decision-methodology.md.
Not read by agents — kept as audit trail for methodology origins.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete web/static/index.html and design-system.css (replaced by Next.js)
- Remove GET / HTML route and StaticFiles import from app.py
- CLAUDE.md: document that web/ = FastAPI API, web-ui/ = Next.js frontend
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Active scripts (5): auto-sync-cases.sh, backup-db.sh, restore-db.sh,
notify.py, bidi_table.py
Archived (17): one-time migration/seeding scripts whose functionality
is now in MCP server or web API. Moved to scripts/.archive/
Deleted (5): zero-value scripts (duplicates, hardcoded single-case,
debug scripts)
Added scripts/SCRIPTS.md — registry of all scripts with purpose,
status, and what superseded them. CLAUDE.md updated with rule:
any script change requires SCRIPTS.md update.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
skills/decision/references/block-schema.md was a stale copy that
diverged from docs/block-schema.md. Now a symlink — single source of truth.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CLAUDE.md: clarify vault was deleted, knowledge is in docs/+training/
- Remove import-final-decisions.py (migration completed, all decisions in DB)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Assets live in ezer-mishpati/paperclip-config (cloned at ~/.paperclip).
Deploy via: ~/.paperclip/hebrew/apply-hebrew.sh
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CEO agent now sends email via notify.py when awaiting human response
- CEO creates child issues (parentId) instead of flat disconnected issues
- Fix notify.py email address to chaim+paperclip@marcus-law.co.il
- Move Paperclip UI assets (RTL CSS + Hebrew JS) into repo under scripts/
- Add deploy.sh script to push assets to live Paperclip instance
- Fix comment box positioning: newest comment on top, input below it
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New endpoint POST /api/cases/{case_number}/start-workflow creates a
Paperclip issue, wakes the CEO agent via wakeup API, and transitions
case status to "processing". Button appears on case page only when
status is "new" or "documents_ready".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- auto-sync-cases.sh: fix broken directory scan (was looking for
status subdirs that don't exist), fix env var word-splitting bug,
add safe.directory handling and error logging
- cases.py: auto-create Gitea repo on case_create, fix
documents/original → documents/originals naming mismatch
- app.py: add GET /api/cases/{case_number}/git-status endpoint
- web-ui: add SyncIndicator component in case header showing
sync status (synced/pending/no remote) with last commit time
- pyproject.toml: add httpx dependency
- CLAUDE.md: update Paperclip wakeup API docs
- settings page: switch tag input from Select to free-text with datalist
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CEO was ignoring the focused wake reason and doing a full heartbeat
scan of all cases/issues before getting to the actual comment. Added
step 0: check $PAPERCLIP_WAKE_REASON first — if user_commented, skip
directly to comment handling. Don't scan other cases.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CEO was missing get_chair_directions, record_chair_feedback,
list_chair_feedback, and search_case_documents. Without these tools
it couldn't read or update chair directions when processing draft
annotations.
Now the CEO will:
1. Read existing chair_directions via MCP tool
2. Record each draft annotation as chair_feedback
3. Update analysis-and-research.md
4. Post summary for user review before routing to writer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the user writes editing instructions inside a draft DOCX, the CEO
must not just forward them as a checklist. Instead:
1. Read analysis-and-research.md + existing chair_directions
2. Translate draft annotations into methodological structure (syllogism)
3. Update chair_directions with the new analysis
4. Post summary to user and WAIT for approval
5. Only after approval → create issue for writer
This gives the user a chance to verify the CEO understood correctly
before the writer starts working.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Even when the user asks to edit specific paragraphs in an existing
draft, the CEO must first analyze through the methodology: identify
which legal issue the edit serves, build syllogistic structure,
reference specific source documents, and state the review standard.
Without this, the writer gets a technical checklist instead of
methodological guidance.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Agent JWT cannot wake other agents directly (returns "Agent can only
invoke itself"). The correct pattern: create an issue + assign to the
target agent → Paperclip triggers wakeup automatically.
Also documented all correct API routes in HEARTBEAT.md:
- POST /api/issues/{id}/comments (not /issues/)
- POST /api/companies/{company-id}/issues (not /api/issues)
- PATCH /api/issues/{id}
- POST /api/agents/{id}/wakeup (self only, with payload.issueId)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CEO was sending empty issues like "הועבר לכתיבה" without any
methodological content. The writer needs: syllogistic structure per
issue, source document references, claim handling table, chair
directions, style guidelines, and draft file path when available.
Added "תבנית issue לכותב ההחלטה" with all 5 required sections.
Updated comment routing to read drafts word-by-word and use the template.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The agents used /api/agents/{id}/wake (404) with a fallback of INSERT
INTO agent_wakeup_requests. The DB insert creates only the wakeup
record without a heartbeat_run, so the Paperclip dispatcher never
processes it — agents get stuck in queued forever.
Fix:
- All agents: /wake → /wakeup (correct Paperclip API endpoint)
- Remove all DB INSERT fallbacks, replace with warning
- Document the rule in CLAUDE.md: always API, never DB insert
- Save to memory for future conversations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix column name mismatch in paperclip_client.py and app.py: Paperclip's
companies table uses `issue_prefix`, not `identifier`
- Fix _LEGAL_DB_URL to read from POSTGRES_URL env var (used in container)
- Add settings page (/settings) for managing tag → Paperclip company mappings
- Replace "תיק חדש" nav item with "הגדרות" (new case is on home page)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaced Dockerfile-based app with Docker Image app in Coolify.
CI builds and pushes image to registry, Coolify pulls it on deploy.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>