Inline # comments in gitignore are not supported — they were silently breaking three patterns (data/checkpoints/, data/adapter-migration-state.json, .claude/agents/.generated/). Moved comments to their own lines and added missing entries for runtime dirs (data/audit/, data/logs/, etc.) and temp files (.interaction_tmp.json, .design-build/, .taskmaster bak files). Also tracks previously untracked legitimate files: scripts, tests, docs, skills references, .env.example, taskmaster templates. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
10 KiB
Hooks: Case Status Webhooks Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: כאשר status של תיק משתנה ב-legal-ai (e.g. qa_failed, exported), ה-plugin מקבל webhook, מעדכן את ה-issue ב-Paperclip, ומעיר את ה-CEO במקרה הצורך.
Architecture: Legal-ai REST API קורא pc_request("POST", "/api/plugins/marcusgroup.legal-ai/webhooks/case-status", ...) אחרי כל שינוי status. ה-plugin מטפל ב-onWebhook() ומגיב: מוסיף תגובה לissue, מעיר CEO אם QA נכשל.
Tech Stack: TypeScript (plugin-legal-ai), Python/FastAPI (legal-ai web), @paperclipai/plugin-sdk@2026.325.0, httpx (Python), pc_request helper.
File Map
| Action | File |
|---|---|
| Modify | plugin-legal-ai/src/worker.ts — add onWebhook() to definePlugin({}) |
| Modify | plugin-legal-ai/plugin.json — add "webhooks.receive" capability |
| Modify | plugin-legal-ai/src/manifest.ts — add webhook capability |
| Modify | legal-ai/web/app.py — emit webhook after PUT /api/cases/{case_number} |
| Modify | legal-ai/web/paperclip_api.py — add emit_webhook() helper |
Task 1: Add emit_webhook helper ב-Python
Files:
-
Modify:
legal-ai/web/paperclip_api.py -
Step 1: קרא את הקובץ הקיים
head -90 /home/chaim/legal-ai/web/paperclip_api.py
- Step 2: הוסף את ה-helper בסוף הקובץ
פתח /home/chaim/legal-ai/web/paperclip_api.py והוסף אחרי הפונקציה pc_request:
async def emit_case_status_webhook(
case_number: str,
old_status: str,
new_status: str,
company_id: str | None = None,
run_id: str | None = None,
) -> None:
"""Notify the Paperclip plugin that a case status changed.
Fire-and-forget: logs errors but never raises, so callers aren't blocked.
"""
try:
await pc_request(
"POST",
"/api/plugins/marcusgroup.legal-ai/webhooks/case-status",
json={
"caseNumber": case_number,
"oldStatus": old_status,
"newStatus": new_status,
"companyId": company_id,
"timestamp": datetime.utcnow().isoformat() + "Z",
},
run_id=run_id,
timeout=5.0,
)
except Exception as exc:
logger.warning("emit_case_status_webhook failed: %s", exc)
הערה:
datetimeו-loggerכבר מיובאים ב-app.py. בדוק שהם מיובאים גם ב-paperclip_api.py— אם לא, הוסףfrom datetime import datetimeו-import logging; logger = logging.getLogger(__name__)בראש הקובץ.
- Step 3: Commit
cd /home/chaim/legal-ai
git add web/paperclip_api.py
git commit -m "feat: add emit_case_status_webhook helper"
Task 2: צרף webhook לendpoint PUT /api/cases/{case_number}
Files:
-
Modify:
legal-ai/web/app.py -
Step 1: מצא את ה-endpoint
grep -n "PUT\|case_number\|update_case" /home/chaim/legal-ai/web/app.py | head -30
- Step 2: קרא את הenable endpoint המלא
זהה את הסקציה המלאה של ה-endpoint ואת הייבוא הקיים.
- Step 3: הוסף import ל-emit_webhook
בראש app.py, בסקציית ה-imports מ-paperclip_api:
from .paperclip_api import pc_request, emit_case_status_webhook
- Step 4: הוסף webhook emit בתוך הendpoint
אחרי שהקוד מעדכן את ה-case (לפני ה-return), הוסף:
# Notify plugin about status change (fire-and-forget)
if updates.get("status") and old_status != updates["status"]:
background_tasks.add_task(
emit_case_status_webhook,
case_number=case_number,
old_status=old_status,
new_status=updates["status"],
company_id=str(case.get("company_id")),
)
אם ה-endpoint כבר מקבל
background_tasks: BackgroundTasks— השתמש בו. אם לא, הוסףbackground_tasks: BackgroundTasksלחתימת הפונקציה. הוסףfrom fastapi import BackgroundTasksל-imports.
- Step 5: שמור את ה-
old_statusלפני ה-update
בתחילת ה-endpoint handler, לפני קריאת ה-DB update:
old_status = (await db.get_case(case_number) or {}).get("status", "")
- Step 6: בדיקה בסיסית — שלח PUT ידני
curl -s -X PUT https://legal-ai.nautilus.marcusgroup.org/api/cases/1130-25 \
-H "Content-Type: application/json" \
-d '{"status": "in_progress"}' | jq .status
בדוק ב-Paperclip logs שהwebhook נשלח (עדיין לא מטופל בצד ה-plugin):
pm2 logs paperclip --lines 20
- Step 7: Commit
cd /home/chaim/legal-ai
git add web/app.py
git commit -m "feat: emit case-status webhook on PUT /api/cases/:case"
Task 3: הוסף onWebhook() ל-plugin
Files:
-
Modify:
plugin-legal-ai/src/worker.ts -
Step 1: קרא את
definePlugin({})הקיים
grep -n "definePlugin\|onWebhook\|onHealth\|onShutdown" /home/chaim/plugin-legal-ai/src/worker.ts
- Step 2: הוסף את
onWebhookhandler
בתוך הobject שמועבר ל-definePlugin({}), אחרי setup(ctx):
onWebhook: async (input) => {
const { endpointKey, payload, companyId } = input as {
endpointKey: string;
payload: {
caseNumber: string;
oldStatus: string;
newStatus: string;
companyId: string;
timestamp: string;
};
companyId: string;
};
if (endpointKey !== "case-status") return;
const { caseNumber, oldStatus, newStatus } = payload;
ctx.logger.info(`Webhook: ${caseNumber} ${oldStatus} → ${newStatus}`);
// Find the Paperclip issue linked to this case
const stateKey = `case:${caseNumber}`;
const issueId = await ctx.state.get({ companyId }, stateKey);
if (!issueId) {
ctx.logger.warn(`No issue found for case ${caseNumber}`);
return;
}
const statusLabels: Record<string, string> = {
in_progress: "🔄 בעבודה",
drafted: "✍️ טיוטה מוכנה",
qa_failed: "❌ QA נכשל",
exported: "📄 יוצא ל-DOCX",
reviewed: "✅ נבדק",
final: "🎯 סופי",
};
const label = statusLabels[newStatus] ?? newStatus;
// Post a status comment on the issue
await ctx.issues.createComment({
issueId: issueId as string,
body: `**עדכון סטטוס:** ${label} (היה: ${oldStatus})`,
});
// Wake CEO if QA failed
if (newStatus === "qa_failed") {
const companies = await ctx.companies.list();
const company = companies.find((c) => c.id === companyId);
if (!company) return;
const CEO_IDS: Record<string, string> = {
"42a7acd0-30c5-4cbd-ac97-7424f65df294": "752cebdd-6748-4a04-aacd-c7ab0294ef33",
"8639e837-4c9d-47fa-a76b-95788d651896": "cdbfa8bc-3d61-41a4-a2e7-677ec7d34562",
};
const ceoId = CEO_IDS[companyId];
if (ceoId) {
await ctx.agents.invoke(ceoId, companyId, {
prompt: `תיק ${caseNumber} נכשל בבדיקת QA. עיין בתוצאות QA ותקן את הבעיות.`,
reason: "qa_failed webhook",
});
}
}
},
הערה:
ctxחייב להיות נגיש ב-onWebhook. אםctxמוגדר בתוךsetup()בלבד — הוצא אותו ל-closure חיצוני של ה-plugin object (ראה את הדפוס הקיים ב-worker.ts).
- Step 3: בדק TypeScript
cd /home/chaim/plugin-legal-ai && npx tsc --noEmit
Expected: 0 errors.
- Step 4: Build
cd /home/chaim/plugin-legal-ai && npm run build
Expected: dist/worker.js נוצר ללא שגיאות.
- Step 5: Commit
cd /home/chaim/plugin-legal-ai
git add src/worker.ts
git commit -m "feat: add onWebhook handler for case-status events"
Task 4: הוסף capability ל-plugin.json ול-manifest.ts
Files:
-
Modify:
plugin-legal-ai/plugin.json -
Modify:
plugin-legal-ai/src/manifest.ts -
Step 1: הוסף
"webhooks.receive"ל-capabilities
ב-plugin-legal-ai/plugin.json, בarray "capabilities", הוסף:
"webhooks.receive"
- Step 2: הוסף גם ב-
manifest.ts
grep -n "capabilities\|webhooks" /home/chaim/plugin-legal-ai/src/manifest.ts
הוסף "webhooks.receive" לarray שם.
- Step 3: Re-install plugin
cd /home/chaim/plugin-legal-ai && npm run build
npx paperclipai plugin uninstall marcusgroup.legal-ai \
--api-base http://localhost:3100 --api-key pcapi_legal_install_key_2026
npx paperclipai plugin install /home/chaim/plugin-legal-ai \
--api-base http://localhost:3100 --api-key pcapi_legal_install_key_2026
pm2 restart paperclip
- Step 4: Commit
cd /home/chaim/plugin-legal-ai
git add plugin.json src/manifest.ts
git commit -m "feat: add webhooks.receive capability to plugin manifest"
Task 5: בדיקה end-to-end
- Step 1: Deploy legal-ai
cd /home/chaim/legal-ai
git push origin main
# המתן לבנייה (~2-4 דקות)
- Step 2: שנה סטטוס תיק
curl -s -X PUT https://legal-ai.nautilus.marcusgroup.org/api/cases/1130-25 \
-H "Content-Type: application/json" \
-d '{"status": "qa_failed"}' | jq .status
- Step 3: בדוק שהתגובה הוספה ל-Paperclip issue
# מצא את ה-issue הקשור לתיק 1130-25
pm2 logs paperclip --lines 30 | grep "1130-25\|webhook\|qa_failed"
Expected: תגובה "❌ QA נכשל" הוספה לissue. CEO הועיר.
- Step 4: בדוק שינוי סטטוס שגרתי (לא QA)
curl -s -X PUT https://legal-ai.nautilus.marcusgroup.org/api/cases/1130-25 \
-H "Content-Type: application/json" \
-d '{"status": "drafted"}' | jq .status
Expected: תגובה "✍️ טיוטה מוכנה" בissue. CEO לא הועיר.
אימות סופי
| בדיקה | פקודה | תוצאה מצופה |
|---|---|---|
| QA נכשל → CEO מועיר | PUT status=qa_failed |
תגובה + agent invocation |
| exported → תגובה בלבד | PUT status=exported |
תגובה בלבד |
| שינוי ללא status | PUT title=... |
שום webhook |
| תיק ללא issue | webhook לתיק חדש | לוג warning, ללא crash |