מעביר עומק תפעולי ל-docs/operations-runbook.md חדש כדי לצמצם את ההקשר שנטען אוטומטית בכל סשן. CLAUDE.md נשאר אינדקס דק עם כל הכללים הקריטיים. הועבר ל-runbook: טבלת Nautilus, פירוט Deploy (Coolify/pm2/legal-chat-service), עץ-תיקיות מלא, Paperclip deep-ops (wakeup payload, cross-company sync, webhook flow, scheduled jobs, deepseek_local + hermes curator adapters), Chair-Feedback, TaskMaster מפורט. נשמר inline (קריטי): spec-first protocol, worktree isolation, יעד-העל Style-Acquisition, טבלת מסמכי-ייחוס, עקרונות-כתיבה G11, וכללי-Paperclip הקריטיים בתמצית (wakeup-via-API, helper-not-curl, comment routing). 344→159 שורות; ~4.3k טוקן/סשן נחסכים. כל התוכן נשאר ב-repo ונגיש דרך קישור. Invariants: G2 (אין מסלול מקביל — תוכן הועבר, לא שוכפל), G11 (עקרונות-כתיבה נשמרו inline). תיעוד בלבד, אין נגיעה בקוד. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
204 lines
16 KiB
Markdown
204 lines
16 KiB
Markdown
# Operations Runbook — עוזר משפטי
|
||
|
||
> תוכן תפעולי-עומק שהוצא מ-[`CLAUDE.md`](../CLAUDE.md) כדי לרזות את ההקשר הנטען בכל סשן (TaskMaster #107.1).
|
||
> ה-CLAUDE.md מחזיק את **הכללים הקריטיים בקצרה**; כאן נמצאים הפרטים המלאים, הפקודות, וטבלאות-הייחוס.
|
||
> כשעובדים על Deploy, Paperplip-ops, או adapters — לקרוא את הסעיף הרלוונטי כאן.
|
||
|
||
---
|
||
|
||
## שרת Nautilus (158.178.131.193)
|
||
|
||
| שירות | תפקיד | כתובת |
|
||
|-------|--------|-------|
|
||
| Coolify | ניהול containers | `http://158.178.131.193:8000` |
|
||
| PostgreSQL + pgvector | בסיס נתונים ראשי | `legal-ai-postgres` (`localhost:5433`, user `legal_ai`) |
|
||
| Redis | תור משימות | `legal-ai-redis` |
|
||
| Gitea | מאגר קוד | `gitea.nautilus.marcusgroup.org/ezer-mishpati` |
|
||
| ezer-mishpati-web | ממשק העלאת מסמכים (Docker/Coolify) | `legal-ai.nautilus.marcusgroup.org` |
|
||
| Paperclip | סוכן AI — מריץ Claude Code agents (pm2, מקומי) | `localhost:3100` |
|
||
| legal-chat-service | גשר claude CLI לטאב הצ'אט ב-/training (pm2, loopback) | `127.0.0.1:8770` |
|
||
| Infisical | ניהול סודות | `secret.dev.marcus-law.co.il` |
|
||
|
||
---
|
||
|
||
## ארכיטקטורת Deploy — חובה לקרוא
|
||
|
||
שלושה מודלי-הרצה דרים יחד. ערבוב ביניהם הוא הטעות הנפוצה ביותר.
|
||
|
||
### עוזר משפטי (Legal-AI) — Docker container דרך Coolify
|
||
- UUID: `gyjo0mtw2c42ej3xxvbz8zio` (build_pack: `dockerimage`, **לא** `dockerfile`)
|
||
- שינוי קוד ב-`web/` או `web-ui/` **לא נכנס לתוקף** עד ש:
|
||
1. עושים `git commit` + `git push origin main`
|
||
2. Gitea Actions בונה image → דוחף ל-registry → מפעיל redeploy ב-Coolify (`mcp__coolify__deploy`)
|
||
3. ממתינים ~2-4 דקות לבנייה
|
||
- **אסור** לנסות להריץ uvicorn / `next dev` מקומית — אין סביבת Python על המכונה
|
||
- ה-container מריץ Next.js (`:3000`, חשוף) + FastAPI (`:8000`, פנימי)
|
||
- בדיקה: `curl https://legal-ai.nautilus.marcusgroup.org/api/health`
|
||
- runbook מלא של ה-pipeline: `~/CI-CD-MIGRATION-GUIDE.md`
|
||
|
||
### Paperclip — מקומית דרך pm2
|
||
- פורט: `localhost:3100`, DB: `localhost:54329` (Postgres embedded)
|
||
- שינויי קוד נכנסים לתוקף אחרי `pm2 restart paperclip`
|
||
- **אין צורך ב-Docker או Coolify** (מיגרציה ל-Coolify נוסתה 2026-04-04 והוחזרה 2026-04-08)
|
||
- תרגום/RTL: `~/.paperclip/hebrew/` → `bash ~/.paperclip/hebrew/apply-hebrew.sh && pm2 restart paperclip`
|
||
|
||
### legal-chat-service — מקומית דרך pm2 (מאפריל 2026)
|
||
- פורט: `127.0.0.1:8770` (loopback בלבד)
|
||
- שירות aiohttp קצר שעוטף את `claude` CLI ב-streaming + session continuation, ומשרת את הטאב "שיחה" בדף `/training`. הקונטיינר משדל אליו proxy דרך `host.docker.internal:8770`.
|
||
- קוד: [`mcp-server/src/legal_mcp/chat_service/`](../mcp-server/src/legal_mcp/chat_service/)
|
||
- התקנה: `pm2 start /home/chaim/legal-ai/scripts/legal-chat-service.config.cjs && pm2 save`
|
||
- בריאות: `curl http://127.0.0.1:8770/health` → `{"ok":true,...}`
|
||
- שינויי קוד: `pm2 restart legal-chat-service`
|
||
- **אפס עלות API** — claude CLI משתמש ב-claude.ai subscription של chaim. הנחת היסוד של `claude_session.py` (claude CLI מקומי בלבד) נשמרת.
|
||
- Coolify dependency: ה-Service Definition של legal-ai חייב להכיל `extra_hosts: host.docker.internal:host-gateway` (אחרת ה-proxy יקבל ConnectError).
|
||
|
||
---
|
||
|
||
## מבנה תיקיות
|
||
|
||
```
|
||
/home/chaim/legal-ai/
|
||
├── CLAUDE.md ← אינדקס דק (כללים קריטיים + מצביעים)
|
||
├── docs/operations-runbook.md ← הקובץ הזה (עומק תפעולי)
|
||
├── Dockerfile ← Docker build
|
||
├── docs/ ← תיעוד + לקחים
|
||
│ ├── architecture.md ארכיטקטורה
|
||
│ ├── block-schema.md 12 בלוקים (המסמך החשוב ביותר)
|
||
│ ├── migration-plan.md תוכנית מעבר vault → DB
|
||
│ ├── legal-decision-lessons.md לקחים מ-3 החלטות
|
||
│ └── memory.md הקשר כללי — skills, פרויקטים
|
||
├── skills/ ← כלי עבודה ומדריכים
|
||
│ ├── decision/ מדריך סגנון + references + 12 בלוקים
|
||
│ ├── assistant/ קטלוג מסמכים
|
||
│ ├── docx/ עיצוב DOCX
|
||
│ ├── dafna-decision-template/ export DOCX לפי תבנית Word של דפנה
|
||
│ └── new-company-setup/ blueprint הוספת חברה חדשה
|
||
├── .claude/
|
||
│ └── agents/ ← הוראות סוכנים + HEARTBEAT.md (symlinks ב-Paperclip)
|
||
│ ├── HEARTBEAT.md checklist הפעלה משותף לכל הסוכנים
|
||
│ ├── legal-ceo.md תזמורן + בקרת זרימה
|
||
│ ├── legal-writer.md כתיבת בלוקים בסגנון דפנה
|
||
│ ├── legal-analyst.md ניתוח משפטי + חילוץ טענות
|
||
│ ├── legal-researcher.md חיפוש תקדימים
|
||
│ ├── legal-qa.md 7 שערי איכות
|
||
│ ├── legal-proofreader.md תיקון OCR
|
||
│ ├── legal-exporter.md ייצוא DOCX סופי
|
||
│ └── hermes-curator.md סוכן Hermes לניתוח סגנון post-export
|
||
├── data/
|
||
│ ├── training/ ← 4 החלטות לאימון (DOCX)
|
||
│ ├── exports/ ← טיוטות DOCX מיוצאות
|
||
│ └── cases/{case-number}/ ← תיקי עררים (מבנה שטוח, סטטוס ב-DB)
|
||
├── web/ ← FastAPI backend (Python): 75+ API endpoints
|
||
│ ├── app.py ← API ראשי
|
||
│ ├── paperclip_api.py ← אינטגרציית Paperclip: `pc_request()` + `emit_case_status_webhook()`
|
||
│ ├── paperclip_client.py ← legacy client (ישן — השתמש ב-paperclip_api.py)
|
||
│ └── gitea_client.py ← אינטגרציית Gitea
|
||
├── web-ui/ ← Next.js frontend (TypeScript/React): ממשק המשתמש
|
||
│ └── next.config.ts ← proxy: /api/* → FastAPI :8000
|
||
├── mcp-server/ ← MCP server + services + tools
|
||
├── adapters/ ← Paperclip external adapters
|
||
│ └── deepseek-paperclip-adapter/ ← `deepseek_local` (Hermes-pinned ל-DeepSeek profile)
|
||
└── scripts/ ← סקריפטים וכלי עזר (ראה scripts/SCRIPTS.md)
|
||
└── .archive/ ← סקריפטים שהושלמו (לא להריץ)
|
||
```
|
||
|
||
---
|
||
|
||
## Paperclip — כללי אינטגרציה (פירוט מלא)
|
||
|
||
> הכללים הקריטיים בתמצית נמצאים ב-[`CLAUDE.md`](../CLAUDE.md). כאן הפירוט המלא, הדוגמאות, וה-"למה".
|
||
|
||
### Wakeup API — תמיד דרך API, לעולם לא דרך DB
|
||
- **הנתיב הנכון**: `POST /api/agents/{agent-id}/wakeup` (לא `/wake`!)
|
||
- **⚠️ אסור**: `INSERT INTO agent_wakeup_requests` ישירות — זה יוצר רק רשומה בלי `heartbeat_run`, והסוכן **לא יתעורר לעולם**
|
||
- **⚠️ חובה לשלוח `payload` עם `issueId`** — בלי זה הסוכן מתעורר בלי הקשר (בלי תיק, בלי issue, בלי cwd נכון)
|
||
- דוגמה נכונה:
|
||
```json
|
||
{"source": "automation", "triggerDetail": "system", "reason": "...",
|
||
"payload": {"issueId": "...", "mutation": "comment", "commentId": "..."}}
|
||
```
|
||
- **Board API Key**: שמור ב-DB (`board_api_keys`), auth: `Authorization: Bearer pbk_...`
|
||
|
||
### ניתוב comments דרך CEO
|
||
- כשמשתמש כותב תגובה על issue ב-Paperclip, הפלאגין (`plugin-legal-ai`) מעיר את ה-CEO דרך `ctx.agents.invoke()`
|
||
- ה-CEO קורא את ה-comment, מחליט על ניתוב, ויוצר issue לסוכן המתאים
|
||
- כל הסוכנים חייבים לקרוא comments אחרונים לפני שהם מתחילים לעבוד (HEARTBEAT שלבים 2b-2c)
|
||
|
||
### קריאות API — תמיד דרך helper, לעולם לא `curl` ישיר
|
||
- **bash (סוכנים):** `~/legal-ai/scripts/pc.sh <METHOD> <PATH> [BODY_JSON]` — מוסיף Authorization, X-Paperclip-Run-Id, Content-Type, base URL. ראה `HEARTBEAT.md §0`.
|
||
- **Python (FastAPI):** `from web.paperclip_api import pc_request; await pc_request("POST", "/api/...", json={...})` — שימוש ב-board API key.
|
||
- **אסור** `curl ... $PAPERCLIP_API_URL` ישיר ב-bash; **אסור** `httpx.AsyncClient` ישיר ל-Paperclip ב-Python.
|
||
- **למה:** ה-skill הרשמי דורש `X-Paperclip-Run-Id` בכל קריאה משנה issue. אצלנו ה-audit trail עבד ממילא דרך JWT claims (`runId: runIdHeader || claims.run_id`), אבל ה-helper מבטיח עקביות + תאימות ל-board API keys (long-lived) שלא נושאות JWT claims.
|
||
|
||
### Cross-company agent sync — אחרי כל שינוי הגדרות
|
||
- יש 14 סוכנים = 7 × 2 חברות (CMP=1xxx, CMPA=8xxx). Paperclip מחייב `agents.company_id NOT NULL` — אין shared agents.
|
||
- **Master = CMP (1xxx)**, **Mirror = CMPA (8xxx)**.
|
||
- אחרי כל שינוי ב-`adapter_config`, `runtime_config`, `budget_monthly_cents`, או skills של סוכן ב-master (UI, SQL, או API), **חובה להריץ:**
|
||
```bash
|
||
PAPERCLIP_BOARD_API_KEY=$(...infisical...) \
|
||
python ~/legal-ai/scripts/sync_agents_across_companies.py --verify # לבדיקה
|
||
PAPERCLIP_BOARD_API_KEY=$(...) \
|
||
python ~/legal-ai/scripts/sync_agents_across_companies.py --apply # לסנכרן
|
||
```
|
||
- הסקריפט מסנן local skills שלא קיימים ב-CMPA (מציג אזהרה), משתמש ב-API (לא DB ישיר), יוצר revisions, idempotent.
|
||
- שאלות ה-skill הרשמי של Paperclip — `paperclip` skill תחת `paperclipai/paperclip`.
|
||
|
||
### Webhook יוצא — עדכון סטטוס תיק לפלאגין
|
||
כשסטטוס תיק משתנה דרך `PUT /api/cases/{case_number}`, הבקאנד שולח webhook אסינכרוני לפלאגין:
|
||
|
||
```
|
||
PUT /api/cases/{case_number} → emit_case_status_webhook() [BackgroundTask]
|
||
→ POST /api/plugins/marcusgroup.legal-ai/webhooks/case-status
|
||
→ plugin-legal-ai/onWebhook()
|
||
→ comment בעברית על issue + CEO wakeup (כשסטטוס = qa_failed)
|
||
```
|
||
|
||
- הקוד ב-`web/paperclip_api.py` (`emit_case_status_webhook`), fire-and-forget, timeout 5s
|
||
- הפלאגין שומר idempotency key ב-state עם TTL 5 דקות למניעת spam על retry
|
||
- `GET /api/cases/stale?days=N` — תיקים שלא עודכנו N ימים; מוחרגים: `new`, `final`, `exported`
|
||
- `GET /api/chair-feedback/weekly-summary` — סיכום פידבק YU"R לשבוע האחרון
|
||
|
||
### Scheduled Jobs (plugin-legal-ai)
|
||
| Job | לוח זמנים | מה עושה |
|
||
|-----|-----------|---------|
|
||
| `stale-case-reminder` | יומי 08:00 | שולח comment אזהרה על תיקים תקועים >3 ימים |
|
||
| `weekly-feedback-analysis` | ראשון 19:00 | מעיר CEO לניתוח פידבק YU"R ועדכון `docs/legal-decision-lessons.md` |
|
||
| `sync-case-status` | כל 30 דק' | מסנכרן סטטוסי תיקים בין legal-ai ל-Paperclip |
|
||
|
||
CEO שמתעורר מ-`weekly-feedback-job` כותב לקובץ בלבד — **אין לו issueId, אל תנסה לפרסם comment או לסגור issue**.
|
||
|
||
### External adapters — `deepseek_local`
|
||
- מיקום ה-package: [`adapters/deepseek-paperclip-adapter/`](../adapters/deepseek-paperclip-adapter/) (לא ב-`node_modules`).
|
||
- רישום ב-Paperclip: רשומה ב-`~/.paperclip/adapter-plugins.json` (נטען אוטומטית ב-startup דרך `buildExternalAdapters`). אין צורך בעריכת `node_modules`.
|
||
- **מה ה-adapter עושה**: spawnל-`hermes chat` עם `HERMES_HOME=/home/chaim/.hermes/profiles/deepseek` כך שה-CLI טוען את `config.yaml` (`base_url=https://api.deepseek.com/v1`, `provider=custom`, `key_env=DEEPSEEK_API_KEY`) ואת `.env` (שמכיל את ה-key).
|
||
- **מודלים זמינים** (lookup ב-DeepSeek `/v1/models`): `deepseek-v4-pro` (default), `deepseek-v4-flash`. יופיעו כדרופ-דאון ב-UI.
|
||
- **התקנה מחדש / עדכון**: `curl -X POST -H "Authorization: Bearer pcapi_legal_install_key_2026" -H "Content-Type: application/json" -d '{"packageName":"/home/chaim/legal-ai/adapters/deepseek-paperclip-adapter","isLocalPath":true}' http://localhost:3100/api/adapters/install`. לעדכון hot — `POST /api/adapters/deepseek_local/reload`.
|
||
- **⚠ Cross-company sync**: `sync_agents_across_companies.py` **מדלג** על סוכנים עם `adapter_type` שונה בין CMP ל-CMPA. כשעוברים סוכן ל-`deepseek_local` חובה להחיל ידנית בשתי החברות לפני sync.
|
||
- **תוספת adapters עתידיים** (OpenAI ישיר, Anthropic ישיר, וכו'): אותו דפוס. ה-package הראשי חייב לייצא `createServerAdapter()` שמחזיר `{ type, label, models, agentConfigurationDoc, execute, testEnvironment, sessionCodec, listSkills, syncSkills, ... }`. ראה את [`adapters/deepseek-paperclip-adapter/dist/index.js`](../adapters/deepseek-paperclip-adapter/dist/index.js) כתבנית.
|
||
|
||
### External adapters — Hermes Curator (`curator-cmp` / `curator-cmpa`)
|
||
- פרופילי Hermes נפרדים לסוכן `hermes-curator` — מנתח החלטות סופיות ומציע עדכוני SKILL.md/lessons.md
|
||
- מיקום: `~/.hermes/profiles/curator-cmp/` + `~/.hermes/profiles/curator-cmpa/`
|
||
- מופעל אחרי export סופי; אינו מעדכן קבצים ישירות
|
||
- **תהליך אישור הצעות:** הצעות ה-curator מגיעות כ-comment ב-Paperclip → חיים בוחן ומאשר ידנית → commits ל-`SKILL.md` ו-`docs/legal-decision-lessons.md`
|
||
|
||
---
|
||
|
||
## הערות יו"ר (Chair Feedback)
|
||
|
||
מנגנון לתיעוד הערות דפנה על טיוטות:
|
||
- **DB**: טבלת `chair_feedback` (case_id, block_id, feedback_text, category, lesson_extracted)
|
||
- **API**: `GET/POST /api/feedback`, `PATCH /api/feedback/{id}/resolve`
|
||
- **MCP tools**: `record_chair_feedback`, `list_chair_feedback`
|
||
- **UI**: דף ניהול ב-`/feedback` (ב-Next.js)
|
||
- **קטגוריות**: missing_content, wrong_tone, wrong_structure, factual_error, style, other
|
||
|
||
---
|
||
|
||
## ניהול משימות — TaskMaster AI (פירוט)
|
||
|
||
- קובץ המשימות הקנוני: `~/legal-ai/.taskmaster/tasks/tasks.json` (יחסי ל-project root, **לא** `~/.taskmaster/tasks/tasks.json`). מכיל את כל ה-tags של legal-ai (`master`, `legal-ai`).
|
||
- פקודות עיקריות: `get_tasks`, `next_task`, `add_task`, `update_task`, `expand_task`
|
||
- לפני התחלת עבודה → `next_task`; אחרי סיום → `update_task` עם status=done; משימה מורכבת → `expand_task`
|
||
- **⚠️ מלכוד cwd ב-CLI:** הדגל `--tag` בוחר קבוצה לוגית *בתוך* הקובץ — הוא **לא** בוחר לאיזה `tasks.json` לכתוב. ה-CLI מאתר את הקובץ לפי ה-cwd. תמיד `cd ~/legal-ai` לפני `task-master add-task` או כל פקודה משנה, ואז אמת ב-MCP `get_tasks`. כשלא בטוחים — לערוך את `~/legal-ai/.taskmaster/tasks/tasks.json` ישירות.
|