Files
legal-ai/.claude/agents/HEARTBEAT.md
Chaim 6a38789379
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 7s
docs+heartbeat: paperclip quirks + temp-file pattern + self-recovery
Two latent issues surfaced today while watching the case 8174-24
end-to-end run, both worth documenting and engineering around because
they will recur on every future case.

Bug 1 — issue.released flips done→todo
  After an agent successfully PATCHes its issue to "done", Paperclip's
  internal issue.released action reverts the status to "todo" within
  ~30 seconds. This triggers a fresh wakeup of the same agent on a
  task that is already complete.
  Reproduced on CMPA-18 (30/04/26):
      18:14:57  agent PATCH → status: done
      18:15:35  Paperclip   → issue.released → status: todo
      18:15:54  new researcher run started
  The fix at the right altitude (Paperclip itself) is outside our repo.
  Mitigation in HEARTBEAT.md §3 — when an agent boots and finds the
  issue in `todo` while expected outputs (file, DB rows) already exist,
  it must short-circuit: post a "no change" comment, PATCH back to done,
  and exit. Costs ~$0.20 per false wakeup but breaks the loop.

Bug 2 — Bash backtick trap on long comment bodies
  Researcher agent built a curl pipeline like:
      curl ... -d "$(python3 -c "body = '''...
        📁 קובץ מחקר: `/path/to/file.md`
        '''")"
  The backticks around the file path (markdown convention) get
  evaluated by the OUTER bash $(...) as command substitution. Bash
  then tries to exec /path/to/file.md, which is not executable, and
  prints "Permission denied" — a misleading error since the actual
  file ownership is fine. The curl itself succeeded; only the bash
  prelude noised up the log.
  Fix in HEARTBEAT.md §4א: long bodies must go via Write→tempfile
  then `curl -d @file`. Avoids every shell quoting edge case.

Files:
  • docs/paperclip-quirks.md — new. Full writeup of both bugs plus
    two prior known-quirks (CEO auto-block in_progress, INSERT vs
    API for wakeups). Each section: what happens, empirical evidence
    from logs, impact, workaround, status.
  • .claude/agents/HEARTBEAT.md — added the self-recovery section to
    §3 and the temp-file pattern to §4א. The temp-file pattern is the
    canonical answer for any agent posting markdown comments —
    applies to all 7 agents in this skill set.
  • CLAUDE.md — referenced the new doc from the docs index.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 18:23:32 +00:00

10 KiB
Raw Blame History

HEARTBEAT.md — רשימת ביצוע לכל ריצה

שפה — כלל עליון

כל הפלט שלך חייב להיות בעברית בלבד. זה כולל:

  • Comments ב-Paperclip
  • הודעות סטטוס
  • תיאורי שגיאות
  • סיכומים ודיווחים
  • חשיבה פנימית (thinking)

אין יוצאים מן הכלל. גם שמות tools, פקודות, ונתיבי קבצים — ההסבר סביבם בעברית.


הרץ את הרשימה הזו בכל heartbeat.

1. זיהוי וסינון חברה

  • וודא שאתה יודע מי אתה: $PAPERCLIP_AGENT_ID
  • בדוק הקשר: $PAPERCLIP_TASK_ID, $PAPERCLIP_WAKE_REASON
  • זהה את החברה שלך: $PAPERCLIP_COMPANY_ID

⚠️ סינון תיקים לפי חברה — כלל ברזל

אתה אחראי רק על תיקים ששייכים לחברה שלך. הספרה הראשונה של מספר התיק קובעת:

חברה COMPANY_ID סוגי תיקים טווח מספרים
ועדת ערר רישוי ובניה 42a7acd0-30c5-4cbd-ac97-7424f65df294 רישוי ובניה 1xxx
ועדת ערר היטלי השבחה 8639e837-4c9d-47fa-a76b-95788d651896 היטל השבחה + פיצויים ס' 197 8xxx, 9xxx
  • אם $PAPERCLIP_COMPANY_ID = 42a7acd0... → עבוד רק על תיקים שמתחילים ב-1
  • אם $PAPERCLIP_COMPANY_ID = 8639e837... → עבוד רק על תיקים שמתחילים ב-8 או 9
  • לעולם אל תיצור פרויקט, issue, או תוכן לתיק שלא בטווח שלך
  • אם issue שהוקצה לך מכוון לתיק שלא בטווח שלך — סרב בנימוס ודווח ב-comment

2. בדוק תיבת דואר

curl -s -H "Authorization: Bearer $PAPERCLIP_API_KEY" "$PAPERCLIP_API_URL/api/agents/me/inbox-lite"
  • תעדוף: in_progress קודם, אחר כך todo
  • אם PAPERCLIP_TASK_ID מוגדר — תעדף אותו

2b. קרא תגובות אחרונות על ה-issue

לפני שאתה מתחיל לעבוד, בדוק אם יש comments חדשים מחיים:

curl -s -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  "$PAPERCLIP_API_URL/api/issues/{issue-id}/comments" | jq '[.[] | select(.authorUserId != null)] | .[-3:]'
  • אם יש comment מחיים (authorUserId, לא authorAgentId) שנכתב אחרי ה-comment האחרון שלך — קרא אותו בתשומת לב
  • אם ה-comment מכיל הוראות עבודה — עקוב אחריהן
  • אם ה-comment מזכיר קובץ שהועלה — בדוק attachments (ראה 2c)
  • אם ה-comment מבקש להעביר לסוכן אחר — עצור, פרסם comment שמאשר, והעֵר את ה-CEO

2c. בדוק קבצים מצורפים

אם comment מחיים מזכיר קובץ או טיוטה:

PGPASSWORD="paperclip" psql -h 127.0.0.1 -p 54329 -U paperclip -d paperclip -c "
SELECT a.original_filename, a.content_type, a.object_key, a.byte_size
FROM issue_attachments ia
JOIN assets a ON a.id = ia.asset_id
WHERE ia.issue_id = '{issue-id}'
ORDER BY ia.created_at DESC LIMIT 5;"
  • נתיב מלא לקובץ: /home/chaim/.paperclip/instances/default/data/storage/{object_key}
  • קבצי DOCX — קרא אותם עם Read
  • השתמש בתוכן הקובץ כקלט לעבודתך

3. Checkout ועבודה

curl -s -X POST -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  "$PAPERCLIP_API_URL/api/issues/{issue-id}/checkout"
  • עבוד על המשימה לפי ההוראות ב-AGENTS.md שלך
  • השתמש בכלים המשפטיים (legal-ai MCP)

⚠️ self-recovery — issue ב-todo עם תוצרים קיימים

ל-Paperclip יש באג ידוע: לאחר ש-issue מתעדכן ל-done, מנגנון issue.released מחזיר אותו ל-todo תוך כ-30 שניות (תועד ב-docs/paperclip-quirks.md §1). זה גורם ל-wakeup חוזר של אותו סוכן על משימה שכבר בוצעה.

לפני שאתה מתחיל עבודה — בדוק שהמשימה לא בוצעה כבר:

  1. בדוק תוצרים בדיסק: Glob על תיקיות ה-output הצפויות ({case_dir}/documents/research/*.md לחוקר, analysis-and-research.md למנתח, וכו')
  2. בדוק תוצרים ב-DB: דרך MCP — precedent_list, get_claims, extract_appraiser_facts (status=completed)
  3. בדוק comments קודמים על ה-issue — אם הסוכן הקודם פרסם "הושלם בהצלחה" מסוף-מצב

אם הכל קיים ותקין: אל תבצע עבודה כפולה. במקום זאת:

  • פרסם comment קצר: "אין שינוי — כל התוצרים קיימים מהריצה הקודמת (X פריטים ב-DB, קובץ Y בדיסק). סוגר את ה-issue."
  • PATCH /api/issues/{id}done
  • צא נקי

אם משהו חסר/שונה: עבוד על מה שחסר בלבד, לא על הכל מחדש.

4. דיווח — חובה!

לפני שאתה מסיים, תמיד:

4א. פרסם comment על ה-issue

ל-body קצר (<500 תווים, בלי backticks/קוד/נתיבים):

curl -s -X POST -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  "$PAPERCLIP_API_URL/api/issues/{issue-id}/comments" \
  -d '{"body": "סיכום העבודה..."}'

ל-body ארוך / markdown עם נתיבים בbacktick / קוד — חובה שתי פעולות נפרדות:

  1. כתוב את ה-JSON לקובץ זמני דרך Write tool (לא דרך bash heredoc):

    Write(file_path="/tmp/comment-{issue-id}.json",
          content=json.dumps({"body": markdown_body}, ensure_ascii=False))
    
  2. אז curl -d @file שקורא את הקובץ ישירות — בלי shell expansion:

    curl -s -X POST -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
      -H "Content-Type: application/json" \
      "$PAPERCLIP_API_URL/api/issues/{issue-id}/comments" \
      -d @/tmp/comment-{issue-id}.json
    

⚠️ למה לא bash heredoc / python3 -c: backticks ב-markdown (`path/to/file`) ייפרשו על ידי bash כ-command substitution גם כשהם בתוך מחרוזת Python. תקבל שגיאת Permission denied מטעה (bash מנסה להריץ את הנתיב כפקודה). הפתרון של temp-file חוסם את כל ה-shell quoting traps. תועד ב-docs/paperclip-quirks.md §2.

4ב. קבע סטטוס — done או blocked

אם המשימה הושלמה בהצלחה (כל המסמכים חולצו, כל הבדיקות עברו, אין חסימות):

curl -s -X PATCH -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  "$PAPERCLIP_API_URL/api/issues/{issue-id}" \
  -d '{"status": "done"}'

אם המשימה נכשלה או חסומה (מסמך לא חולץ, timeout, חוסר מידע, שגיאה שלא ניתנת לפתרון):

curl -s -X PATCH -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  "$PAPERCLIP_API_URL/api/issues/{issue-id}" \
  -d '{"status": "blocked"}'

אסור לסיים issue כ-"done" אם יש כשל שלא טופל. "done" = הכל הושלם בהצלחה. אם משהו נכשל — "blocked".

4ג. העֵר את העוזר המשפטי (CEO) — חובה!

אחרי כל סיום משימה (done או blocked), העֵר את העוזר המשפטי של החברה שלך כדי שיבדוק תוצאות ויחליט על הצעד הבא:

⚠️ בחר CEO לפי חברה:

חברה COMPANY_ID CEO Agent ID
רישוי ובניה (CMP) 42a7acd0-... 752cebdd-6748-4a04-aacd-c7ab0294ef33
היטלי השבחה (CMPA) 8639e837-... cdbfa8bc-3d61-41a4-a2e7-677ec7d34562
# קבע CEO_ID לפי חברה:
if [ "$PAPERCLIP_COMPANY_ID" = "8639e837-4c9d-47fa-a76b-95788d651896" ]; then
  CEO_ID="cdbfa8bc-3d61-41a4-a2e7-677ec7d34562"
else
  CEO_ID="752cebdd-6748-4a04-aacd-c7ab0294ef33"
fi

curl -s -X POST -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  "$PAPERCLIP_API_URL/api/agents/$CEO_ID/wakeup" \
  -d '{"source":"automation","triggerDetail":"system","reason":"סוכן [שמך] סיים משימה [issue-id] בסטטוס [done/blocked]","payload":{"issueId":"[issue-id]","mutation":"agent_completion"}}'

⚠️ כללי ברזל — Paperclip API:

  1. אסור INSERT INTO agent_wakeup_requests — לא יוצר heartbeat_run, הסוכן לא יתעורר לעולם
  2. חובה payload.issueId בכל wakeup — בלי זה הסוכן מתעורר בלי הקשר (בלי תיק, בלי cwd)
  3. agent JWT לא יכול להעיר סוכנים אחרים — רק את עצמו. כדי להעיר סוכן אחר → צור issue + הקצה אליו (Paperclip מפעיל wakeup אוטומטי)

נתיבי API:

פעולה נתיב
פרסום comment POST /api/issues/{issue-id}/comments
יצירת issue POST /api/companies/{company-id}/issues
עדכון issue PATCH /api/issues/{issue-id}
wakeup עצמי/CEO POST /api/agents/{agent-id}/wakeup (עם payload!)

5. התראת מייל — כשנדרשת תשובה אנושית

כשהתוצאה דורשת החלטה או תשובה של חיים, שלח מייל:

python3 /home/chaim/legal-ai/scripts/notify.py \
  "נדרשת תשובתך — [תיאור קצר]" \
  "תוכן ההודעה עם סיכום מה נדרש"

מתי לשלוח — תמיד:

  • סיום כל משימה — עם סיכום קצר של מה בוצע
  • בקשה לקביעת תוצאה (דחייה/קבלה/חלקית)
  • בקשה לאישור כיוון נימוק
  • דוח QA שנכשל (צריך החלטה על תיקונים)
  • החלטה מוכנה לביקורת דפנה
  • כל מצב שדורש פעולה אנושית ולא יכול להתקדם לבד
  • שגיאה שלא ניתן לפתור ללא התערבות

מתי לא לשלוח:

  • עדכוני סטטוס ביניים (רק בסיום)
  • שגיאות טכניות שאפשר לפתור לבד

6. Release

curl -s -X POST -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  "$PAPERCLIP_API_URL/api/issues/{issue-id}/release"