******** ** **
/**///// **** ***** /**
/** **//** **///** ***** ******* ******
/******* ** //** /** /** **///**//**///**///**/
/**//// **********//******/******* /** /** /**
/** /**//////** /////**/**//// /** /** /**
/********/** /** ***** //****** *** /** //**
//////// // // ///// ////// /// // //
A file-based inter-session messaging system and orchestrator pattern for Claude Code. Multiple Claude Code sessions (an EA, a code agent, a triage worker, etc.) coordinate by dropping markdown files into each other's inboxes. No daemon, no broker, no polling cost when nothing's there.
Part of termpaper.dev, a set of utilities for managing Claude Code from the terminal. Built on top of a-team, which provides the session registry and launcher: EAgent layers the inter-session messaging protocol, an orchestrator-agent pattern, and a shared markdown knowledge base on top.
A starter for building a personal executive assistant out of multiple coordinated Claude Code sessions, communicating via the file system and a shared markdown knowledge base.
Multiple specialized AI sessions, each owning a narrow domain, coordinated through the file system and a shared knowledge base:
- One orchestrator session — the conversational one you type into
- Several worker sessions — narrow, scheduled (e.g., email triage runs on cron) or always-on
- File-based inter-session messaging — drop a markdown file in another session's inbox; receiving session surfaces it automatically via hooks
- Shared knowledge base — markdown wiki (people, companies, themes, decisions), optionally mirrored to a parallel structured graph store like Graphite Atlas
- Reply queue in
task.md— triage maintains a📨 Repliesstrip at the top of each project section with one-click links to the source email thread, rewritten every cycle - Triage log + edit-feedback loop — short rolling log of every triage cycle (
triage-log.md) linked fromtask.md; each cycle diffstask.mdagainst a snapshot to learn from the user's deletions, edits, completions, and annotations (kb/themes/task-learnings.md) - Per-write git commits —
scripts/commit-task.shcommitstask.mdafter every worker write, giving intra-day audit history alongside the daily snapshot cron - Conservative defaults — workers surface uncertainty up to the user instead of acting autonomously
- Context isolation. Each session has its own context window, kept lean by a narrow CLAUDE.md per session. Triage burns tokens reading email — orchestrator stays conversational.
- File system as integration layer. No daemons, no message bus, no DB. Markdown files in folders. Trivially debuggable.
- Hooks for proactive surfacing. Sessions auto-detect new inbox messages via SessionStart + PreToolUse hooks. The agent doesn't need to remember to look.
- Schedules via
/loop, not launchd. Scheduled work stays conversational; you can interrupt or redirect. - Markdown everywhere. Diff-able, grep-able, version-controllable. Cheapest possible interchange format.
.
├── README.md # this file
├── docs/
│ ├── architecture.md # the pattern, end to end
│ ├── components.md # what each piece does
│ ├── extension.md # how to add a new session
│ ├── kb-schema.md # knowledge base conventions
│ ├── messages-protocol.md # inter-session messaging spec
│ └── does-framework.md # one example classification rubric
├── prompts/
│ └── email-triage.md # the triage worker's full prompt (template)
├── scripts/
│ ├── send-message.sh # drop a message into another session's inbox
│ ├── check-inbox.sh # called by hooks — surfaces unread messages
│ ├── wire-inbox.sh # idempotently sets up inbox infra for a new session
│ ├── audit-inboxes.sh # walks agent registry, reports gaps
│ ├── spawn-session.sh # registers + launches a new session, auto-wires inbox
│ ├── list-agents.sh # list registered agents
│ ├── lib-slugify.sh # shared helpers for slug derivation
│ ├── kb-index.sh # regenerate the KB catalog
│ ├── kb-log.sh # append a change entry to the KB feed
│ ├── kb-lint.sh # audit KB for orphans, stale entries, schema violations
│ ├── snapshot.sh # auto-commit data folder daily (safety net)
│ ├── commit-task.sh # commit task.md + worker state after every write (intra-day audit)
│ ├── inbox-notifier.sh # fswatch daemon: macOS banner when a message lands
│ ├── install-inbox-notifier.sh # one-shot installer for the notifier (launchd)
│ └── templates/
│ └── inbox-claude-section.md # boilerplate injected into new agent CLAUDE.mds
├── .claude/
│ ├── CLAUDE.md # orchestrator system prompt (template)
│ ├── settings.json # hooks wiring
│ └── commands/ # slash commands
├── triage/ # worker session: scheduled email triage
│ └── .claude/
│ ├── CLAUDE.md # triage worker system prompt (template)
│ └── settings.json
├── user-commands/ # user-level slash commands (install to ~/.claude/commands/)
│ ├── checkmsg.md # /checkmsg — manual peek of current session's inbox
│ ├── sendmsg.md # /sendmsg <slug> <body> — drop a message in another session
│ └── start-triage-loops.md # /start-triage-loops — arm 3 cron jobs for triage worker
└── .github/workflows/
└── validate-kb.yml # CI: lint the KB on push
flowchart TB
User([User at desk])
subgraph Orchestrator["Orchestrator (conversational)"]
EA[EAgent orchestrator]
end
subgraph Workers["Workers (scheduled / always-on)"]
Triage[Triage worker]
DomainA[Domain session A]
DomainB[Domain session B]
end
subgraph Substrate["Shared substrate (files)"]
KB[(KB markdown wiki)]
Graph[(Optional structured graph store)]
Tasks[(task.md)]
TriageLog[(triage-log.md)]
Digests[(inbox-digests/)]
Inboxes[(messages/inbox/<slug>)]
end
subgraph External["External integrations (via MCP)"]
Email[Email MCP]
Notion[Notion MCP]
Other[Other MCPs]
end
User <--> EA
User -.daily glance.-> Tasks
Tasks -.nav link.-> TriageLog
TriageLog -.per-cycle drilldown.-> Digests
EA --> KB
EA --> Tasks
EA --> Inboxes
Triage --> KB
Triage --> Tasks
Triage --> TriageLog
Triage --> Digests
Triage --> Inboxes
Triage <--> Email
Triage <--> Notion
DomainA --> KB
DomainA <--> Inboxes
DomainB --> KB
DomainB <--> Inboxes
KB <-.optional mirror.-> Graph
Full architecture explainer: docs/architecture.md.
Note
EAgent assumes macOS. Some scripts use open and macOS path conventions; Linux works with minor edits.
- Claude Code installed and authenticated
- An agent registry to manage multiple sessions. EAgent expects a TOML at
~/.config/a-team/agents.toml— the reference implementation is a-team, but any compatible tool works. - bash 4+,
python3,jq,awk,sed(standard on most macs / dev machines) - MCP servers as needed for your integrations — email (e.g., Superhuman), Notion, Graphite Atlas for a parallel graph store, etc.
Tip
Keep the repo (code) and the data folder (task.md, KB, messages) separate. The repo is shareable; the data is personal. Symlinks bridge them at runtime.
# 1. Clone
git clone <this-repo-url> ~/code/eagent
cd ~/code/eagent
# 2. Pick a data folder (where task.md, KB, messages live — keep this OUT of git)
export EA_DATA_DIR="$HOME/Documents/ea-data"
mkdir -p "$EA_DATA_DIR"/{kb/{people,companies,themes,decisions},messages/{inbox,archive},inbox-digests,drafts}
# Seed the task surface
touch "$EA_DATA_DIR"/{task.md,triage-log.md,.ea-task-snapshot.md,.ea-task-state.json}
touch "$EA_DATA_DIR"/kb/themes/task-learnings.md
# 3. Symlink the orchestrator's config into the data folder
ln -s "$PWD/.claude" "$EA_DATA_DIR/.claude"
ln -s "$PWD/scripts" "$EA_DATA_DIR/scripts"
ln -s "$PWD/prompts" "$EA_DATA_DIR/prompts"
# 4. Install user-level slash commands (works in every Claude Code session)
mkdir -p ~/.claude/commands
cp user-commands/*.md ~/.claude/commands/
# 5. Customize the orchestrator's CLAUDE.md
# Open .claude/CLAUDE.md — replace placeholders (your role, priorities, projects, key people)
# 6. Register the orchestrator with your agent registry
a-team new "My EA" "$EA_DATA_DIR"
# 7. Launch
cd "$EA_DATA_DIR" && claudeFor adding workers (triage, domain-specific loops), see docs/extension.md.
The SessionStart + PreToolUse hooks only fire on session activity. If a session is open and idle when a new message arrives, nothing surfaces until you act on the session.
To close that gap, install the fswatch notifier — a tiny background daemon that watches messages/inbox/ for new files and fires a macOS notification the moment one appears:
brew install fswatch terminal-notifier
bash scripts/install-inbox-notifier.shNote
terminal-notifier is strongly recommended. macOS often silently suppresses osascript-based notifications when fired from launchd context, since they inherit Script Editor's permission state. terminal-notifier has its own bundle ID and gets a clean permission prompt on first use. The installer will warn if it's not installed.
What it does:
- Copies the watcher to
~/Library/Application Support/eagent/(macOS TCC requires this — launchd can't read scripts under~/Documents/without Full Disk Access) - Generates a
launchdplist at~/Library/LaunchAgents/com.eagent.inbox-notifier.plist - Loads it (starts at login, restarts on death)
- Logs go to
~/Library/Logs/eagent-inbox-notifier{.log,.err.log}
You'll see a banner like "📨 worker-a has new message: <title>" whenever any session drops a message in any inbox. Clicking into the session triggers the normal hook flow that surfaces it.
To uninstall, see the messages printed at the end of the installer.
Note
A handful of paths are configurable. Search-and-replace these in the scripts if you want to change them — they're the only hardcoded assumptions in the cleaned-up scripts.
Defaults:
- Repo (code) at
$HOME/code/eagent/(or wherever you cloned) - Data folder at
$HOME/Documents/ea-data/(or wherever you setEA_DATA_DIR) - Agent registry at
~/.config/a-team/agents.toml
EAgent's KB is markdown-first — that handles ~70% of practical queries via grep + wikilinks. For typed, multi-hop structural queries ("who approves wires over $100K?", "if I change System X, what processes are affected?"), mirror your KB into a parallel structured graph store.
The reference implementation is Graphite Atlas — a knowledge graph platform with a typed ontology (Person, Position, Process, System, Outcome, etc.) and MCP server. KB markdown files cross-reference graph nodes via a graph_uuid field in frontmatter; graph nodes have a kb_file property pointing back.
See docs/kb-schema.md for the cross-reference convention. Any graph DB or knowledge graph product works — Atlas is just the cleanest fit for this pattern.
Read in order:
docs/architecture.md— the pattern explained end to enddocs/components.md— what each component doesdocs/messages-protocol.md— the inter-session messaging specdocs/kb-schema.md— knowledge base conventionsdocs/extension.md— how to add your own worker session
Warning
Don't try to use EAgent as-is. The templates in .claude/CLAUDE.md and triage/.claude/CLAUDE.md are starting points — edit them to match your role, your projects, your priorities. The pattern is what's valuable; the specific prose is meant to be replaced.
See CHANGELOG.md.
eagent is part of termpaper.dev, a set of utilities for managing Claude Code state from the terminal:
- a-team — parallel sessions: pick, launch, and restore Claude Code windows in Ghostty. EAgent uses a-team's TOML registry to know what sessions exist.
- whispertty — record + transcribe + diarize audio from the terminal.
- skillbox — inventory and manage skills, slash commands, and subagents.
- eagent — multi-session executive assistant pattern, file-based messaging (this repo).
MIT — see LICENSE.