Edita PA Runbook
Edita PA Runbook
TLDR
- Edita = Alem's AI Personal Assistant. Daemon
com.john.edita-loop(LaunchAgent), script~/system/agents/pa/edita-loop.js. Reports to John, who reports to Alem. - Runs email triage every 5 min on
info@alai.no(Migadu). Classifies ARCHIVE / REPLY_TEMPLATE / ESCALATE, writes drafts, never auto-sends. AUTO_REPLY_ENABLED = false— hardcoded CEO kill switch (order 2026-03-07). Drafts only land in~/system/intake/drafts/; nothing goes out without a human/John send.- Calendar tick and memory-consolidation tick exist in the loop but are stub code ("Faza 3") — not yet active. Only email triage (Faza 1) and the incoming-message handler (Faza 2, event-driven Slack/Telegram) run for real.
- Check it's alive:
launchctl list | grep com.john.edita-loopandcat ~/system/logs/edita-loop-heartbeat.json. - Restart:
launchctl kickstart -k gui/$(id -u)/com.john.edita-loop.
Identity
| Field | Value |
|---|---|
| Name | Edita |
| Role | Personal Assistant, ALAI Holding AS |
| Boss | Alem Basic (CEO, alem@alai.no) |
| Manager | John (AI Director) |
| Primary mailbox | info@alai.no (Migadu) |
| System prompt | ~/system/agents/pa/edita-system-prompt.md |
Language: mirrors the user (Bosnian/English/Norwegian mix OK). Tone: direct, warm, professional, max 3 sentences for routine replies. Edita never says "I can't" — she escalates to John instead.
What Edita does
- Triages inbound email: ARCHIVE / REPLY_TEMPLATE / ESCALATE
- Answers Telegram/Slack messages from Alem
- Creates and updates MC tasks
- Checks calendar, reminds about meetings (stub — not active yet)
- Writes draft email replies (never sends automatically)
- Consolidates memory/session context (stub, delegated to
edita-memory-writer.js) - Coordinates and escalates — does not deploy, does not build, does not commit code
What Edita does NOT do
- Send email automatically without passing the Gate 3 kill switch
- Commit code or deploy services
- Make business decisions without confirmation
- Touch financial systems directly
Escalation rules (always → John → Alem)
- VIP sender (see
~/system/agents/pa/memory/contacts-vip.json) - Money/legal keywords: ugovor, faktura, ponuda, legal, NDA, payment
- New/unknown client contact
- Classifier confidence < 0.6
Architecture — the loop
Script: ~/system/agents/pa/edita-loop.js (extends daemon-base.js — signal handling, heartbeat, circuit breaker).
masterTick()
A. emailTriageTick() — every 5 min [ACTIVE]
B. calendarTick() — every 15 min [STUB — Faza 3, not active]
C. memoryConsolidationTick() — every 30 min [STUB — Faza 3, delegated to edita-memory-writer.js]
D. incomingMessageHandler() — event-driven [ACTIVE — Slack/Telegram, Faza 2]
validationTick() — every 6h, always active (incl. dry-run)
Email triage flow (emailTriageTick):
- Pull unclassified mail for
info@alai.nofrom~/system/databases/email-inbox.db. - Classify via Ollama (
TRIAGE_MODEL = llama3.1:8b,OLLAMA_HOSTdefaulthttp://localhost:11434). - Write-back classification even in dry-run, so items aren't re-examined every tick.
- If reply warranted: build draft, write to
~/system/intake/drafts/draft-<ts>-<subject>.md. - Gate 3 check:
autoReplyEnabled = config.auto_reply_enabled || AUTO_REPLY_ENABLED(AUTO_REPLY_ENABLEDis hardcodedfalsein code) — if false, hold and logGATE3_HOLD, notify John. No send happens.
Key config/paths
| Const | Path |
|---|---|
INTAKE_CONFIG |
~/system/config/intake-config.json |
DRAFTS_DIR |
~/system/intake/drafts/ |
DECISIONS_LOG |
~/system/logs/edita-decisions.jsonl |
HEARTBEAT_FILE |
~/system/logs/edita-loop-heartbeat.json |
SYSTEM_PROMPT_FILE |
~/system/agents/pa/edita-system-prompt.md |
EMAIL_INBOX_DB |
~/system/databases/email-inbox.db |
VIP_CONTACTS |
~/system/agents/pa/memory/contacts-vip.json |
Run modes
node ~/system/agents/pa/edita-loop.js # live (LaunchAgent default)
node ~/system/agents/pa/edita-loop.js --dry-run # Faza 1: logs decisions only, no drafts sent
node ~/system/agents/pa/edita-loop.js --allow-archive # next safe step after dry-run: allows ARCHIVE action, still no sends
Operations
# Status
launchctl list | grep com.john.edita-loop
cat ~/system/logs/edita-loop-heartbeat.json
# Restart
launchctl kickstart -k gui/$(id -u)/com.john.edita-loop
# Recent decisions
tail -50 ~/system/logs/edita-decisions.jsonl
# Pending drafts (never auto-sent — review before send)
ls -la ~/system/intake/drafts/
Plist: ~/Library/LaunchAgents/com.john.edita-loop.plist.
Troubleshooting
Edita not triaging new mail
- Confirm daemon is running:
launchctl list | grep com.john.edita-loop(should show a PID, not-). - Check heartbeat freshness:
cat ~/system/logs/edita-loop-heartbeat.json— stale timestamp means the tick loop died silently; kickstart it. - Check Ollama circuit breaker:
grep "circuit breaker open" ~/system/logs/edita-loop.log— if tripped, Ollama (localhost:11434) is unreachable; test withcurl -s localhost:11434/api/tags. - Confirm
info@alai.nois actually being scanned — see [[Email System Runbook]] for the account/daemon relationship (separate daemon,email-agent.js, ingests mail intoemail-inbox.db; Edita reads from that same DB, it does not do its own IMAP fetch).
A draft never turned into a sent email
This is expected — AUTO_REPLY_ENABLED = false is a deliberate CEO gate, not a bug. Drafts sit in ~/system/intake/drafts/; John or Alem must review and send manually via the paths in [[Email System Runbook]].
Calendar reminders / auto-memory-consolidation not happening
Expected — both are Faza 3 stub code in edita-loop.js (calendarTick, memoryConsolidationTick are no-ops that just log a debug line). Not a regression; they were never activated.
Related
- [[Email System Runbook]] — the underlying email ingest/audit/send pipeline Edita's triage tick reads from and drafts against.
~/system/agents/pa/edita-memory-writer.js— standalone memory consolidation script (the real implementation behind the Faza 3 stub).