Skip to content

Architecture decisions

This is the decision log Evarness grew up with: one record per non-obvious or trade-off-heavy decision, with its context, the choice, the alternatives rejected and the consequences, as they were understood at the time.

Read it with three things in mind.

  • A record is history, not a description of the current system. It is not edited when the code changes. The current system is described in Architecture and the pages under docs/architecture/. When a record and the code disagree, the code is current and the record explains how it got there; a superseding record says so in its status line.
  • They predate the rename. Until 0.2.0 the project was IRIS, and the records say IRIS, iris_harness, IRIS_* and ~/.iris. Read evarness, EVARNESS_* and ~/.evarness.
  • Some decisions concern code that is not in this repository. The finance, calendar, file-manager, planner and coding-agent domains live in a private tree. Their records are kept here because the harness decisions reference them; the Where column says private tree.

Status pass, 2026-10-18. Every record cited by the code whose named files no longer existed, and every Proposed record, was checked against the code. Where something changed, a dated Status pass line sits under the record's own status and the Where column below says where the code lives now, or that it is superseded, private, implemented or not implemented. A record without that line was not re-checked and reads as written.

Records numbered 0001 to 0134 were written between May and October 2026. Thirteen of them (0078 to 0086, 0092, 0097, 0101 to 0103) were sections of the project decisions log rather than standalone files and were extracted on 2026-10-18; each says so under its title. Two records share the number 0123; both are kept. Numbers with no record were never written.

# Title Status Where Cited by code
0001 Singular IRIS agent, skill packs only — no sub-agents Accepted
0002 Privacy-aware Tier 3 — local vs cloud resolved by per-category sensitivity Accepted yes
0003 OAuth tokens in the macOS Keychain via keyring; no custom vault Accepted kernel/governance/vault/credentials.py yes
0004 Reuse the existing wiki/knowledge subsystem as the cross-domain correlation engi Superseded
0005 Task vocabulary + soft migration of the legacy reminders module Accepted evarness/services/tasks/ yes
0006 Finance ingestion via PDF-from-email + manual drop; no Plaid/scraping in core Accepted yes
0007 Multi-currency model — currency-required, group-by-currency aggregation, no impl Accepted yes
0008 R2/R3 split for calendar writes — private events auto, attendee events prompt Accepted
0009 No sandboxing for community skills — explicit trust model + governance enforceme Accepted yes
0010 Entity extractor — tighten regex + hint validation, not rewrite Accepted memory/knowledge/entity_extractor.py yes
0011 Keychain credentials module — implementation shape Accepted
0012 Manifest schema extension — implementation shape Accepted yes
0013 Event bus promotion — implementation shape Accepted foundation/eventbus/ yes
0014 Tasks subsystem — implementation shape Accepted evarness/services/tasks/ yes
0015 PDF unlock helper — implementation shape Accepted private tree
0016 Email accounts registry — implementation shape and DB location Accepted yes
0017 Email classification — dynamic, hierarchical, self-learning categories Accepted yes
0018 iris email bootstrap-categories CLI — implementation shape Accepted evarness_personal/plugins/email_workflows/cli.py, discovery.py yes
0019 categories data model + iris email accept-categories CLI — implementation sh Accepted evarness_personal/email/category_store.py yes
0020 Drift correction — user-driven corrections for systematic LLM naming errors Accepted yes
0021 email-triage skill — implementation shape Superseded by ADR-0022 yes
0022 Resource-aware triage — pure-kNN per email, on-demand LLM batch review Accepted yes
0023 kNN-gate measurement + holdout-labeling tools Accepted yes
0024 Self-learning substrate — Phase 1 scope Accepted yes
0025 email → wiki ingestion shape Accepted email_workflows/wiki_ingestion.py and evarness/memory/knowledge/event_subscribers.py yes
0026 email-search FTS shape Accepted yes
0027 iris task + iris goal CLI — implementation shape Accepted
0028 email-followup skill — implementation shape Accepted
0029 Morning brief Phase 2 integration — implementation shape Accepted
0030 Delivery-only Reminder primitive + channel routing — implementation shape Accepted
0031 Finance data layer — schema, models, and hybrid institution registry Accepted
0032 Pluggable secret store — keyring default, encrypted file vault optional Accepted yes
0033 Statement extraction — Tier-3 LOCAL into a strict schema, injectable extractor Accepted
0034 PDF extraction engine — pypdfium2 + pdfplumber, no AGPL; deterministic decoding Accepted
0035 Deterministic numbers — don't let the LLM transcribe digits; read cells + reconc Accepted private tree
0036 Per-document-type extractors — contract notes → trades, CAS → holdings Accepted private tree
0037 iris finance CLI + per-currency net-worth semantics Accepted private tree
0038 Transaction categorization — hybrid rules + embedding kNN + corrections Accepted
0039 Finance Monitor heartbeat + morning-brief integration Accepted private tree yes
0040 Calendar agent foundation — provider abstraction, ICS first, one ICS implementat Accepted
0041 Native Google Calendar provider — OAuth, provider mapping, syncToken delta Accepted private tree
0042 Calendar write governance as a boundary module (not a governor-policy extension) Accepted private tree
0043 Calendar C3 — meeting-prep routine, reconcile-based task/bill mirror, stdlib MCP Accepted private tree yes
0044 Planner agent foundation — deterministic daily-plan synthesis Accepted private tree
0045 Planner P1 — parallel wave execution + a registered planner agent type Accepted evarness/agent/agent_executor.py yes
0046 Planner P2 — grounded LLM plan narrative (brief headline dropped) Accepted
0047 Document RAG foundation — index the user's docs (connector, not owner), cited re Accepted
0048 Obsidian vault connector — front-matter, wikilinks, incremental sync Accepted
0049 RAG grounded cited Q&A + tag scope + MCP exposure Accepted
0050 RAG PDF + image ingestion with opt-in OCR Accepted
0051 FileManager secure foundation — deny-by-default confinement, secret-aware reads, Accepted
0052 FileManager governed mutations — R2/R3 + soft, reversible ops Accepted
0053 FileManager cloud — Google Drive (read-only) + iCloud Drive as a local root Accepted
0054 FileManager advanced security — redaction-on-share + sensitivity-tiered reads + Accepted
0055 System agent — user-facing status + IRIS self-introspection Accepted
0056 FileManager interactive approval — agent requests, human approves destructive op Accepted
0057 RAG Microsoft Word (.docx) ingestion Accepted
0058 FileManager pending-approval TTL — stale destructive requests expire Accepted
0059 Planner brief "today's plan" headline via a synthesis slot Accepted yes
0060 Finance source-of-truth — authority, identity-keyed dedup, bounded agent reasoni Accepted
0061 Finance document storage & retention policy Accepted private tree yes
0062 — FileManager as custodian: the File Catalog + custody API (FMX0) Accepted yes
0063 — Finance as the first FileManager custody client (FMX1) Accepted yes
0064 — FileManager media + iCloud Drive indexer (FMX2) Accepted yes
0065 — FileManager Apple Photos library indexer (FMX3) Accepted yes
0066 — RAG documents in the catalog; custody scope for other writers (FMX4) Accepted yes
0067 — FileManager never deletes files it doesn't own (purge tier guard) Accepted yes
0068 — Curator-driven tier-escalation judge (model cascade) Accepted yes
0069 System Health — a harness capability with local-on / network-opt-in probing Accepted evarness/services/health/, sdk/health.py, harness_api/health_routes.py yes
0070 Sandbox replay-eval harness for learning experiments Accepted runtime/self_learning_loop.py, tools/sandbox/ yes
0071 Semantic email retrieval + dues-from-notification extraction Accepted evarness_personal/email/semantic_index.py, agent_tools.py yes
0072 Judge-gated, optional feedback & clarify loop Accepted yes
0073 Pending actions — background jobs surface actionable blockers as tasks, with an Accepted services/tasks/pending_actions.py, runtime/action_center.py, harness_api/action_center_routes.py yes
0074 Per-agent console — an ops dashboard per registered agent Accepted agent/agent_metadata.py, runtime/agent_console.py, harness_api/agent_routes.py yes
0075 Calendar as the single write authority (events, invites, appointments, reminders Accepted private tree yes
0076 In-chat approval for consequential actions Accepted yes
0077 Converge on one governed agentic loop — tools as universal actionable items Accepted yes
0078 Generic surface-feedback + suppression spine Accepted (PRD log) services/learning/suppression.py, harness_api/session_routes.py, runtime/react_tools.py yes
0079 Window-aware conversation auto-compaction Accepted (PRD log) yes
0081 Context-health surface (one view of context management) Accepted (PRD log) agent/context_health.py, runtime/session_memory.py, cli/context_health.py yes
0082 Learn before you forget (mine the compaction-archived span) Accepted (PRD log) yes
0083 Learning experiment console (hot-toggle, no restart) Accepted (PRD log) yes
0084 Act on context-health (on-demand compaction) Accepted (PRD log) yes
0085 Measure the memory garbage-in / garbage-out guarantees Accepted (PRD log) yes
0086 Agent self-management tools (act on your own brain) Accepted (PRD log) yes
0092 Portfolio answered locally — kill the web-search name leak Accepted (PRD log)
0097 Portfolio vs market — live index context, not a fake benchmark Accepted (PRD log) yes
0101 Apple Calendar read-back — IRIS can finally see your schedule Accepted (PRD log) private tree yes
0102 Personal-finance questions never touch the web — dues intercept + research guard Accepted (PRD log) yes
0103 Action requests escalate to a capable model (generic, not finance-specific) Accepted (PRD log) yes
0105 User-fact store coherence — single write-seam + reconcile doctor, no DB merge Accepted yes
0106 Session-owned continuations — every pending question has an owner Accepted yes
0107 The PostStep evaluator does not run on the streaming loop Accepted yes
0108 The approval queue, connected — and a channel for the web Accepted yes
0109 The layered tree — src/iris_harness as the harness's building blocks Accepted
0110 Tool effects and loop guidance are declared in the manifest; the loop mechanics Accepted yes
0111 The planner engages for cross-agent or parallel work, and hands results downstre Accepted yes
0112 Reminder text is summarised, dates are resolved on the user's clock, a clarifyin Accepted
0113 The finance agent forms the user's accounts and card due cycles from the evidenc Accepted yes
0114 Memory is what the owner confirmed, and context is what the prompt actually carr Accepted yes
0115 Memory is a graph of claims, and its engine (memris) knows no vocabulary Accepted yes
0116 The health watch repairs what it can, then asks the owner — and remembers Accepted yes
0117 Paired devices hold their own tokens; the shared secret is for services Accepted yes
0118 A destructive tool call is approved by code, per call, through the approval queu Accepted (implemented) kernel/governance/plugins/destructive_approval.py, plugin_host/manifest.py yes
0119 Removing something from memory is reversible, and it reaches the agent Accepted (implemented) memory/removal.py, memris/graph.py, harness_api/memory_routes.py yes
0120 Settings the app changes live in one store on the data volume Accepted yes
0121 Finance reads trusted mail in full and answers card questions from records Accepted yes
0122 The loop delivers, or it is not proven Accepted (implemented) services/routines/seeded.py, foundation/clock.py, config/heartbeats.yaml yes
0123 Apple Foundation Models as a local model provider Proposed (not implemented)
0123 Models are chosen by capability, not by tier size Proposed (not implemented)
0125 Owner-PII masking across every guard Accepted yes
0126 The public tree carries no owner and no deployment Accepted
0127 A turn the system opens, and the first-chat welcome Accepted yes
0128 No bundled trace UI: OTLP to the user's backend Accepted yes
0129 HarnessServices field freeze + a pinning test Accepted
0130 Capability catalogue stays closed for 0.x Accepted
0131 Canonical store + rebuildable projection is a standing rule, not a one-off fix Accepted
0132 A durable PRE_TOOL_USE intent record for high-risk/destructive actions Accepted
0133 A party field on PluginManifest, distinct from the existing trust field Accepted
0134 PluginManifest.party defaults to untrusted Accepted yes