Personal-AI-Employee
CLAUDE.md8 starsChanged 4 months agoMITView on GitHub
This project's actual agent runtime is OpenCode, which reads AGENTS.md instead of this file (and ignores CLAUDE.md entirely if AGENTS.md is present — see OpenCode's docs on rules precedence). AGENTS.md and this file are kept in sync intentionally, the same way .agents/skills/ and .claude/skills/ are duplicated so each tool finds what it needs natively. If you update one, update the other. A local-first, human-in-the-loop autonomous agent system ("Personal AI Employee") that triages email, manages LinkedIn, and drafts business actions for…
- Reads credentials
- Deletes or force-pushes
- Commits and pushes
In this repository27 other files it gives its agents.
- AGENTS.mdAGENTS.md
- ceo-briefingSkill
- dashboard-updateSkill
- email-skillSkill
- fetch-library-docsSkill
- hitl-workflowSkill
- linkedin-skillSkill
- mcp-builderSkill
- odoo-accountingSkill
- process-tasksSkill
- reasoning-loopSkill
- skill-creator-proSkill
- skill-validatorSkill
- social-managerSkill
- ceo-briefingSkill
- dashboard-updateSkill
- email-skillSkill
- fetch-library-docsSkill
- hitl-workflowSkill
- linkedin-skillSkill
- mcp-builderSkill
- odoo-accountingSkill
- process-tasksSkill
- reasoning-loopSkill
- skill-creator-proSkill
- skill-validatorSkill
- social-managerSkill
The file
We split this CLAUDE.md into the rules it gives an agent
2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 33
Run a single watcher directly (useful for isolated debugging):
- Distinctive: line 43
Run an MCP server standalone:
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This project's actual agent runtime is OpenCode, which reads AGENTS.md instead of this file (and ignores CLAUDE.md entirely if AGENTS.md is present — see OpenCode's docs on rules precedence). AGENTS.md and this file are kept in sync intentionally, the same way .agents/skills/ and .claude/skills/ are duplicated so each tool finds what it needs natively. If you update one, update the other.
What this project is
A local-first, human-in-the-loop autonomous agent system ("Personal AI Employee") that triages email, manages LinkedIn, and drafts business actions for human approval. See the README's "Project Status" table for what's actually working vs. scaffolding before relying on any given component. It follows a Perception → Reasoning → Action loop:
- Watchers (
watchers/*.py) poll Gmail, LinkedIn, and the local filesystem, dropping Markdown task files intovault/Needs_Action/.gmail_watcher.pysupports multiple Gmail accounts via theGMAIL_ACCOUNT_LABELenv var (orchestrator.pylaunches one process per account — currentlydefault/personal andwork/job-search); each account gets its owntoken_<label>.json,processed_emails_<label>.txt, andgmail_watcher_<label>.log, and generated task files carry anaccount:frontmatter field so downstream skills know which inbox — and which address to reply from — a given email came from. - Reasoning: an LLM agent runs via the OpenCode CLI, reads the vault, uses Agent Skills in
.agents/skills/(OpenCode discovers these natively, no migration needed), and drafts actions. Configured inopencode.jsonat the repo root, currently pointed at OpenCode Zen's freeopencode/big-picklemodel. - Action: MCP servers in
mcp_servers/execute approved actions. Everything irreversible (sending email, posting socially, financial writes) is meant to go through a Human-in-the-Loop gate: agent drafts tovault/Pending_Approval/, a human approves it, andwatchers/approval_watcher.pyexecutes it and moves the file tovault/Done/. Approval has three independent paths intovault/Approved/: manually dragging the file (Obsidian),telegram_approval_watcher.py, ordiscord_approval_watcher.py— the latter two both ping their respective platform with Approve/Reject/Request Changes buttons the moment a file lands inPending_Approval/(Discord exists as a redundant channel because Telegram is intermittently blocked in Pakistan; both notify independently for the same files and re-check file existence before acting, so acting from one makes the other's buttons harmlessly no-op with "already handled"). "Request Changes" on either platform appends the human's free-text reply to the file and moves it tovault/Needs_Action/withstatus: needs_revisionfor the next OpenCode pass to redraft.
The Obsidian vault (vault/) is the system's state machine, config layer, and audit log — not just docs. Read vault/Company_Handbook.md (rules of engagement) and vault/Business_Goals.md (KPIs/targets) before making behavioral changes to any skill or watcher; skills are expected to comply with the Handbook's approval thresholds.
Commands
There is no build step, linter, or test suite in this repo.
Install dependencies:
uv sync # uses pyproject.toml + uv.lockRun the system:
python orchestrator.py # boots all watchers (2x gmail, linkedin, filesystem, approval, telegram_approval, discord_approval), auto-restarts on crash
opencode # second terminal: starts the reasoning agent (interactive TUI)
opencode run "<prompt>" --auto # non-interactive, unattended run — used by scheduler/run_agent.ps1 and scripts/ralph_loop.ps1Run a single watcher directly (useful for isolated debugging):
python watchers/gmail_watcher.py # GMAIL_ACCOUNT_LABEL=work env var selects the second account
python watchers/linkedin_watcher.py
python watchers/filesystem_watcher.py
python watchers/approval_watcher.py
python watchers/telegram_approval_watcher.py # idles (no crash) until TELEGRAM_BOT_TOKEN/CHAT_ID are set
python watchers/discord_approval_watcher.py # idles (no crash) until discord.py installed + DISCORD_BOT_TOKEN/CHANNEL_ID are setRun an MCP server standalone:
uv run mcp_servers/email/server.py
python mcp_servers/odoo_mcp.py
python mcp_servers/socials_mcp.pyLocal Odoo instance for accounting integration testing:
docker-compose up -d # odoo:latest on :8069 + postgres:15Windows Task Scheduler wiring: scheduler/setup_task.ps1 registers scheduler/run_agent.ps1 as a recurring job; scripts/ralph_loop.ps1 implements the "Ralph Wiggum" retry loop (creates a task file, polls until it's moved to vault/Done/ or MaxIterations is hit).
Safety model
.env'sDRY_RUNflag gates whether watchers/MCP servers perform real side effects (send email, post socially) vs. log-only. Check.envfor the current value before testing anything that hits a live API..env,token*.json(one per Gmail account —token.json,token_work.json, etc.),credentials.jsonhold real secrets and are gitignored — never read their values into responses or logs, never commit them.- MCP servers are registered in
opencode.json'smcpkey (not a separateconfig/mcp.json— that file was removed when the project switched from Qwen Code to OpenCode). Onlymcp_servers/email/server.pyis currently registered there.odoo_mcp.pyandsocials_mcp.pyexist but aren't wired intoopencode.json— they aren't reachable by the agent as currently configured. opencode.json'spermissionblock allowsedit/bashby default (needed for vault file operations) but explicitly deniesrm -rf *and requires confirmation ongit push/git reset --hardas defense-in-depth. The real HITL safety boundary is still the vault'sPending_Approval→Approvedfile-move gate, not tool permissions.- Most
vault/subdirectories (Needs_Action,Logs,Pending_Approval,Approved,Done,Rejected,Briefings,Plans) are gitignored but re-included for tool visibility via.rgignore(OpenCode's Glob/Grep tools are ripgrep-backed and silently respect.gitignoreotherwise — see Known Issues). OnlyCompany_Handbook.md,Business_Goals.md,Dashboard.md, and.obsidian/config stay tracked in git — everything else fills up with real runtime data (actual email content, client/business specifics) that shouldn't enter git history. If you can't see files somewhere undervault/via Glob, check.rgignorebefore assuming the directory is empty.
Known issues / gaps (read before making changes here)
This audit reflects the state as of 2026-07-09. Re-verify anything load-bearing before relying on it, since the codebase is about to change substantially.
odoo_mcp.pyhas no code-level safety gate —odoo_execute_kwis a generic ORM executor (create/write/unlink on any model) with noDRY_RUNcheck and no approval-file requirement, unlike every other action path in the system. The only guard is a prompt-level instruction in theodoo-accountingskill. Treat this as the highest-priority item to fix before enabling real Odoo writes.socials_mcp.pyis a stub, not a real integration — it logs posts to a local JSON file and returns hardcoded fake metrics. No real Facebook/Instagram/Twitter API calls exist despite README claims.scripts/post.ps1posts live to the LinkedIn API with no dry-run gate; treat it as a manual, deliberately-live test script, not something to run casually.- Fixed 2026-07-11: removed
requirements.txt, which had drifted out of sync withpyproject.toml(missingdiscord-pybefore removal — proof the two-manifest setup wasn't being kept in sync in practice).pyproject.toml+uv.lock(viauv sync) is now the only dependency path. - Fixed 2026-07-11: removed
filesystem_watcher_basic.py(dead code, fully superseded by the watchdog-basedfilesystem_watcher.py) and flattenedwatchers/done/*.py→watchers/*.py(thedone/todosplit was vestigial —watchers/todo/never existed on disk). Every watcher's root-path calculation (Path(__file__).parent.parent...) was updated from 3 levels to 2 to match the new depth. scripts/watchdog.pyis a second, undocumented supervisor that restartsorchestrator.pyitself; it isn't referenced by anything else in the repo and may be orphaned — confirm intent before relying on or removing it.gmail_watcher.py's generated frontmatter format andapproval_watcher.py's regex-based recipient extraction are loosely coupled and not covered by tests — changes to one's output format can silently break the other's parsing.docs/SETUP.mdreferences a Playwright-based WhatsApp watcher that was never built (matches the emptywhatsapp_session/gitignore entry). The README's "Project Status" table is the current source of truth for what's real vs. stub — keep it in sync if you change component status, since the olddocs/PROGRESS.mdtracker drifted out of sync with the code and was removed for exactly that reason.- Agent runtime was switched from Qwen Code (via a
claudeCLI + local Ollamaqwen2.5:3bhack) to OpenCode on 2026-07-09, because Ollama wasn't even running locally and the 3B model was unreliable at tool calling.opencode.jsonnow pinsmodeltoopencode/big-pickle, a free model on the OpenCode Zen gateway. Zen's free-model lineup rotates (models get pulled or start being billed with little notice) — if the agent starts erroring or being billed, runopencode modelsto see what's currently free and updatemodel/small_modelinopencode.json. Zen requires a card on file even for $0 models (never charged as long as you stick to free-labeled ones). - Leftover artifacts from the prior Qwen Code setup (
QWEN.md,.qwen/) were removed on 2026-07-09 as part of the OpenCode switch. - OpenCode's Glob/Grep tools are ripgrep-backed and respect
.gitignoreby default (upstream limitation, no config toggle — see opencode issue #31994). Since mostvault/runtime subdirectories are intentionally gitignored (see Safety model), the agent couldn't see files in them via Glob until a root-level.rgignorewas added to re-include those paths for tool visibility without changing what git tracks. If you add another gitignored-but-agent-needs-to-read directory undervault/, add it to.rgignoretoo, or the agent will silently see it as empty. - Rapid back-to-back
opencode runinvocations (or one running while an interactiveopencodeTUI session is still open) can intermittently fail withError: Unexpected error / Failed query: PRAGMA wal_checkpoint(PASSIVE)— a local SQLite session-DB lock collision. It's transient; retrying the command succeeds. Close stray interactiveopencodesessions before relying on scheduledopencode run --autojobs to avoid this. - Fixed 2026-07-09/10:
scheduler/run_agent.ps1had a check-then-act race that let two scheduled ticks both pass the "orchestrator not running" check and each spawn a full orchestrator + 4-watcher tree simultaneously. This is almost certainly what caused the "6 duplicate CEO Briefing task files" bug. Fixed with a namedSystem.Threading.Mutexguarding the whole script (a second concurrent invocation now exits immediately instead of duplicating work) plus a PID-lock-file check for the orchestrator specifically. Validated in production across multiple real scheduled cycles since the fix. - Fixed 2026-07-09/10:
run_agent.ps1'sStart-Process -FilePath "opencode"failed on every single scheduled run with%1 is not a valid Win32 application— npm's Windows install also creates anopencode.ps1shim, andStart-Processuses rawCreateProcess, which can't execute a.ps1directly (unlike interactive PowerShell command resolution). Fixed by targetingopencode.cmdexplicitly. This means every scheduled OpenCode run before this fix silently did nothing. orchestrator.py's watcher-restart loop has no backoff or retry limit — a crashed watcher (e.g.gmail_watcher.pyhitting an expired OAuth token) gets relaunched every 10 seconds forever. In practice this produced 185,000+ log lines and an 18MBorchestrator.logover about four months before being noticed (the Gmail token has since been fixed). Adding exponential backoff or a give-up-and-alert threshold is a good-first-contribution (seeCONTRIBUTING.md).telegram_approval_watcher.pypings a Telegram chat for every newvault/Pending_Approval/file and handles Approve/Reject/Request Changes replies (see CONTRIBUTING.md for bot setup). Deliberately does not crash-exit whenTELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_IDare unset — it idles and logs a reminder every ~10 minutes instead, specifically to avoid repeating the gmail_watcher.py crash-loop failure mode above.discord_approval_watcher.pyis a second, redundant approval channel (same Approve/Reject/Request Changes UX) added because Telegram is intermittently blocked in Pakistan by PTA. Usesdiscord.py's Gateway client (websocket, outbound-only — no port forwarding needed), not raw REST like the Telegram watcher, since receiving button interactions requires either a Gateway connection or a publicly reachable webhook URL. Same "idle, don't crash" guard applies ifdiscord.pyisn't installed orDISCORD_BOT_TOKEN/DISCORD_CHANNEL_IDare unset.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

