A generic workflow/inbox automation toolkit for message sources, classification, and action pipelines.
flowmesh is designed to sit between messy provider APIs and higher-level automation/orchestration.
It is intentionally not tied to any specific personal inbox, hardcoded address, or one-off naming scheme.
- Wrap multiple inbox/message providers behind small composable commands
- Normalize provider-specific payloads into one stable JSON shape
- Make classification, routing, and action steps pluggable
- Work cleanly with cron, Lobster-style pipelines, shell scripts, and orchestrators
- Keep provider-specific addresses, accounts, folders, labels, and identities in config/args rather than code
- Monolithic personal assistant logic
- Hardcoded mailbox names, email addresses, or user-specific categories
- Giant all-in-one daemon as the first step
flowmesh/
README.md
docs/
architecture.md
cli.md
workflows.md
config.md
normalized-message.schema.json
bin/
flowmesh
src/
core/
types.ts
normalize.ts
classify.ts
filters.ts
emit.ts
providers/
apple-mail/
himalaya/
gog/
imap/
mcp/
workflows/
triage.ts
digest.ts
followup.ts
archive.ts
extract.ts
pipelines/
lobster/
inbox-pull.ts
inbox-triage.ts
followup-scan.ts
formatters/
json.ts
jsonl.ts
markdown.ts
config/
load.ts
resolve.ts
examples/
config.flowmesh.yaml
prompts/
classify-system.txt
summarize-digest.txt
tests/
fixtures/
normalized/
provider-raw/
Each provider implements a small contract, for example:
list→ enumerate messages/itemsget→ fetch one full itemwatch→ optional long-poll/webhook bridge latersend→ optional outbound action latermutate→ archive/tag/move/reply state changes
Adapters should be thin wrappers around existing tools:
- Apple Mail → AppleScript/JXA wrapper
- Himalaya → CLI wrapper
- gog → workspace CLI wrapper for Gmail/Drive/Calendar ecosystems
- IMAP → generic direct mailbox adapter
- MCP → generic remote tool adapter for inbox-like sources
Everything should map into one common JSON shape before downstream logic runs.
Example:
{
"id": "provider-native-id",
"provider": "himalaya",
"account": "work",
"mailbox": "INBOX",
"threadId": "optional-thread-id",
"subject": "Quarterly review",
"from": [{ "name": "Alex", "address": "alex@example.com" }],
"to": [{ "name": "Ops", "address": "ops@example.com" }],
"cc": [],
"receivedAt": "2026-04-03T14:00:00Z",
"snippet": "Can you review the attached plan...",
"bodyText": "...",
"bodyHtml": null,
"labels": ["inbox", "important"],
"attachments": [
{ "filename": "plan.pdf", "mimeType": "application/pdf", "size": 48192 }
],
"flags": {
"read": false,
"starred": true,
"archived": false
},
"refs": {
"providerId": "abc123",
"providerThreadId": "th-456"
},
"meta": {
"rawSource": "provider-specific extras allowed here"
}
}Provider quirks stay inside meta or adapter-specific refs, not in workflow logic.
Classification should be a separate stage, not tangled into provider fetching.
Hook points:
- rule-based local filters
- external LLM classifier
- MCP tool classifier
- shell command hook
Expected classifier output:
{
"category": "followup",
"priority": "high",
"confidence": 0.91,
"tags": ["customer", "deadline"],
"needsResponse": true,
"dueAt": null,
"reason": "Direct request with deadline language"
}Keep first-class pipeline commands that behave well in shells and schedulers:
- read JSON in / write JSON out
- support JSONL for batch pipelines
- support deterministic exit codes
- avoid chatty logs unless
--verbose
Examples:
flowmesh pull --provider himalaya --account work --mailbox INBOX --format jsonl \
| flowmesh normalize --input jsonl --output jsonl \
| flowmesh classify --profile default --output jsonl \
| flowmesh route --workflow triage --output json
flowmesh workflow triage --provider gog --account personal --query 'label:inbox newer_than:2d' --jsonThis is the big anti-footgun.
Bad:
- hardcoding
chris@... - hardcoding
Brain,VIP,Receipts, or other personal folder names into logic - baking provider-specific mailbox names into workflow code
Good:
--account personal--mailbox INBOX--source receipts-mailprofiles.default.includeLabels=['important']routing.rules[]in config
Example config:
accounts:
personal-gmail:
provider: gog
identity: personal
selectors:
defaultQuery: "label:inbox"
work-imap:
provider: imap
host: imap.example.com
port: 993
authRef: op://mail/work-imap
workflows:
triage-default:
source: personal-gmail
classifier: default-llm
archiveOn:
- newsletters
- receipts
escalateOn:
- urgent
- human-reply-neededflowmesh providers listflowmesh pullflowmesh getflowmesh normalizeflowmesh classifyflowmesh routeflowmesh mutateflowmesh workflow <name>flowmesh schema print normalized-messageflowmesh doctor
--provider--account--source--mailbox--query--since--limit--config--profile--format json|jsonl|table--json--verbose
flowmesh pull --provider apple-mail --account local --mailbox INBOX --limit 25 --json
flowmesh pull --provider himalaya --account work --mailbox Inbox --format jsonl
flowmesh classify --profile default < messages.jsonl
flowmesh workflow digest --source personal-gmail --since 24h --json
flowmesh mutate --source work-imap --id 123 --action archiveFetch recent messages, normalize them, classify them, and emit actionable buckets.
Output:
- urgent
- reply-needed
- FYI
- archive-candidate
- spam/noise
Produce a structured summary for the last N hours/day.
Output JSON should include:
- important threads
- pending replies
- top senders
- suggested next actions
Find messages that likely need a response or are waiting on someone.
Heuristics:
- unanswered direct questions
- commitments with dates
- stale threads without closure
Find receipt/order/statement-like messages and emit extracted fields.
Useful for:
- bookkeeping
- archival
- expense pipelines
Bulk archive low-value or already-processed messages based on rules/classifier results.
Must support:
--dry-run- machine-readable planned actions
- optional provider mutation step
Design every workflow so it can run safely from cron:
- no interactive prompts by default
- explicit
--json/--format jsonl - stable exit codes
--dry-runfor mutating workflows- one command can do one thing well
- stderr for logs, stdout for machine output
Example cron-safe usage:
flowmesh workflow triage --source personal-gmail --since 2h --json > /var/tmp/triage.json
flowmesh workflow followup --source work-imap --since 7d --json | jq '.items[] | select(.priority=="high")'Build the first milestone around three adapters and one normalized schema:
himalayagog(for Gmail-like fetch/query flows)imap
Then add:
apple-mailmcp
Why: Himalaya/IMAP/Gmail cover the broadest generic cases first. Apple Mail and MCP can slot in once the contracts are proven.
- Define
normalized-message.schema.json - Implement provider interface and adapter test fixtures
- Build
pull,normalize, andworkflow triage - Add classifier hook contract (
stdin/stdout JSONfriendly) - Add
mutate --dry-runand action planning output - Add example configs for gog, himalaya, and IMAP
This folder is currently a design scaffold only. No heavy implementation has been added yet.