AI员工自动化管理工具

一款本地优先、代理驱动的AI员工工具,可自动管理电子邮件、社交媒体和业务任务,所有敏感操作需经人工批准。

  • by SirHamza
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 SirHamza/gold-tier

使用说明

Personal AI Employee — Gold Tier

Your life and business on autopilot. Local-first, agent-driven, human-in-the-loop.

Tier: Gold | Built with Claude Code + Obsidian + Python + Node.js MCP

A Digital FTE (Full-Time Equivalent) AI agent that autonomously manages email, WhatsApp, LinkedIn, Twitter/X, Facebook, Instagram, Odoo ERP accounting, and business tasks — 24/7, with human approval for all sensitive actions.


Architecture

A closed loop: the system perceives external events, remembers them as markdown, reasons over them with Claude, asks a human before anything sensitive, acts through MCP servers, and records every step back into memory.

flowchart TB
    S["Gmail · WhatsApp · LinkedIn · Twitter/X<br/>Facebook/Instagram · Bank · Filesystem"]

    W["Perception Layer — 7 Python Watchers<br/><i>base_watcher.py: polling · dedupe · backoff</i>"]

    V["Memory — Obsidian Vault<br/><i>markdown + frontmatter</i><br/>Tasks · Plans · Handbook · Accounting"]

    O["orchestrator.py<br/><i>dispatch · HITL routing · watchdog</i>"]

    C["Claude Code + 10 Agent Skills<br/><i>reason → plan → act</i>"]

    H["stop_hook.py<br/><i>Ralph loop — keeps working<br/>until the task is actually done</i>"]

    G{"Human Approval Gate<br/>sensitive actions only"}

    M["Action Layer — 5 MCP Servers<br/>email · linkedin · twitter · facebook · odoo"]

    A["audit_logger.py<br/><i>90-day retention</i>"]
    R["retry_handler.py<br/><i>exponential backoff<br/>+ graceful degradation</i>"]
    D["Web Dashboard<br/><i>localhost:8765</i>"]

    S --> W --> V --> O --> C
    C <--> H
    C --> G
    G -->|approved| M
    G -->|rejected| V
    M --> R --> A
    A --> V
    V --> D

    classDef src fill:#0d1117,stroke:#2f81f7,color:#c9d1d9
    classDef mem fill:#0d1117,stroke:#8957e6,color:#c9d1d9
    classDef gate fill:#0d1117,stroke:#d29922,color:#f0d58a,stroke-width:2px
    classDef act fill:#0d1117,stroke:#3fb950,color:#c9d1d9
    classDef obs fill:#0d1117,stroke:#6e7681,color:#c9d1d9

    class S,W src
    class V,O,C,H mem
    class G gate
    class M act
    class A,R,D obs

The loop that matters: nothing reaches the outside world without passing the approval gate, and every action that does pass is written back into the vault. The agent's memory and its audit trail are the same artifact — which is why you can read what it did in plain markdown, and why a rejected action teaches it just as much as an approved one.


Design Decisions

Five choices shaped this system. Each one bought something and cost something.


1 · The filesystem is the state machine

Chosen: a task is a markdown file, and its state is which folder it sits in. Needs_Action -> In_Progress -> Pending_Approval -> Approved / Rejected -> Done.

Given up: transactions, queries, concurrent writers, and anything resembling a schema. There is no database, so there is no SELECT.

Why: because it makes the approval gate mv. Approving an action is moving a file from Pending_Approval to Approved — which works in Obsidian, in Finder, over SSH, or on a phone with a synced folder. No custom approval UI has to exist, and none can break. The dashboard at localhost:8765 is a reader of that state, not the owner of it; delete the dashboard and the system still works.

The cost is real: two watchers writing the same task at the same moment would race, and there is no migration path if the frontmatter shape changes. At single-operator scale that trade is worth it. At team scale it would not be.


2 · Approval is a gate, not a notification

Chosen: sensitive actions stop at Pending_Approval and stay there. orchestrator.py only dispatches out of Approved, so nothing reaches the outside world without a human having physically moved the file.

Given up: speed. The agent cannot finish an email at 3 AM; it can only prepare one.

Why: an agent with your Gmail token, your LinkedIn account and your Odoo ledger is not a productivity tool — it is a liability surface. The failure mode of "notify the human afterwards" is an apology to a client. The failure mode of "wait for the human" is a delay. Delays are recoverable.

DRY_RUN defaults to true in orchestrator.py and independently inside all five MCP servers. That duplication is deliberate: a bug in the orchestrator still cannot cause a real send, because the server it calls is also refusing. Two locks, one key — and CI asserts that every server still has its lock, because two of them once did not.


3 · Actions go through MCP servers, not inline API calls

Chosen: each integration is a separate Node process speaking MCP. orchestrator.py holds a routing table (action_type -> server + skill) and shells out.

Given up: simplicity and latency. Five npm installs, five processes, and a subprocess hop that an inline requests.post() would not need.

Why: credential isolation and blast radius. The Twitter server only ever receives Twitter credentials; a bug in it cannot touch the Odoo ledger. Each server is testable alone, replaceable alone, and usable by Claude Code directly without the orchestrator running at all. When an integration breaks, exactly one process is suspect.

Unknown action_type values fall back to a generic Claude prompt rather than raising — an unrecognised action degrades into "a human-readable instruction" instead of a crash.


4 · Memory is markdown, and it is the same artifact as the audit trail

Chosen: the vault is plain markdown with YAML frontmatter, readable in Obsidian. The agent's working memory and its record of what it did are one directory tree.

Given up: query performance, and any guarantee that a human editing the vault mid-run will not confuse the agent.

Why: you can audit it by hand. When an autonomous agent has acted on your behalf for a week, the question is never "what does the database say" — it is "show me what it actually did, in a form I can read without your tooling." A JSON audit log in Postgres answers that badly; a folder of dated markdown answers it in a text editor, five years from now, with no dependency on this project still existing.

Retention is 90 days by default and purge_old_logs() only deletes files matching YYYY-MM-DD.json — audit_summary.md and the health state survive a purge on purpose.


5 · Watchers poll; they do not receive webhooks

Chosen: each of the seven watchers polls on an interval, inheriting the retry-safe loop in base_watcher.py.

Given up: latency. A webhook is instant; a 30-second poll averages 15 seconds behind.

Why: webhooks require a public endpoint, which requires a server, a domain, TLS, and an inbound hole in the network. This system is designed to run on the operator's own machine with no inbound connectivity at all. Polling is the price of that, and 15 seconds is not a meaningful delay for triaging an inbox.

The loop's guarantee matters more than its latency: one failing poll never kills the watcher. base_watcher.run() catches per-cycle exceptions and continues, and tests/test_base_watcher.py asserts exactly that. A watcher that dies silently is worse than one that never started, because the operator believes it is still running.


Silver Tier is the same architecture with a smaller surface — 4 watchers, 2 MCP servers, 7 skills, no audit logger and no retry handler: SirHamza/silver-tier-complete.

These are the trade-offs as the code makes them. Where a decision no longer fits — team scale, higher volume, an integration that genuinely needs webhooks — the section above is also the list of what to revisit first.


What It Looks Like Running

The dashboard reads the Obsidian vault directly. Every number above comes from markdown files on disk — there is no database and no hidden state, which is what makes the agent's memory auditable by hand.

Full view — activity log, active plans, briefings and the 10 agent skills

Note the two post_linkedin rows in the activity log: a 429 rate limit marked error, followed by recovered on attempt 3 marked success. That is orchestrator/retry_handler.py doing exponential backoff — the failure is recorded rather than hidden, which is the whole point of the audit trail.

Reproduce this yourself in under a minute — see Quick Start below. Screenshots use sample data from demo/seed_demo.py; no credentials involved.


Gold Tier Features

Feature Implementation
Full cross-domain integration Personal (email, WhatsApp) + Business (social, accounting)
Odoo Community ERP mcp_servers/odoo_mcp/ — JSON-RPC invoicing + accounting
Facebook/Instagram mcp_servers/facebook_mcp/ + watchers/facebook_watcher.py
Twitter/X mcp_servers/twitter_mcp/ + watchers/twitter_watcher.py
Finance Watcher Bank CSV drops + API polling → alerts for large transactions
Ralph Wiggum Stop Hook hooks/stop_hook.py + .claude/settings.json
Audit Logging (90-day) orchestrator/audit_logger.py — JSON logs + markdown summary
Error Recovery orchestrator/retry_handler.py — exponential backoff + graceful degradation
5 MCP Servers email, linkedin, twitter, facebook, odoo
10 Agent Skills 7 Silver + post-twitter, post-facebook, odoo-accounting

Quick Start

Three levels. Level 0 needs nothing but Python and takes under a minute.

Level 0 — Demo mode (no credentials, no cost)

git clone https://github.com/SirHamza/gold-tier.git && cd gold-tier
pip install python-dotenv

python demo/seed_demo.py       # sample vault data, clearly marked
python dashboard/server.py     # http://localhost:8765

Nothing here touches a network service or needs an API key. Remove the sample data with python demo/seed_demo.py --clean.

Level 1 — Check what you have

python scripts/check_setup.py

Reports which runtimes, packages and credential groups are present, and tells you what demo and live mode can currently do. It never prints a secret value, only whether one is set.

Level 2 — Live mode

Prerequisites

Need Install
Python 3.10+ pip install -r requirements.txt
Node.js 18+ required by the five MCP servers
Claude Code npm install -g @anthropic/claude-code
PM2 (optional) npm install -g pm2 — process supervision
Odoo 16+ (optional) self-hosted, for the accounting skill
pip install -r requirements.txt
for d in email linkedin twitter facebook odoo; do
  (cd "mcp_servers/${d}_mcp" && npm install)
done

Configure

cp .env.example .env

Two variables matter before anything else:

# Absolute path to this clone. The five MCP servers resolve their entry
# points from it, so nothing starts until this is correct.
AI_EMPLOYEE_ROOT=/absolute/path/to/gold-tier

# Safety switch. While true, every outbound action is logged but NOT sent.
# Leave it on until you have watched a full cycle in the dashboard.
DRY_RUN=true

Everything else is optional and independent. Configure only the channels you want — an unconfigured watcher stays idle rather than failing, so you can start with Gmail alone and add the rest later.

Run

pm2 start scheduling/pm2.config.js && pm2 save     # supervised
# or run pieces by hand:
python orchestrator/orchestrator.py
python watchers/gmail_watcher.py
python dashboard/server.py

Then open http://localhost:8765 and re-run check_setup.py to confirm the feature groups you configured now report ready.

Agent skills

claude /process-inbox                   # triage everything in Needs_Action
claude /ceo-briefing                    # morning business briefing
claude /send-email                      # dispatch an approved email
claude /post-linkedin "Your post text"
claude /post-twitter "Tweet text"
claude /post-facebook "Post text"
claude /odoo-accounting summary
claude /create-plan "Task description"  # turn a task into PLAN_*.md
claude /weekly-audit                    # revenue + subscription + Odoo audit
claude /ralph-loop "<task>" --completion-promise "DONE" --max-iterations 10

Scheduled tasks (Windows)

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
.\scheduling\setup_windows_scheduler.ps1
# CEO Briefing (Mon-Fri 8am) + Weekly Audit (Sun 11pm)

The script resolves the project root from its own location, so it works wherever you cloned the repo. macOS and Linux use scheduling/setup_cron.sh.


Tests

pip install -r requirements-dev.txt
python -m pytest

43 tests covering the three files the whole system leans on:

Module What is asserted
orchestrator/retry_handler.py exponential backoff schedule and its max_delay cap, that PermanentError is never retried, that MaxRetriesExceeded fires only after the last attempt, and that GracefulDegradation falls back instead of raising
orchestrator/audit_logger.py entry schema, one file per day, the approval trail records request and approval as two entries, and that retention purges dated logs without touching audit_summary.md or the health state
watchers/base_watcher.py the abstract contract, that Needs_Action is always created, and that a failing poll never kills the loop — the guarantee all seven watchers depend on

Retry tests patch time.sleep and assert the recorded delay schedule instead of waiting on it, so the whole suite runs in well under a second.

tests/test_module_imports.py exists because of a real bug: retry_handler.py called os.getenv() at module scope while import os sat twenty lines below it. The module raised NameError on import, and because orchestrator.py guards that import with except ImportError — which does not catch NameError — the orchestrator crashed on startup instead of degrading. An import is the cheapest test there is.


Project Structure

AI_Employe/
├── AI_Employee_Vault/           # Obsidian vault (GUI + long-term memory)
│   ├── Dashboard.md             # Real-time status
│   ├── Company_Handbook.md      # AI rules of engagement
│   ├── Business_Goals.md        # KPIs and revenue targets
│   ├── Needs_Action/            # Items awaiting Claude
│   ├── Plans/                   # PLAN_*.md + RALPH_STATE_*.json
│   ├── Pending_Approval/        # Actions awaiting human approval
│   ├── Approved/                # Move files here to authorize
│   ├── Rejected/                # Move files here to cancel
│   ├── Done/                    # Completed task archive
│   ├── Logs/                    # JSON audit trail (90-day retention)
│   ├── Briefings/               # Monday CEO briefings
│   ├── Content_Queue/           # Social media post drafts
│   ├── Finance_Drop/            # Drop bank CSVs here for processing
│   └── Accounting/              # Financial data + Odoo sync
├── watchers/                    # Python perception scripts (× 7)
│   ├── base_watcher.py          # Abstract base class
│   ├── gmail_watcher.py         # Gmail API
│   ├── whatsapp_watcher.py      # Playwright WhatsApp Web
│   ├── linkedin_watcher.py      # LinkedIn API
│   ├── filesystem_watcher.py    # Local file drops
│   ├── finance_watcher.py       # Bank CSV + API (Gold)
│   ├── twitter_watcher.py       # Twitter mentions + keywords (Gold)
│   └── facebook_watcher.py      # Facebook/Instagram comments (Gold)
├── orchestrator/                # Master process
│   ├── orchestrator.py          # Folder watcher + MCP dispatcher
│   ├── watchdog.py              # Process health monitor
│   ├── audit_logger.py          # 90-day audit logging (Gold)
│   └── retry_handler.py         # Exponential backoff + degradation (Gold)
├── mcp_servers/                 # External action servers (× 5)
│   ├── email_mcp/               # Gmail OAuth2 (send, draft, list)
│   ├── linkedin_mcp/            # LinkedIn REST API
│   ├── twitter_mcp/             # Twitter API v2 (Gold)
│   ├── facebook_mcp/            # Facebook Graph API + Instagram (Gold)
│   └── odoo_mcp/                # Odoo JSON-RPC ERP (Gold)
├── hooks/                       # Claude Code hooks (Gold)
│   └── stop_hook.py             # Ralph Wiggum Stop Hook
├── dashboard/                   # Web Dashboard UI
│   ├── server.py                # Python HTTP server + JSON API
│   └── index.html               # Real-time web dashboard
├── skills/                      # Agent Skill descriptors (× 10)
│   ├── process-inbox.md
│   ├── ceo-briefing.md
│   ├── post-linkedin.md
│   ├── post-twitter.md          # Gold
│   ├── post-facebook.md         # Gold
│   ├── send-email.md
│   ├── create-plan.md
│   ├── weekly-audit.md
│   ├── ralph-loop.md
│   └── odoo-accounting.md       # Gold
├── .claude/
│   ├── commands/                # Claude Code slash commands (× 10)
│   └── settings.json            # Stop hook registration (Gold)
├── scheduling/
│   ├── pm2.config.js            # PM2 (all 10 processes)
│   └── setup_windows_scheduler.ps1
├── .mcp.json                    # 5 MCP server registrations
├── .env.example                 # Full credential template
└── PLAN.md                      # Development roadmap (Gold complete)

Human-in-the-Loop (HITL) Workflow

1. Claude reads Needs_Action file
2. Claude creates: Pending_Approval/APPROVAL_*.md
3. Review in Obsidian or Dashboard UI (http://localhost:8765)
4. Move to /Approved  → Orchestrator dispatches via correct MCP server
   Move to /Rejected  → Action cancelled, logged

Actions that ALWAYS require approval:

  • Emails to new contacts / bulk sends
  • LinkedIn / Twitter / Facebook / Instagram posts
  • Odoo invoice confirmation (posting to ledger)
  • Payments > $50 or any new payee
  • Finance alerts flagged by Finance Watcher

Ralph Wiggum Stop Hook

The stop hook (hooks/stop_hook.py) intercepts Claude's exit signal:

Claude starts a ralph-loop task
→ Creates RALPH_STATE_<id>.json in /Plans
→ Works on task
→ Tries to exit
→ Stop hook checks: is task file in /Done?
   YES → Allow stop (complete)
   NO  → Block exit, increment iteration, Claude continues
→ Max iterations → creates INCOMPLETE_<task>.md alert

Registration: .claude/settings.json → hooks.Stop


Odoo Community ERP Integration

Odoo (local, http://localhost:8069)
    ↕ JSON-RPC 2.0
Odoo MCP Server (mcp_servers/odoo_mcp/)
    ↕
Claude Code + /odoo-accounting skill

Tools: create_invoice, confirm_invoice (HITL),
       create_customer, list_invoices, list_products,
       get_accounting_summary (month-by-month P&L)

Weekly audit automatically pulls Odoo accounting summary for CEO Briefing.


Audit Logging

Every action is logged to Vault/Logs/YYYY-MM-DD.json:

{
  "timestamp": "2026-02-20T10:30:00",
  "action_type": "send_email",
  "actor": "claude",
  "target": "client@example.com",
  "parameters": {"subject": "Invoice #123"},
  "approval_status": "approved",
  "approved_by": "human",
  "result": "success"
}
  • 90-day retention — audit_logger.purge_old_logs() auto-runs weekly
  • Weekly summary → Vault/Logs/audit_summary.md

Security

Measure Implementation
Credentials .env file (gitignored), never in vault
Default mode DRY_RUN=true — no real actions until you're ready
Payments Always require human approval, never auto-execute
Odoo write ops All invoice posting / customer creation requires approval
Audit trail 90-day JSON logs in Vault/Logs/
Rate limiting Max 10 emails/hr, max 3 payments/day
Sessions WhatsApp session in sessions/ (gitignored)
Finance alerts Large transactions (>$200) → Needs_Action alert

Where This Sits

Four capability tiers, built in order. Each one is a working system on its own, not a stage of an unfinished one.

Tier Scope Status
Bronze Vault + watchers + Claude reading and writing markdown shipped
Silver 4 watchers · 2 MCP servers · HITL approval · dashboard shipped
Gold (this repo) 7 watchers · 5 MCP servers · Odoo ERP · audit logging · retry + graceful degradation · Ralph loop shipped
Platinum Cloud/local split, always-on hosting, agent-to-agent delegation not started

Silver is the one to read first if you want the architecture without the integration surface. Gold is the one to read if you want to see how it holds up once there are five external services, an ERP ledger and a 90-day audit trail involved.


Author

Hamza Saifuddin — AI Architect · Agentic Systems · Karachi, PK

Portfolio · GitHub · LinkedIn · hamzasaifuddinh@gmail.com

Licensed under MIT — use it, fork it, build on it.