{"id":"795e8aa7-a812-4bc6-89dc-10389d597a70","slug":"abdulsamad94-personal-ai-employee","kind":"mcp","name":"Personal-AI-Employee","summary":"Local-first, human-in-the-loop personal AI employee. Watches email/LinkedIn, drafts actions with OpenCode, and waits for your approval via Telegram/Discord, before anything real happens.","owner":"AbdulSamad94","repoUrl":"https://github.com/AbdulSamad94/Personal-AI-Employee","license":"MIT","licenseTier":"permissive","trust":"community","stars":8,"match":null,"fewStars":false,"format":"mcp","createdAt":"2026-03-02T20:13:26.000Z","addedAt":"2026-10-21T16:55:07.075Z","logoUrl":"https://avatars.githubusercontent.com/u/160336057?u=8d482f3cb109e19ea9d80b846ccdf451c0dc3e81&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["productivity","communication","developer-tools"],"tags":["ai","ai-agents","ai-employees","claude-code","agentic-ai","ai-automation","automation","gmail-automation"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T22:27:40.560Z","sample":false,"url":"https://conduits.dev/tools/abdulsamad94-personal-ai-employee","language":"Python","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# Personal AI Employee\n\n> Local-first, human-in-the-loop autonomous agent. It watches your inbox and business signals, drafts the response, and waits for you to approve it before anything real happens.\n\n![Python 3.11+](https://img.shields.io/badge/Python-3.11%2B-blue.svg)\n![OpenCode](https://img.shields.io/badge/AI-OpenCode-orange.svg)\n![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)\n\n## Quick start\n\n```bash\ngit clone https://github.com/AbdulSamad94/Personal-AI-Employee.git\ncd Personal-AI-Employee\nuv sync\ncp .env.example .env   # fill in your credentials — see Setup & Installation below\npython orchestrator.py # boots the watchers\nopencode run \"Process all pending tasks in vault/Needs_Action/\" --auto\n```\n\nThat's the whole loop in one shot. Full setup (Gmail OAuth, Telegram/Discord approval bots, etc.) is in [Setup & Installation](#setup--installation).\n\n## Table of Contents\n\n- [What this is](#what-this-is)\n- [Core Architecture](#core-architecture)\n- [Project Status](#project-status)\n- [Codebase & Vault Structure](#codebase--vault-structure)\n- [Setup & Installation](#setup--installation)\n- [Application Workflows](#application-workflows)\n- [Security & Privacy Posture](#security--privacy-posture)\n- [Permission Policy](#permission-policy)\n- [The \"Ralph Wiggum\" Retry Loop](#the-ralph-wiggum-retry-loop)\n- [Error Handling — current vs. planned](#error-handling--current-vs-planned)\n- [Troubleshooting / FAQ](#troubleshooting--faq)\n- [Contributing](#contributing)\n\n## What this is\n\nMost \"AI agent\" products are a black box: you give a SaaS tool your credentials and hope it does the right thing. This project takes the opposite approach — every piece of state the agent knows or plans is a plain Markdown file you can read, edit, or delete yourself, and nothing irreversible (sending an email, posting socially, moving money) happens without you physically approving the draft first.\n\nIt runs entirely on your own machine, uses a local [OpenCode](https://opencode.ai) agent for reasoning, and keeps its entire memory in an Obsidian vault.\n\n## Core Architecture\n\nThe system follows a **Perception → Reasoning → Action** loop.\n\n```mermaid\ngraph TD\n    subgraph \"Perception (Watchers)\"\n        GW[Gmail Watcher] --> |Creates EMAIL.md| Inbox[(Vault / Needs_Action)]\n        LW[LinkedIn Watcher] --> |Creates LEAD.md| Inbox\n        FW[Filesystem Watcher] --> |Drops FILES.md| Inbox\n    end\n\n    subgraph \"Reasoning (The Brain & Memory)\"\n        Inbox --> |Read Trigger| OC[OpenCode Engine]\n        OC <--> |Uses Skills| Skills[Agent Skills]\n        OC <--> |Checks Rules| CH[Company_Handbook.md]\n        OC <--> |Checks Goals| BG[Business_Goals.md]\n    end\n\n    subgraph \"Action (MCP Servers & HITL)\"\n        OC --> |Drafts Action| PA[(Vault / Pending_Approval)]\n        PA --> |Human Reviews & Moves| APP[(Vault / Approved)]\n        APP --> |Triggers| AW[Approval Watcher]\n        AW --> |Executes via| MCP[MCP Servers]\n        MCP --> |Logs to| Done[(Vault / Done & Logs)]\n    end\n```\n\n### 1. The Senses (Watchers)\nLightweight Python background scripts (`/watchers/`) acting as the system's eyes and ears. Managed by `orchestrator.py`, they scan APIs and filesystems, transforming external events into Markdown files dropped into the Obsidian Vault.\n\n### 2. The Brain & Memory\n- **The Brain**: OpenCode runs in a continuous loop. Woken by new files in `Needs_Action`, it leverages custom **Agent Skills** (`.agents/skills/`) to break down complex tasks and draft solutions.\n- **The Memory**: The Obsidian Vault (`/vault/`) acts as the state machine, config layer, and audit log. Everything the AI knows or plans is visible as local, editable text.\n\n### 3. The Hands (MCP & HITL)\n- **Model Context Protocol (MCP)**: Standardized servers (`/mcp_servers/`) that expose external tools (like sending Gmail, posting socially, accessing Odoo) to OpenCode. See [Project Status](#project-status) — not all of these are wired up or safe to use yet.\n- **Human-In-The-Loop (HITL)**: The AI writes draft actions to `/Pending_Approval`. Actions strictly wait for a human to drag the file to `/Approved` before the `approval_watcher` executes them.\n\n---\n\n## Project Status\n\nBeing upfront about what actually works vs. what's scaffolding, so you don't wire something up expecting it to be production-ready:\n\n| Component | Status | Notes |\n| :--- | :--- | :--- |\n| Gmail watcher + triage | ✅ Working, multi-account | Polls for priority mail across multiple Gmail accounts (`GMAIL_ACCOUNT_LABEL` env var), drafts replies via `email-skill` from the matching address, routes through HITL approval. |\n| LinkedIn watcher | ✅ Working | Monitors connections/messages, drafts outreach for approval. |\n| Filesystem watcher | ✅ Working | Event-driven (watchdog-based) ingestion of dropped files. |\n| Approval workflow | ✅ Working | The `Pending_Approval → Approved → Done` gate is enforced in code, not just policy. Three independent approval paths: drag-and-drop (Obsidian), Telegram bot, Discord bot — any one moves the file. |\n| Telegram/Discord approval bots | ✅ Working | Push a notification with Approve/Reject/Request Changes buttons the moment a draft is ready — no manual file dragging needed. Both run in parallel as redundant channels (useful if one platform is blocked on your network); see `CONTRIBUTING.md` for bot setup. |\n| Email MCP server | ✅ Working, wired up | Registered in `opencode.json`, respects `DRY_RUN`, supports sending from multiple configured accounts. |\n| Odoo accounting MCP | ⚠️ Exists, not wired up, no safety gate | `mcp_servers/odoo_mcp.py` can create/write/delete any Odoo record with no `DRY_RUN` check or approval requirement in code — only a prompt-level instruction in its skill. Don't register it in `opencode.json` until that's fixed. |\n| Social media MCP | ⚠️ Stub | `mcp_servers/socials_mcp.py` logs posts to a local JSON file and always reports success — it does not call any real Facebook/Instagram/Twitter API yet. |\n| WhatsApp watcher | ❌ Not built | Referenced in early planning docs, never implemented. |\n| Weekly CEO Briefing | ✅ Working | Audits `Business_Goals.md` and generates a summary in `vault/Briefings/`. |\n| Windows Task Scheduler integration | ✅ Working, Windows-only | `scheduler/setup_task.ps1` registers a recurring job, wakes the machine from sleep to run. No Linux/Mac equivalent yet (cron/launchd). |\n\n---\n\n## Codebase & Vault Structure\n\n```text\n/personal-ai-employee\n├── .env                        # Environment Secrets (DO NOT COMMIT)\n├── opencode.json               # OpenCode config: model, MCP servers, permissions\n├── orchestrator.py             # Main entry point: Runs all background watchers continuously\n├── vault/                      # 🧠 The Obsidian Vault (System State & Memory)\n│   ├── Inbox/                  # Raw drops\n│   ├── Needs_Action/           # Tasks awaiting OpenCode's attention\n│   ├── Pending_Approval/       # OpenCode's drafted tasks awaiting human approval\n│   ├── Approved/               # Human-approved tasks waiting for execution watcher\n│   ├── Done/ & Logs/           # History of completed actions\n│   ├── Company_Handbook.md     # Rules of behavior for the AI\n│   ├── Business_Goals.md       # KPIs and targets for autonomous audits\n│   └── Dashboard.md            # Real-time state overview\n├── watchers/                   # 👀 The Senses — active Python background scripts\n│   ├── gmail_watcher.py        # Monitors unread priority emails (multi-account via GMAIL_ACCOUNT_LABEL)\n│   ├── linkedin_watcher.py     # Monitors LinkedIn connections/messages\n│   ├── filesystem_watcher.py   # Event-driven local file ingester\n│   ├── approval_watcher.py     # Executes tasks dropped in /Approved\n│   ├── telegram_approval_watcher.py  # Pending_Approval → Telegram Approve/Reject/Edit ping\n│   └── discord_approval_watcher.py   # Pending_Approval → Discord Approve/Reject/Edit ping\n├── .agents/skills/             # 🛠️ OpenCode's Reasoning capabilities\n│   ├── hitl-workflow/          # Logic for requesting human permissions\n│   ├── email-skill/            # Logic for drafting, triaging emails\n│   ├── linkedin-skill/         # Logic for B2B lead generation & posting\n│   ├── ceo-briefing/           # Logic for weekly audits\n│   ├── odoo-accounting/        # Logic for ERP connections\n│   ├── social-manager/         # Logic for social media PR\n│   ├── reasoning-loop/         # Deep multi-step task planning\n│   └── ...\n└── mcp_servers/                # 👐 The Hands\n    ├── email/                  # Python MCP Server for Gmail\n    ├── odoo_mcp.py             # Python MCP Server for local Odoo APIs (unwired, unsafe — see status table)\n    └── socials_mcp.py          # Python MCP Server for FB/IG/Twitter (stub — see status table)\n```\n\n---\n\n## Setup & Installation\n\n### Prerequisites\n1. **Python 3.11+**\n2. **[OpenCode](https://opencode.ai)** installed (`npm install -g opencode-ai`)\n3. **Obsidian** (optional, for viewing the `/vault` visually)\n\n### Step-by-Step\n\n1. **Clone & install dependencies**\n    ```bash\n    git clone https://github.com/AbdulSamad94/Personal-AI-Employee.git\n    cd Personal-AI-Employee\n    uv sync\n    ```\n\n2. **Configure environment variables**\n    ```bash\n    cp .env.example .env\n    ```\n    Then fill in the values you need — `.env.example` documents every variable, including which are optional (second Gmail account, Telegram/Discord bots, Odoo). At minimum you need `GMAIL_USER`/`GMAIL_APP_PASSWORD` to get started; leave `DRY_RUN=true` until you've reviewed what the agent does.\n\n3. **Initialize the orchestrator**\n    Boots all background watchers. Leave it running in a terminal.\n    ```bash\n    python orchestrator.py\n    ```\n\n4. **Boot up OpenCode**\n    In a second terminal:\n    ```bash\n    opencode\n    > \"Trigger the process-tasks skill to empty the Needs_Action folder.\"\n    ```\n    Or run it non-interactively (what the scheduled task does):\n    ```bash\n    opencode run \"Process all pending tasks in vault/Needs_Action/...\" --auto\n    ```\n\n---\n\n## Application Workflows\n\n### Secure Email Triage (Human-In-The-Loop)\n\n```mermaid\nsequenceDiagram\n    participant Web as Gmail servers\n    participant GW as gmail_watcher.py\n    participant V as Vault (Obsidian)\n    participant Q as OpenCode\n    participant AW as approval_watcher.py\n    participant MCP as MCP Email Server\n\n    Web->>GW: New urgent client email arrives\n    GW->>V: Creates EMAIL_101.md in /Needs_Action\n    Q->>V: Detects EMAIL_101.md\n    Q->>Q: Uses email-skill & hitl-workflow to plan reply\n    Q->>V: Drafts response & moves to /Pending_Approval\n    Note over V: Waiting for local human review...\n    Human->>V: Drags via Obsidian into /Approved\n    AW->>V: Detects approved file\n    AW->>MCP: Sends JSON-RPC payload to dispatch\n    MCP->>Web: Sends actual Email\n    AW->>V: Moves EMAIL_101.md to /Done & Updates /Logs\n```\n\n### Automated LinkedIn Lead Generation\n\n```mermaid\nsequenceDiagram\n    participant LW as linkedin_watcher.py\n    participant V as Vault (Obsidian)\n    participant Q as OpenCode\n\n    LW->>V: Scrapes daily metrics & new connections\n    LW->>V: Logs to /Needs_Action/LINKEDIN_Event.md\n    Q->>V: Analyzes connection profiles\n    Q->>Q: Compares against Business_Goals.md\n    Q->>V: Drafts personalized welcome DMs or Lead scores\n    Q->>V: Places recommendations in /Pending_Approval\n```\n\n---\n\n## Security & Privacy Posture\n\n- **Zero-cloud memory**: all internal state lives in local Markdown files inside `/vault`. You own the data.\n- **HITL by default**: the AI uses the `/Pending_Approval` workflow. No irreversible API calls (payments, outgoing emails, social posts) trigger without an explicit, manual file move — this is enforced in `approval_watcher.py`, not just a policy statement.\n- **Dry-run sandbox**: set `DRY_RUN=true` in `.env` to log intended actions without actually sending/posting anything, useful while testing changes.\n- **Known gap**: the Odoo MCP server has no code-level dry-run/approval check (see [Project Status](#project-status)) — don't wire it into `opencode.json` for real financial data until that's fixed.\n\n## Permission Policy\n\nThe intended action thresholds, as defined in `vault/Company_Handbook.md`. Today these are enforced through the Handbook + skill instructions the agent reads before acting, not hard-coded checks — treat this as policy the agent is instructed to follow, not a guarantee:\n\n| Action Category | Auto-Approve Threshold | Always Requires Manual Approval |\n| :--- | :--- | :--- |\n| Email Replies | Known contacts (whitelisted domains) | New contacts, bulk sends, sensitive topics |\n| Social Media | Scheduled \"evergreen\" posts | Real-time replies, DMs, sponsored content |\n| Payments | Recurring bills < $50 | All new payees, transfers > $100 |\n| File Ops | Reading, creating in vault | Deleting, moving files outside the vault |\n\n## The \"Ralph Wiggum\" Retry Loop\n\n`scripts/ralph_loop.ps1` keeps OpenCode working a single task until it's actually moved to `vault/Done/`, instead of accepting the first response as complete — this fights the \"lazy agent\" problem where a model claims a task is done without doing it.\n\n```mermaid\nsequenceDiagram\n    participant O as Orchestrator\n    participant Q as OpenCode\n    participant V as Vault (Obsidian)\n\n    O->>V: Detects new file in /Needs_Action\n    O->>Q: Bootstraps OpenCode with \"Process Inbox\" goal\n    loop Ralph Wiggum retry loop\n        Q->>V: Reads Tasks & Plans\n        Q->>V: Executes step (e.g., Drafts email)\n        Q->>Q: Checks completion criteria\n        alt Task Not Found in /Done\n            Q->>Q: Self-corrects & Loops\n        else Task Moved to /Done\n            Q->>O: Emits <promise>TASK_COMPLETE</promise>\n        end\n    end\n    O->>O: Graceful Shutdown or Sleeps\n```\n\n## Error Handling — current vs. planned\n\n**What's actually implemented today**: `orchestrator.py` acts as a watchdog process, monitoring the PIDs of all watchers and auto-restarting any that exit with a non-zero code. Watchers catch and log exceptions broadly to stay alive across transient failures.\n\n**Not yet implemented** (roadmap, not current behavior): exponential backoff on retried API calls, and automatic quarantine of a task into an `ALERT_HUMAN.md` file after repeated failures. If you build these, they'd slot naturally into the watcher poll loops and `approval_watcher.py`.\n\n---\n\n## Troubleshooting / FAQ\n\n**Gmail OAuth fails with \"Access blocked: has not completed the Google verification process\" / Error 403.**\nYour Google Cloud OAuth app is in \"Testing\" mode, which only allows explicitly allow-listed accounts to log in. Go to [Google Cloud Console](https://console.cloud.google.com) → APIs & Services → OAuth consent screen → Test users → add the Gmail address you're trying to authorize, then retry.\n\n**Telegram bot never sends notifications, even though the token/chat ID are correct.**\nTelegram is intermittently blocked at the network/ISP level in some regions (Pakistan's PTA, for one). Check with `curl -sS -o /dev/null -w \"%{http_code}\\n\" https://api.telegram.org` — if it hangs or times out, that's the cause, not a bug. The watcher degrades gracefully (retries automatically, doesn't crash) — if you need a channel that works right now, set up the Discord bot as a redundant path (both are supported side by side; see `CONTRIBUTING.md`).\n\n**Discord bot connects but \"Request Changes\" text replies don't get picked up.**\nThe bot needs the **Message Content Intent** enabled in the [Discord Developer Portal](https://discord.com/developers/applications) (Bot tab) — Discord doesn't let a bot read message content by default. Buttons (Approve/Reject) still work without it; only free-text replies need it.\n\n**Scheduled task runs on Windows but nothing seems to happen.**\nCheck `vault/Logs/scheduler.log` first — it logs every run's outcome. If you see `%1 is not a valid Win32 application`, that's a known Windows quirk with how `opencode` resolves (fixed as of this repo's current `run_agent.ps1`, but worth checking if you've forked/modified it).\n\n**I get duplicate task files / the same event processed twice.**\nAlmost always means two orchestrator processes are running at once (e.g. from overlapping scheduled runs). Check with `Get-CimInstance Win32_Process -Filter \"name='python.exe'\" | Where-Object { $_.CommandLine -match 'orchestrator.py' }` — you should see exactly one. `run_agent.ps1` uses a named Mutex to prevent this, but if you're invoking `orchestrator.py` manually alongside the scheduled task, you can still hit it.\n\n---\n\n## Contributing\n\nIssues and PRs welcome — see [`CONTRIBUTING.md`](./CONTRIBUTING.md) for dev setup, where things live, and a list of good first contributions (the Odoo safety gate is the highest-value one). Licensed under MIT — see `LICENSE`.\n"}