Architecture · personal operating system GitHub repo

XJ-OS: two AI systems, one mailbox

A fleet of Grok bots runs the clock and talks to the world. Claude Code keeps the record and makes the judgment calls. They never call each other's APIs. They trade Markdown files in one shared Drive folder, and each file has exactly one writer.

1 · Watch it run

Play a day to see every scheduled handoff fire in order, or pick a protocol to step through one exchange. Each moving dot is one file or message.

06:00
Claim: Grok handles everything that runs on a clock or reaches the phone. Claude handles everything that changes the record. They meet only in the Drive mailbox.

2 · Who does what

One routing rule decides where every new job goes. It removed nine areas where both systems did the same work.

GrokIt runs on a clock, or it reaches the phone.
ClaudeIt reads or writes the record, or it needs judgment about history.
Claude cloudIt must run with the laptop closed and needs careful reading.
YouIt is a decision, or it sends something. Claude asks it as a coded question.

Claude Code · laptop

Model
Claude Opus, interactive in the IDE
Starts
You type a question or a /ritual
Context
CLAUDE.md rules (~80 lines), a memory index, skill descriptions. Status is read on demand, never injected.
Tools
Files, shell, MCP connectors (mail, calendar, Drive), 10 subagents, local search
Writes
The record, local git, state/, to-grok/
Guards
A pre-tool hook blocks destructive shell. Send, push and share always ask.

Claude cloud routines

Model
Claude Sonnet, on a cron schedule
Starts
Daily 06:30; Fridays 07:30 and 08:00
Context
The prompt only. Each run starts empty: no rules file, skills, memory or laptop.
Tools
Mail (read only), Drive, open network for feeds, a small fetch script
Writes
One file in from-cloud/, or one Gmail draft
Guards
Duplicate guard, read-only mail, propose only, "nothing new" in one line

Grok fleet

Model
Grok agents (xAI), 20+ bots, 5 group rooms
Starts
Its own schedules, and any chat message
Context
Per-bot instructions and memory, plus state/ and to-grok/
Tools
3 mail accounts, calendars, Drive, X, messenger sessions on a shared Linux box
Writes
Chat posts, from-grok/, its own Drive folder, a weekly setup doc for Claude
Guards
Drafts only. Never sends, buys or trades. Messengers use a separate account.

You

Phone
Group rooms: digests, goals and three domain rooms. Text task: … to any bot.
Laptop
IDE sessions, the dashboard at 127.0.0.1:8766, the Obsidian task board
Fixed time
One Sunday /weekly (~25 min) and a 💾 Save after edits
Always yours
Every send, every sign-off, every major decision

3 · The rhythm

Intake runs every morning without you. Work changes hands six times a week through the mailbox. Your fixed time is one Sunday review.

Day board: Grok, Claude cloud, Claude laptop and You as lanes; events from 06:20 to 21:05 with handoff arrows
Claim: the cloud routines finish 30 minutes before Grok relays their files. The Sunday loop is Grok → Claude → Grok in one evening.
Weekly calendar (table)
When (PT)RitualOwnerOutput
Daily 06:30Morning digest (chats, X, newspaper)GrokDigest room post
Daily 06:30 → 07:00Newsletter digest → relayClaude cloud → Grokfrom-cloud/ file → chat block
Weekdays 07:52 · 09:02Task reminder · CRM nudgeGrok1:1 chat; drafts only
Mon · Wed · Fri 07:00Weekly goals check-inGrok1:1 chat
Fri 07:30Funding radarClaude cloudGmail draft
Fri 08:00 → 08:30Podcast + video scan → relayClaude cloud → Grokfrom-cloud/ file → chat block
Fri 08:00Setup doc refresh (bot roster, schedules)GrokDoc that Claude reads before building anything
Sun 15:00 → 21:00Rollup → /weekly → intakeGrok → Claude → Grokfrom-grok/ → to-grok/
Any session/decide · /coaching · /invest · /write · /endsessionClaudeDecision log, drafts, approved writes
After edits💾 SaveYou → Claude scriptsTask sync, git commit, state/

4 · The protocol

Files, not APIs. Every handoff is a Markdown file with a small header. Folders say who writes; the header says what it is.

Mailbox folders

FolderWriterReaders
state/Claude (laptop) onlyGrok, cloud routines
to-grok/ClaudeGrok
from-grok/GrokClaude
from-grok/tasks/Shared; rules settle conflictsBoth
from-cloud/Cloud routinesGrok relay
*/done/The recipient moves handled files hereArchive

Header block

---
id: req-20XX0101-weekly-context
from: claude-local     # claude-cloud | grok
to: grok
type: request          # state | request | reply | fyi
                       # task | capture | rollup | digest
project: domain-3
created: 20XX-01-01T19:30-08:00
status: open           # open | done | current
reply_to: …            # replies only
lane: This Week        # tasks only: board lane
---
Task sync rules (from-grok/tasks/ ⇅ the task board)

Runs only when you press 💾 Save. A file and a card are matched by the card's detail line - grok: <id>. Done wins on either side. Nothing is ever deleted.

Drive fileBoard cardResult
opennoneNew card in the From Grok lane. A card with the same title adopts the file instead.
openopenThe file's lane: follows the card's lane.
opendoneThe file moves to done/ with status: done and a close date.
doneopenBoth were done last time: you reopened it, so the file comes back. Otherwise Grok closed it: the card is checked.
missingopenThe card is flagged ⚑. Nothing else changes.
noneopen, tagged #grokA new file is written for Grok and the card gets its id line. Private tags never leave the laptop.

Safety: the board is written only if every untouched line survives in order and the editor did not save mid-run. Files changed in the last 60 s wait for the next Save. A dry run shows the pending changes as a badge on the Save button.

Example files (anonymized)
---
id: 20XX-01-01-state-now
from: claude-local
to: grok, claude-cloud
type: state
status: current
---
# Current column — open cards

## Goal 2 · Domain 2
- Project B · In Progress — next: outcome X by date Y
## Goal 1 · Domain 1
- (private)
---
id: task-20XX0101-book-venue
from: grok
to: claude
type: task
source: Domain bot D4
project: domain-4
due: 20XX-02
status: open
lane: This Month
---
Book the venue for event Z.

5 · Tech stack

No database, no message queue, no server in the cloud. Plain files, a synced folder, local git and a 400-line Python server do the work.

InterfacesVS Code + Claude CodeGrok chat app (phone)dashboard: 1 HTML file, vanilla JSObsidian + Kanban pluginGmail draftsHTML reports
ModelsClaude Opus (interactive)Claude Sonnet (routines)Grok agents (xAI)
Agent harnessCLAUDE.md rulesskills (SKILL.md)slash commands10 subagentsPreToolUse hookask / deny permission rulesfile-based memory
SchedulingClaude Code cloud routines (cron)Grok bot schedulesmacOS LaunchAgent (server at login)
TransportGoogle Drive for DesktopMarkdown + header blockCSV / XLSX for tablesno API between systems
Local servicesPython 3 stdlib http.server127.0.0.1 onlysha check → 409schema check → 422fcntl lockstemp + rename writesrolling backups
Storage + searchMarkdown in local git (no remote)QMD hybrid search, 6 collectionsmemory index + weekly lint
ConnectorsMCP: Gmail, Calendar, DriveRSS + YouTube feedsmessenger sessions on Grok's box
Qualitywrite → code-reviewer → qa → shiplossless parser round-trip test (node)sync dry-run badgeweekly OS audit

6 · Guardrails

Rules that matter are enforced by code, not by asking the model to remember. Trust moves one rung right only after a workflow runs cleanly for weeks.

L0 · you do it
  • Send any message
  • Sign-offs
  • Major decisions
L1 · bot drafts, you approve
  • Mail and CRM drafts
  • Funding radar
  • /endsession and /weekly writes
L2 · bot acts, reports
  • Task sync
  • State export
  • Sunday rollup
L3 · exceptions only
  • Digests and scans
  • Watches
  • Search reindex

trust grows → you hear less · sending a message never leaves L0

Enforcement list
RiskControlEnforced by
Destructive shell (rm -rf, force-push, hard reset)Blocked with a reasonPreToolUse hook
Sending mail, pushing code, sharing filesAlways asksPermission rules
Secrets (.env, tokens)Never readableDeny rules + .gitignore
Private domains leaking to botsAllowlist export; deny-term redaction; private tags never syncedExport and sync scripts
Two writers clobbering a fileOne writer per folder; sha check on saveFolder contract + server (409)
Lost editsBackups before every write; local git commit on SaveServer
Hand edits overwritten by scriptsHand moves are final; scripts never recompute themRules + dry run
Silent routine failureRelay posts "did not deliver" after a recheckGrok relay contract

7 · How it got here

Each version removed work before it added any. The current design has one hook, one sync trigger and one shared folder.

v1 · Claude does allClaude ran the morning brief, digests and inbox skills. Intake was scheduled; review lapsed for weeks.
v2 · two fleetsGrok bots took over messaging. Nine areas were done twice: digests, inbox, morning brief, read-later and more.
v3 · the mailboxThe routing rule split the work. A Drive folder with one writer per file became the only contact point.
v4 · Save is the syncStatus lives in a dashboard. One Save syncs tasks, commits and exports. Claude writes digests; Grok relays them. Hooks cut to one guard.