Built an always-on AI Chief of Staff that texts me.
I've been in this community for about a month now and wanted to share where things stand with one of my builds. This isn't polished by any stretch. I do have a few other workflows like content-creator, document-creator, but I needed something to help me navigate my day-to-day as I begin a couple side quests outside my normal 9-5.
The goal was simple: I didn't want another chat window I have to remember to open. I wanted something that knows my priorities, reads my calendar, checks my email, and texts me when I need a nudge. Not a chatbot, more like a Chief of Staff. And the goal is to operate within the bounds of the subscription with no extra costs, while also maximizing token efficiency.
The other thing I didn't want to do is implement an orchestrating harness yet (OpenClaw, Hermes, etc). The challenge for myself was to keep this as simple as possible without inflating scope. Someone in this community said once: 'constraints are just as, if not more, important than your requirements. What do you NOT want your build to do?' I've definitely taken this to heart in my workflows.
## Planning
I've made a few posts about this in comments, but I cannot stress the importance of planning before you build. My method was simple:
  • First I brain dumped context via voice dictation and transcribed this. Simple tools: VoiceMemos, copy, paste.
  • Next, I worked through the planning phase with the chat function of Claude in Opus 4.6. I wanted pushback, challenge, and for the model to force me to think deeper and keep me honest. This produced the product requirement document, or PRD. This was a multi-day process (a week?) in my free-time.
  • For the architecture build, I used Cowork. Handed it the PRD, answered a few basic questions, and then it went on it's way. Got it uploaded to a private git repo.
  • Currently, I'm working thru further debugging and walking thru the checklist within the PRD in a phased approach. As you'll see below, I have setup a remote screenshare so I can also let Cowork see what I'm doing. This was the most essential because we work TOGETHER to make things happen. it's like working side-by-side with my developer and engineer.
## THE BIGGEST TIP
Tell it (being Cowork, Claude Code, or the agent) to do the work for you. If it gives you direction, your first instinct should be "can you do that for me?" This will save you hours... especially if you also have tracking mechanisms in place like change logs, error reporting, and backup repos stored.
## The Summary
Her name is Emma and she runs 24/7 on an old mid-2015 MacBook Pro that was just laying around. She communicates through iMessage (expanding to other channels later). I text her and she texts back. She also texts me first, as you'll see. The goal is to have a proactive chief-of-staff of life that can eventually orchestrate and advise, deploy sub-agents to do tasks I simply don't want to do, and enable me to do what I love: design, workshops, and development.
## The architecture
If you've been following along in this community, the structure will look familiar. The entire agent is a folder of markdown files. There aren't any vector databases or proprietary memory stores. If you open the folder and read the files, you understand the full system immediately. As Jake repeats: 'plain English'.
It runs on a layered model:
  • The identity layer is three files that define who Emma is, how she operates, and what triggers proactive behavior. These always load.
  • The navigation layer is a single routing file that points her to the right domain or skill for any given task. Also always loaded.
  • Everything else (domains, skills, memory) only loads when it's relevant to what I'm asking about.
That selective loading is the biggest thing I've extracted from this community. If I ask about my work calendar, she loads my work context. She does NOT load my business planning files or my relocation context. Only what's needed, every time. That's how you keep token usage efficient on a decade-old laptop.
The whole thing is model-agnostic. The markdown files, the folder structure, the domain separation... none of it cares what model is running underneath. The only model-specific lines are the CLI command in two bash scripts. Swap that line, the whole system runs on something else. I documented this in a runtime-bindings reference file so the system itself knows what to change. That way, if I decide to either switch models or do a multi-model infrastructure... I can.
## What's live right now
The reactive loop.
I text Emma, a bash script polls the iMessage SQLite database every 5 seconds, pipes the message to the LLM with full project context, and an AppleScript sends the response back as an iMessage. No API needed for the messaging layer. iMessage is native to macOS.
Conversation memory. Before every response, Emma queries the last 20 messages in the iMessage thread from the SQLite database. iMessage itself is the memory store. I can say "What's the weather in Atlanta?" and follow up with "What about tomorrow?" and she handles the context naturally. Zero additional infrastructure.
Morning brief.
A separate script runs on a macOS launchd schedule at 4:45am. It pulls weather, news, and calendar context through web search and MCP connectors, generates a briefing, and sends it as an iMessage. I wake up to a text from Emma with my day's plan already laid out.
MCP integrations.
Google Calendar, Gmail, Google Drive, and Notion are all connected. She reads my calendars, detects conflicts, surfaces meeting context, reads and drafts emails (never sends without my approval), searches Drive documents, and queries Notion databases.
Auto-start on boot.
A macOS LaunchAgent plist fires the start script at login. If the MacBook reboots, Emma comes back online without me touching anything. Worst-case scenario is a full shutdown. This will be solved later with battery backup.
Remote access.
Both machines are on a Tailscale VPN mesh. I can screen-share into Emma's MacBook from anywhere in the world. With both my current job and future plans, this will be extremely essential.
## Hard-won lessons
launchd uses a minimal PATH that doesn't include Homebrew binaries. Had to hardcode the full PATH into every script. Lost a few hours to that one.
KeepAlive: true in launchd means "restart this process every time it exits." If your script exits after launching tmux, that creates an infinite restart loop. RunAtLoad: true is what you actually want.
iMessage's SQLite database requires Full Disk Access. That's why Emma runs on a dedicated machine, not my daily driver. If this were a newer Macbook or MacMini, the Anthropic iMessage plugin would have worked seamlessly and poling would have been fine. Since this is operating on Monterey, we're dealing with some archaic tech. I also solved message-to-message memory through basic context direction.
## What's still on the roadmap
  • End-of-day intention setting (scheduled trigger, not yet built)
  • Commitment follow-up nudges
  • Weekly review prompts
  • Connecting work email and calendar viewing (enterprise auth is its own beast)
  • Voice transcript pipeline so Emma can recall what was said in meetings
  • Specific skills and YAML docs to perform repeatable tasks with consistency and accuracy.
  • Speech capabilities so Emma can do voice sessions or, eventually, call out
  • A second fork of the architecture for my wife
## The compound interest piece
Every correction Emma gets makes her permanently better, and every domain context file I populate makes her smarter about that area of my life. Every skill I add expands what she can do.
My mission was pretty clear: no vendor lock-in, no subscription lock-in, and no cloud dependency. Readable markdown on an old laptop, accessible from anywhere.
Still early. But it works today, and it's built to grow with me.
23
36 comments
Justin Solomon
5
Built an always-on AI Chief of Staff that texts me.
Clief Notes
skool.com/cliefnotes
Jake Van Clief, giving you the Cliff notes on the new AI age.
Leaderboard (30-day)
Powered by