🔶 qm:面向工作的多人 Agent 运行框架
英文标题:🔶 qm – Multiplayer agent harness for work
QM 是一款面向创业公司的多人 Agent 运行框架,可在 Slack 和 Web 中使用,为员工、频道、群聊及项目提供彼此隔离又可协作的 Agent 工作空间。它支持 Pi、OpenCode、Codex 和 Claude Code 等多种 harness,底层核心不绑定单一模型或供应商,并以 Postgres 持久化会话、记忆和任务状态。QM 提供严格、自动和危险三种安全策略,以及按作用域隔离的沙箱、文件、凭据、定时任务和 Web 应用能力。对开发者而言,项目既支持通过部署仓库配置和发布,也支持维护私有镜像仓库以在保留组织定制内容私密性的同时同步上游代码。
495.7 KB
39.5 KB
中文
一款面向工作的多人 Agent 运行框架。可在 Slack 和 Web 中使用。
大多数 Agent 都被设计为个人助手。你可以让一个 Agent 为整个公司工作,但复杂度会迅速上升。QM 专为创业公司设计。每位员工都有自己的隔离工作空间,可以独立工作而不影响他人;同时,他们也可以在频道、群聊和项目中与 Agent 协作。
每个人和每个房间都拥有各自作用域内的记忆、文件、密钥链视图、权限、定时任务、Web 应用和持久化沙箱。
它以开源为导向构建。你可以选择自己的 harness 和模型,并在它们之间切换——Pi、OpenCode、Codex 和 Claude Code 都驱动同一个核心,因此一次部署不会绑定于单一供应商。
-
个人与共享作用域。 用户可以将 Agent 定制为 自己的 Agent,同时仍可在 Slack 频道和项目中与其协作。
-
Slack 与 Web。 相同的身份和配置可在 Slack 与 Web 应用之间延续。
-
管理员控制。 设置组织级配置、安全策略,以及可用的 harness 和模型。
-
Web 应用。 创建自定义内部应用,并将其发布给合适的人员。
-
共享技能。 技能归作用域所有,可通过授权共享;管理员可审核后将其提升至整个组织,也可从 git 仓库导入技能包。
-
后台工作。 定时任务和监视器会在无人关注时持续运行工作。
-
同时搜索内部笔记、电子邮件、文档、数据库和 Web
-
从企业知识库中检索信息
-
构建内部应用,将其发布给合适的人员,并保持其中的数据最新
-
从过去发送的内容中学习你的写作风格,然后按计划分拣收件箱——包括标签和回复草稿
-
在现有代码仓库中工作:运行测试、创建 PR、监控 CI、检查系统日志
-
在共享频道中跟踪项目,并发布更新和后续事项
flowchart LR DB[("Postgressessions · memory · queue")]
subgraph CORE["Headless core"] API["API · identity · policy · scheduler"] LOOP["Agent loop(Pi, OpenCode, Claude Code)"] API <--> LOOP end
SBX["Per-scope sandboxfiles · tools · logged-in services"]
DB <--> API LOOP <--> SBX
加载中
每一轮交互都会经过一个中央核心,核心可以使用多种模型和 harness 来生成响应。Postgres 持久化层保存用户数据、会话历史及其他持久化状态。Agent 具有一组小而固定的工具接口;其中之一是 execute,用于在该作用域自己的隔离沙箱中运行命令——这是其持久化计算机,已安装的工具会保持安装状态。Web UI、管理面板和公共门户是核心 HTTP API 上的可选插件;Slack 则是一个可选的进程内插件,核心通过直接服务客户端启动并监管它。
核心直接在 Node 上运行 TypeScript,并使用 Fastify 提供 HTTP 服务。Slack 插件使用 Bolt;Web UI 使用 Vite 构建,并以 Lit 渲染。
核心本身是通用的。所有特定于某家公司的内容——组织配置、自定义工具和技能、沙箱镜像、基础设施——都位于一个由 qm CLI 验证和部署的 部署目录 中。每个底层组件(harness、会话存储、沙箱、记忆)都置于接口之后,因此生产环境实现可通过一个接线文件进行替换。
QM 的方法遵循 OpenCode、Codex 和 Claude Code 等本地编码 Agent:Agent 以其服务对象的身份行动,使用该用户的凭据和权限,且其执行的所有操作都会被审计。组织选择一种安全策略,而更窄的作用域只能进一步收紧该策略:
- 严格(Strict) —— 除两个无副作用的回合结束工具外,每一次 harness 工具调用都会暂停等待人工批准。
- 自动(Auto,默认) —— 分类器会在带来源标记的外部数据和工具结果到达模型之前对其进行筛查;部署也可以将其指向自定义筛查代理。
- 危险(Dangerous) —— 不进行内容筛查,工具调用之间也不暂停。
预声明的命令策略——包括审批规则以及针对递归删除或破坏性 SQL 等操作的硬性拒绝——适用于每一种策略,包括 Dangerous。
SECURITY.md 包含威胁模型、运营者假设以及已知限制。
创建一个依赖 @yc-software/qm 的组织自有部署仓库:
npm exec --yes --package=@yc-software/qm@latest -- \
qm init . --org <slug> --target <fly-or-aws>
npm install
初始化会为 Agent 生成一项部署技能,并引导完成基础设施、Web 登录、连接器凭据、可选的 Slack 访问、部署和线上验证——无需检出源代码。每个部署均运行在运营者自己的云账户中;初始化不会生成或启用部署 CI,并且该仓库没有生产部署工作流。详见 deployment.md。
我们接受以 人工撰写 的文本形式提交贡献,而非代码——请参阅 CONTRIBUTING.md。请在 adrs/ 中的 .txt 或 .md 文件里,用非正式方式描述你希望进行的变更;如果双方达成一致,我们将负责实现。请私下报告漏洞——请参阅 SECURITY.md,不要公开提交 issue。
上述部署仓库承载配置和沙箱层,且永远不需要检出源代码。一些组织希望采用相反的取舍:将整个代码库放在同一个位置,让工程师和编码 Agent 可以一并阅读核心代码与定制内容,同时让定制内容本身保持私有。为此,请维护一个 私有 fork:这是一个独立的私有仓库,其历史从 qm 的克隆开始,且其核心始终与上游保持一致。
先填充一次,然后将其克隆下来进行工作:
gh repo create <org>/qm-private --private
git clone --bare git@github.com:yc-software/qm qm-seed.git
git -C qm-seed.git push --mirror git@github.com:<org>/qm-private
rm -rf qm-seed.git
git clone git@github.com:<org>/qm-private
git -C qm-private remote add upstream git@github.com:yc-software/qm
请如上所示通过普通克隆创建私有 fork,绝不要使用 GitHub 的 fork 功能。此处的“fork”指的是一种概念——有意产生分歧并从上游合并的下游副本——而不是 GitHub 的 Fork 按钮。GitHub fork 会继承其来源仓库的可见性,因此公开仓库的 fork 无法设为私有。GitHub fork 还会与其来源仓库共享同一个对象网络,因此推送至 fork 的提交仍可从公开侧通过 SHA 获取。许多组织也禁止 fork 私有仓库。普通克隆不存在这些问题,但代价是:该克隆是一个普通仓库,因此上游的 CI 工作流会在你自己的账户中实际运行。请准备好提供这些工作流所需的密钥,或者禁用不希望运行的工作流。
所有特定于你组织的内容都位于 deploy/layers/<org>/ 中——配置、沙箱工具和技能、插件镜像、基础设施——其结构与 qm init 生成的内容相同。请参阅 deploy/layers/README.md。核心代码与上游保持字节级一致,这正是让合并保持小规模的原因。
两项技能会双向维护这一边界。update-qm 将上游 qm 合并至私有 fork,并创建同步 PR;upstream-pr 则将与组织无关的修复提交回 qm:它从 upstream/main 创建分支,并在推送前检查待发出的 diff、提交消息和截图中是否存在组织标识符。deploy/layers/ 下的任何内容都不会传回上游。
除非另有说明,QM 以 MIT License 提供。
English / 原文
A multiplayer agent harness for work. In Slack and on the web.
Most agents are designed like personal assistants. You can make one work for a whole company, but it quickly gets complex. QM is designed for startups. Employees each get their own isolated workspace and work independently without affecting each other, and they can also collaborate with the agent in channels, group messages, and projects.
Each person and each room has its own scoped memory, files, keychain view, permissions, crons, web apps, and durable sandbox.
It's built with open source in mind. Pick your own harness and model and switch between them — Pi, OpenCode, Codex, and Claude Code all drive the same core, so a deployment isn't tied to any single vendor.
-
Personal and shared scopes. People customize the agent to be theirs , and still work with it collaboratively in Slack channels and projects.
-
Slack and web. The same identity and configuration carries between Slack and the web app.
-
Admin control. Set org-level configuration, a security posture, and which harnesses and models are available.
-
Web apps. Spin up custom internal apps and publish them to the right people.
-
Shared skills. Skills are scope-owned and shareable by grant, with admin-gated promotion to the whole org and skill packs imported from git repositories.
-
Background work. Crons and watches run work while nobody's watching.
-
Search internal notes, email, documents, databases, and the web together
-
Retrieve information from your company brain
-
Build internal apps, publish them to the right people, and keep their data current
-
Learn your writing voice from past sends, then triage your inbox on a schedule — labels and reply drafts included
-
Work in an existing repository: run tests, open PRs, monitor CI, check system logs
-
Track a project in a shared channel and post updates and follow-ups
flowchart LR DB[("Postgressessions · memory · queue")]
subgraph CORE["Headless core"] API["API · identity · policy · scheduler"] LOOP["Agent loop(Pi, OpenCode, Claude Code)"] API <--> LOOP end
SBX["Per-scope sandboxfiles · tools · logged-in services"]
DB <--> API LOOP <--> SBX
Loading
Every turn runs through a central core, which can use a variety of models and harnesses to generate the response. A Postgres persistence layer holds user data, session history, and other durable state. The agent has a small, fixed tool surface; one of those tools is execute, which runs commands in the scope's own isolated sandbox — its durable computer, where installed tools stay installed. The web UI, the admin panel, and the public portal are optional plugins over the core's HTTP API; Slack is an optional in-process plugin that core starts and supervises through a direct service client.
The core runs TypeScript directly on Node and uses Fastify for HTTP. The Slack plugin uses Bolt; the web UI builds with Vite and renders with Lit.
The core itself is generic. Everything specific to one company — org config, custom tools and skills, sandbox image, infrastructure — lives in a deployment directory that the qm CLI validates and deploys. Every substrate (harness, session store, sandbox, memory) sits behind an interface, so production implementations swap in via one wiring file.
QM's approach follows local coding agents like OpenCode, Codex, and Claude Code: the agent acts as the person it's working for, with their credentials and permissions, and everything it does is audited. An org picks one security posture, which narrower scopes can only tighten:
- Strict — every harness tool call pauses for human approval, except the two no-effect turn enders.
- Auto (default) — a classifier screens provenance-labelled external data and tool results before they reach the model; a deployment can point that at its own screening proxy.
- Dangerous — no content screening, no pauses between tool calls.
The predeclared command policy — approval rules and hard denials for things like recursive deletes or destructive SQL — applies in every posture, Dangerous included.
SECURITY.md has the threat model, the operator assumptions, and the known limitations.
Create an organization-owned deployment repository that depends on @yc-software/qm:
npm exec --yes --package=@yc-software/qm@latest -- \
qm init . --org <slug> --target <fly-or-aws>
npm install
Initialization materializes a deployment skill for an agent and walks through infrastructure, web sign-in, connector credentials, optional Slack access, deployment, and live verification — no source checkout required. Each deployment runs in the operator's own cloud account; initialization does not generate or enable deployment CI, and this repository has no production deployment workflow. See deployment.md for the details.
We take contributions as human-written text, not code — see CONTRIBUTING.md. Describe the change you'd like informally in a .txt or .md file in adrs/, and if we're aligned we'll handle the implementation. Report vulnerabilities privately — see SECURITY.md, not a public issue.
The deployment repository above carries config and a sandbox layer, and never needs a source checkout. Some organizations want the opposite trade: the whole codebase in one place, so engineers and coding agents read core and customizations together, while the customizations themselves stay private. For that, keep a private fork : a standalone private repository whose history begins as a clone of qm and whose core stays identical to upstream.
Populate it once, then clone it to work in:
gh repo create <org>/qm-private --private
git clone --bare git@github.com:yc-software/qm qm-seed.git
git -C qm-seed.git push --mirror git@github.com:<org>/qm-private
rm -rf qm-seed.git
git clone git@github.com:<org>/qm-private
git -C qm-private remote add upstream git@github.com:yc-software/qm
Create the private fork with a plain clone, as shown above, and never with GitHub's fork feature. The word "fork" here names the concept — a downstream copy that diverges deliberately and merges from upstream — not GitHub's Fork button. A GitHub fork inherits the visibility of the repository it came from, so a fork of a public repository cannot be made private. A GitHub fork also shares one object network with the repository it came from, so commits pushed to the fork stay fetchable by SHA from the public side. Many organizations disallow forking private repositories as well. A plain clone has none of these problems, and it costs one thing: the clone is an ordinary repository, so upstream's CI workflows run live in your own account. Expect to supply the secrets those workflows need, or disable the ones you do not want running.
Everything specific to your organization goes in deploy/layers/<org>/ — config, sandbox tools and skills, plugin images, infrastructure — in the same shape qm init produces. See deploy/layers/README.md. Core stays byte-identical to upstream, which is what keeps merges small.
Two skills maintain the boundary in both directions. update-qm merges upstream qm into the private fork and opens the sync PR; upstream-pr sends an organization-agnostic fix back to qm, cutting the branch from upstream/main and checking the outgoing diff, commit messages, and screenshots for organization identifiers before it pushes. Nothing under deploy/layers/ ever travels upstream.
Except where otherwise noted, QM is available under the MIT License.
