README.en.md

September 21, 2026 · View on GitHub

OpenWorkBuddy

OpenWorkBuddy

An AI office assistant that runs on your own machine.
Ask for something once; it plans, does the work, checks it, and leaves a real
PPT / Word / Excel / web page on your disk — a file you can open, not a chat log.

中文 · English

▶ Run it in three minutes  ·  Download  ·  Feature list (zh)  ·  Docs  ·  Feishu group  ·  Changelog

Star License Skills Tools Connectors Experts

Free for personal, learning and non-profit use. Commercial use needs a license — one sentence below ↓

OpenWorkBuddy demo: say what you need, the agent does the work and hands you real files


You say it, it hands you the file

You sayYou get
"Build a Q3 review deck from this spreadsheet"reads → computes → a .pptx you can present
"Research AI companion apps in China, write a report"searches → reads each page → Markdown / Word
"Turn this material into a page I can read on my phone"writes HTML → serves it locally → scan the QR
"Every day at 9, collect industry news and send it to me on Feishu"cron + IM push; missed runs catch up

Ask once; OpenWorkBuddy plans, executes and verifies, and hands back PPTX / DOCX / XLSX / HTML files

Note

Also: parallel tasks, goal-based acceptance, 👍👎 feedback that feeds self-evolution, two-layer memory, permission tiers, remote control over Feishu / WeChat, a desktop pet… Full list (Chinese): 功能清单.

Why this one

📄 The files are real.

Decks, documents, spreadsheets and pages are actually generated — open them from the output panel and check. Claim a file was written when it isn't on disk and the run gets stopped and redone.

🔌 Swap models freely; everything stays yours.

DeepSeek / Qwen / GLM / Kimi / OpenRouter / Ollama switch with one click. Already have Claude Code or Codex on this machine? Use it as the engine — no second token bill. Sessions, files and keys never leave your disk; it listens on 127.0.0.1 by default.

🧩 Adding a capability = dropping one Markdown file.

Save it as skills/<name>/skill.md and it's live on the next task — no code, no restart, no build.

🔍 It's also a readable agent.

Model routing, tool calls, file acceptance, memory, permissions and local traces all live in one repo: for any real task you can see why it did what it did, which model it used, and what it finally handed over.

Run it in three minutes

All three routes are the full product; none of them is a cut-down edition.

macOS, one line (downloads, installs into /Applications, strips the quarantine flag, opens it):

curl -fsSL https://raw.githubusercontent.com/CatCatUncle/openworkbuddy/main/install-mac.sh | bash

⚠️ If you download the dmg by hand, the first launch will be blocked: "OpenWorkBuddy" Not Opened — Apple could not verify …, with only Done and Move to Trash on the dialog. That is Apple's blanket block on apps without a paid certificate, not a verdict about this build — the certificate is being applied for, and this step disappears once it comes through. Click Done → System Settings → Privacy & Security → scroll to the bottom → Open Anyway → enter your login password. Once, and never again. The curl line above has no dialog at all. Full three-route walkthrough below, under "Your OS blocks the first launch".

Windows / manual download: grab -win-setup.exe from Releases (one installer for x64 and ARM64) and double-click; on a locked-down work machine take the portable build, -win-x64-portable.exe (arm64 on ARM).

From source (Node.js 18+, no build step, no framework — edit, refresh, done):

git clone https://github.com/CatCatUncle/openworkbuddy.git
cd openworkbuddy && npm install
npm run app # desktop app; or `npm start` and open http://localhost:3800

Paste a model API key on first launch, then type something like "make a slide deck introducing OpenWorkBuddy". Everything you own lives in ~/OpenWorkBuddy — config, sessions, output files, skills. Uninstalling doesn't delete it; moving machines is a folder copy.

Text too small, or want a different skin? Avatar menu, top right → Appearance: four text sizes, five themes and UI density all live on that page.

Your OS blocks the first launch · double-clicked and nothing happened

The code-signing certificate is still being applied for (Apple charges $99/year, Windows a few thousand), so today's builds are ad-hoc signed. What the OS blocks is "I have never seen this developer"not "this file is malware". The signature inside the build is intact; codesign --verify --deep --strict confirms it.

macOS — pick one of three

  1. Without touching a terminal (recommended): double-click → click Done on the dialog (not Move to Trash) → open System Settings → Privacy & Security → scroll all the way down to the Security section, where it says "OpenWorkBuddy" was blocked to protect your Mac → click Open Anyway → enter your login password → confirm with Open. Once, and never again.
  2. One command: first drag the .app out of the dmg into Applications (the dmg is a read-only volume, so running this inside it fails), then
    xattr -dr com.apple.quarantine /Applications/OpenWorkBuddy.app
    
  3. No dialog at all: use the curl line at the top. A browser-downloaded file gets tagged com.apple.quarantine; a curl-fetched one doesn't, so Gatekeeper never enters the picture.

Don't follow the old "right-click → Open" tutorials. That route only works on macOS 14 and earlier — Apple removed it in macOS 15 (Sequoia), and the right-click dialog no longer has a second Open button, which is exactly why it reads as "it just won't open".

If the message says "is damaged and can't be opened" rather than could not be verified, the signature really was corrupted — cloud drives, sync folders and some unzip tools all do this. Download again, or re-sign in place with codesign --force --deep --sign - /Applications/OpenWorkBuddy.app.

Windows: in the SmartScreen dialog click the small grey "More info" → "Run anyway".

  • Nothing happened: the boot log is at ~/OpenWorkBuddy/logs/boot.log — wherever it stops is the problem. Running from source, try node cli.js doctor first. Walk-through → 安装与启动 (Chinese)

Mirrors, port conflicts, moving the data directory → 安装与启动 | moving machines → 数据同步与搬家 (Chinese)

What it looks like

"Same person, four different scenes, holding a hand-written sign — make it look like a snapshot, not an AI render."

The same person at a cafe window, on a rainy night street, at an office desk and in a morning bedroom, each holding a wooden sign reading 关注 OpenWorkBuddy 项目

The hard part isn't drawing a person — it's keeping the same person across all four and the Chinese on the sign legible. So it generates one, then actually looks at what it just made (a real vision call on its own output, not a claim from memory), and fans the rest out from there.

"Build me a Hunan travel guide site — all 14 prefectures, no skipping."

Hunan travel guide: the ink-wash landing screen, and the index of all 14 prefectures grouped by region

https://hunan-travel.pages.dev/ — it's live, go click around. One HTML file plus a folder of images, no external CDN. Drop it on any static host and it's a site. Not a mockup — the thing it actually handed over.

"Every morning at seven, send me today's weather and what I should watch out for, on Feishu."

A scheduled OpenWorkBuddy task pushing a morning briefing to Feishu: today's weather and UV, tomorrow's rain, plus two things worth doing today

One sentence set this up. It runs whether or not anyone is at the machine, and every run keeps its full transcript under Automation → Run history. Feishu / WeCom / DingTalk / Telegram all take the same path.

How it pulled those off → 三个案例,拆开讲 (Chinese, but the screenshots speak for themselves)

AI short-drama infinite canvas

Script, characters, scenes, shots, reference images, video, voice and the edit timeline all sit on one canvas. The wires aren't decoration — they are what the next generation actually reads for character, first frame and sound. Change one shot and only that shot re-runs.

OpenWorkBuddy infinite canvas: character sheet, location plate and shot first-frames on one board, with purple wires labelled 「生成」 pointing at what the next generation actually reads

Open "Infinite canvas" in the left sidebar. Drag empty space to pan, Shift+drag to marquee-select, Shift/+click to add or drop nodes from the selection, and @ any node or asset from the chat box at the bottom.

Put it on a server for your team

One command on a clean VPS that already has Docker:

git clone https://github.com/CatCatUncle/openworkbuddy.git && cd openworkbuddy
bash deploy.sh --domain buddy.example.com # automatic HTTPS, reachable from outside

It waits for the health check to actually pass before claiming success; if it won't start you get the logs. All data sits in ./openworkbuddy-data.

Important

Register the admin account first thing. The first account to register becomes the super admin (one per org, transferable but never issuable), and self-registration closes right after. An empty instance on a public IP means whoever gets there first owns it.

One process serves several companies, invisible to each other. Avatar menu → Admin console: orgs, seats, usage, security policy. New hires are created from a department template (role and monthly credits in one go); when someone leaves, one click closes five doors at once — paired devices, their scheduled jobs (the scheduler doesn't go through the login gate, so disabling the account alone leaves them running on the company's credits), unused invite codes, 2FA, and tasks still running. Revoke access, keep the data, and you get a receipt you can paste into the handover doc.

One metrics snapshot per minute, threshold breaches pushed to WeCom / DingTalk, and /api/ops/metrics.prom for your existing monitoring — behind the platform-owner check like every other endpoint.

Reverse proxy, upgrades, migration, security checklist → 部署 | deploy/README.md | 多人协作 (Chinese)

Models

Settings → Models: pick a provider preset (OpenAI / Anthropic / OpenRouter / Volcano Ark / Bailian / DeepSeek / GLM / Kimi / Ollama), the base URL and protocol are filled in, paste a key, save — hot reload, no restart. A mispasted key is caught on save and it tells you which character is wrong, instead of handing you an unreadable 401 later. Reasoning models can have thinking turned off or dialed down from the UI.

Image / speech / video models have their own table; video spans five protocols (Tongyi Wanxiang · Volcano Ark Seedance · GLM CogVideoX · MiniMax Hailuo · SiliconFlow), and if it cannot tell which vendor it is, it does not send the request — video bills per clip and a wasted call takes minutes to fail.

Per-provider table → 配置模型 (Chinese)

Important

config.json is the only file holding API keys and is already in .gitignore. Don't commit it.

Command line

openworkbuddy shares one set of config, skills, memory, connectors and sessions with the desktop app — start something in the terminal and you can watch it and chime in from your phone; stop halfway on the desktop and openworkbuddy resume picks it up.

npm link # once: install the global command (or just run `node cli.js …`)

openworkbuddy "write my weekly report" # one-shot: runs and exits
openworkbuddy # interactive: type / for the command menu
cat error.log | openworkbuddy "what is this" # pipe: stdin becomes material
openworkbuddy -q "write my weekly report" > report.md # just the report, no progress bars

One-shot and pipe mode never ask you questions, so scripts and cron don't hang. Exit codes mean something: 0 success, 1 task failed, 2 bad arguments, 130 Ctrl+C — so openworkbuddy doctor && npm start stops a misconfigured machine before it starts.

sessions / resume / engines / doctor / pair (QR-pair your phone) / worktree, plus --mode --perm -C -f --json and the rest → 命令行用法 (Chinese)

How it's put together

flowchart TB
 subgraph Entry["Your devices"]
 Desktop["Desktop / Web"]
 CLI["openworkbuddy CLI"]
 IM["Feishu / WeChat and other remote entries"]
 end

 Entry --> Runtime["OpenWorkBuddy local runtime\nsessions · permissions · projects · API"]
 Runtime --> Agent["Agent orchestration\nplanning · tool calls · file acceptance"]
 Agent <--> Models["Model routing\ncloud LLM / Ollama / Claude Code / Codex"]
 Agent <--> Capabilities["Capabilities\nMarkdown Skills · experts · MCP · plugins"]
 Agent <--> Workspace["Local workspace\nfiles · assets · project context · memory"]
 Agent --> Canvas["Executable infinite canvas\nscript · characters · shots · assets · timeline"]
 Agent --> Trace["Local trace\nmodel · tools · latency · tokens · I/O"]
 Trace -. optional .-> Langfuse["Langfuse"]

The diagram doubles as a reading order: start at server.js, then see how agent.js orchestrates models and tools. Details → 实现细节 (Chinese)

What's new

  • Sep 21 Search knew three vendors — Jina, Tavily, Brave — so users in China had to tunnel out first: eight now, domestic ones first — Bocha, Zhipu, Qiniu, then Tavily / Serper / Jina / Brave, plus a custom slot (POST a JSON, get an array back; your own SearXNG works). It falls through however many you configured when one is down, and only then to the keyless free channel; the bill records the vendor that actually answered, not the one picked in settings.
  • Sep 21 A turn whose process died mid-run spins "running…" in the history forever, with nothing anywhere to stop it: replay closes a turn when it reaches the matching answer record, so a question with no answer after it never gets an end drawn — and at that point the session is not in runningSessions, so there is no stop button on screen either. It now closes as interrupted: "Interrupted · 1 step", with the reason on the header.
  • Sep 21 A fork you already answered asks again every time you open that conversation: the done class carried two meanings at once — "not clickable any more" and "the verdict is already painted". Replay set it for the first and thereby blocked the second. Split into two marks, the same conversation replays as "You settled this fork · you chose …".
  • Sep 21 In English, every “Delete” confirmation still comes up in Chinese: all 31 of them used the native confirm(), and translation walks the DOM — the sentence inside a native dialog is only ever a JS string, never enters the DOM, and no on-screen gate can see it. Two side debts: tick “prevent this page from creating additional dialogs” and confirm() silently returns false, muting every delete button; and a native modal can't be clicked offscreen, so none of those 31 paths had been tested. They all use the app's own dialog now — a verb on the red button, focus on “Never mind”, and the things about to go listed one per line (height-capped and scrolling, because a dialog pushed off screen takes “Never mind” with it)
  • Sep 21 Create a folder, then go looking for a way to delete it — there isn't one: delete only existed in the list layout; icon and gallery set display: none on it and search results never drew it. All three layouts have it now, search included, and standing inside a folder puts "Delete this folder" next to "New folder" — deleting the one you're in walks you back up. Workspace output still gets none: that's what a task wrote in the working directory. On a non-empty folder the button now reads "Open and empty it" instead of "Got it", and takes you in
  • Sep 21 Switch the workbench to English, open the admin console, and it's still all Chinese: the console never loaded i18n.js. 494 dictionary entries + 28 patterns, a 中文 / English switch in the sidebar, and names the user chose (organizations, departments, channels, models) stay untranslated — they're data, not UI. Numbers follow the language, and switching repaints the page, since the 万 bucket and thousands separators are computed at render time
  • Sep 21 Hold a card mid-drag, let a sync land, and the card snaps back: same root cause as the next entry (applying a snapshot rebuilds the whole graph). Sync now waits for typing and dragging, timed from your last movement, and a drag released outside the window can't stall it
  • Sep 21 Type on the canvas, let a sync land, and the half-sentence you just typed is gone: the inspector is rebuilt wholesale, so focus falls back to the body, the rest of what you type goes nowhere, and the node's text is overwritten by the incoming copy. Sync now waits while you type and resumes 10s after your hands stop; a rebuild puts the caret back on the same character
  • Sep 21 Deleted edges came back on a sync, a reload, or an undo: "keep my edges if the incoming snapshot has none" and "one shot plus one named location, so draw the link back in" were meant to protect older boards, but "no edges" can also mean the user just deleted them. Boards now save as version 2 — edges recorded as they are, empty means empty; version 1 files still get inferred links, and one delete upgrades them
  • Sep 21 Deleted boards came back from the dead; emptied boards grew cards on their own: deleting a board only removed the server's copy, so creating one with the same name brought the deleted cards back and saved them again; and the two starter cards were seeded whenever the board "is empty right now", so a board you cleared yourself regrew them on every open. Deleting or creating a board now clears the local copy too, and starter cards are only for a board nobody has ever touched — a new board keeps updatedAt: 0, and every save after that (clearing included) stamps the time
  • Sep 20 Open another project and the canvas showed the previous project's cards: the local copy was keyed by board name only, so both projects' main shared one slot, and the next save overwrote the new project's own canvas; same for switching boards, where the save waits 240ms and only then reads which board is current. The key now carries the project, a pending save is flushed before any switch, and every write re-checks who it was meant for
  • Sep 20 Three silent data losses on the infinite canvas: nodes titled 「开始工作」 or 「开始创作」 were dropped on every load and sync, edges with them (3 nodes + 2 edges in, 1 node and 0 edges out, in the local copy and on the server both); a snapshot pulled from the server was written straight back, so two open tabs shove each other every 1.8s and copy a .bak each time; and select 3 nodes, sync once, and only 1 is still selected — the next Delete removes something else. The canvas had no tests at all; the new test/canvas.js goes 6 pass / 9 fail to 16 / 0

Older entries → Changelog.

⚠️ This agent has a shell

Warning

It runs commands, reads and writes files and reaches the network — so the gates are real: command approval, a file blacklist, a URL allowlist, audit logs and four permission tiers. Read 安全 (Chinese) before exposing it to the internet; the defaults are tuned for local use only.

Skills get screened before they're installed. A skill is a set of instructions written for an agent, handed to something that can run commands on your machine — unlike npm install, where a package only runs when you require it; a skill is read and followed on its own. So an install runs 34 static rules first and shows you what it found, in three buckets: install / look first / don't install by default (no score — a score just teaches people that "42 looks fine"). Ten of the rules actually block (reverse shells, curl | bash, reading SSH private keys, wiping disks, erasing traces); an admin can force past them, and that goes into .install.json.

It is not antivirus. On a public labelled set, pure static rules catch about three quarters — one in four gets through. Install toolward and it's used as a second ruler automatically, merging in a direction that only ever tightens. And the one that matters more than every rule above: read the skill.md yourself before installing. It's Markdown, not a binary.

How the call is made, and why the force-install hatch stays → 安全 | 安全基线 (Chinese)

Contributing

  • Something broke? Open an issue, even if it's one line of error text. Scrub your API keys first.
  • 10 minutes — write a skill: one Markdown file at skills/<name>/skill.md, live on save. Template
  • One evening — pick an issue: npm install && npm start runs it, npm test goes green without any API key

Project layout, tests and PR conventions are in CONTRIBUTING.md. No need to open an issue first — send the PR.

Docs

Most docs are in Chinese; the code and comments are the source of truth.

DocWhat's in itDocWhat's in it
功能清单Every capability, skill and tool部署Server / Docker / reverse proxy
案例How the pictures above were made多人协作Multi-tenant, accounts, quotas
安装与启动Installers, source, common snags安全Approval gates, allowlists, audit
配置模型base_url / model names per provider数据同步与搬家Where data lives, moving machines
命令行用法CLI flags, pipes, --json, cron开源与商业版边界What a licence actually buys
扩展Skills, MCP, plugins, experts路线图What's next, what counts as done
IM与定时任务Feishu / QQ / WeCom / WeChat / DingTalk实现细节How the agent loop actually runs
安全基线Where data lands, who can read it, what isn't covered远程访问Reaching your machine from outside; both switches off by default

Also by the same author

  • toolward — a static safety check for agent skills and MCP connectors: 37 rules in six families, zero runtime dependencies, Node 20.10+. Run npm i -g toolward and OpenWorkBuddy picks it up as a second ruler automatically; skip it and nothing changes. Like this project it is PolyForm Noncommercial.

License

In one sentence: personal, learning and non-profit use is free; making money with it (including internal productivity at a company) needs a commercial license from the author. The license is PolyForm Noncommercial 1.0.0; what counts as commercial and how to talk about it is in COMMERCIAL-LICENSE.md.

A license does not unlock features. There is one codebase — this repo — and you are looking at all of it: the agent loop, 40+ tools, the drama canvas, IM remote control, execution traces, self-evolution and memory, multi-tenancy and the admin console included. No feature flags, no trial countdown, no greyed-out buttons. A license buys three other things: the right to make money with it, trademark and white-label room, and someone to reach → 开源与商业版边界 (Chinese)

Some of it isn't even non-commercial. Deployment configs, CI pipelines, scripts, the eval set, skill templates and sample code in the docs are additionally released under MIT → LICENSE-ECOSYSTEM.md. And skills, plugins and connector configs you write are your own work, not derivatives of this project.

This license grants no rights to any third-party product, trademark, logo, brand asset or screenshot; those belong to their respective owners.

Copyright (c) 2026 开发者猫叔

Disclaimer

What this is. OpenWorkBuddy (repo CatCatUncle/openworkbuddy) is an independent open-source project written from scratch by 开发者猫叔; all source is in this repo. Architecture, tool protocol, permission model, memory and self-evolution are original work; projects studied along the way are listed one by one in section 4 of NOTICE.md. The name is Work + Buddy — two ordinary English words — with the Open- prefix common to open-source projects.

Relationship with third parties: none. This project is not affiliated with, authorised, sponsored or endorsed by Tencent or its WorkBuddy product, and contains none of its code, assets, UI resources or non-public information. If "WorkBuddy" is someone's registered trademark, the rights belong to its owner; third-party names appear here only to describe compatibility or draw a factual distinction (nominative use). Feishu, WeCom, QQ and the rest are integrated through their own publicly published open APIs; no reverse engineering is involved.

If a rights holder thinks something here is wrong, reach me through Issues or the contact in COMMERCIAL-LICENSE.md and it will be fixed once verified.

Support this project

That Star button in the top-right corner — press it

Star this repo

Pass it to one colleague who hand-builds decks, weekly reports and meeting notes — worth more than a hundred impressions.

Contributors

Thanks to everyone who has changed something here. Want to join them: CONTRIBUTING.md.

OpenWorkBuddy contributors

Star history

Star History Chart