MonkeyCode 开源社区治理:RFC 决策机制与社区自治实践指南
引言
"开源项目的成功,不在于代码写得有多好,而在于社区治理有多透明。"
在开源世界中,技术能力只是基础。一个真正可持续发展的开源项目,需要一套完善的治理机制来协调贡献者、维护者、用户之间的利益关系。MonkeyCode 作为完全开源的 AI 编程助手项目,在社区治理方面积累了丰富的实践经验。
本文将系统性地分享 MonkeyCode 的 RFC(Request for Comments)决策机制、社区自治实践、以及如何构建一个健康、透明、高效的开源治理体系。
🎯 核心信息
- GitHub 仓库: https://github.com/monkeycode-ai/monkeycode
- 开源协议: Apache License 2.0
- 欢迎提交 Issue: 治理相关问题请标记
governance标签- 参与 RFC 讨论: 查看 rfc/ 目录
一、为什么开源项目需要治理机制?
1.1 常见的开源治理困境
┌─────────────────────────────────────────────────────────────┐
│ 开源项目常见治理困境 │
│ │
│ 🔴 "独裁者困境" │
│ ├── 创始人/核心维护者拥有绝对决策权 │
│ ├── 贡献者感到缺乏话语权 │
│ ├── 项目方向过度依赖个人意愿 │
│ └── 维护者倦怠后项目陷入停滞 │
│ │
│ 🟠 "混乱民主" │
│ ├── 缺乏明确的决策流程 │
│ ├── 讨论无休止无法收敛 │
│ ├── PR 合并标准不一致 │
│ └── 社区分裂成多个 fork │
│ │
│ 🟡 "企业控制" │
│ ├── 主要贡献来自某一家公司 │
│ ├── 社区担心被"绑架" │
│ ├── 独立贡献者边缘化 │
│ └── 利益冲突难以平衡 │
│ │
│ 🟢 MonkeyCode 的选择: 结构化 RFC + 社区共识 │
│ ├── 明确的提案流程 │
│ ├── 透明的讨论记录 │
│ ├── 可量化的决策标准 │
│ └── 渐进式权限模型 │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 治理成熟度模型
# monkeycode/governance/maturity-model.yaml
governance_maturity_model:
level_0_ad_hoc:
name: "临时性"
characteristics:
- 无正式治理结构
- 决策由创始人/少数人做出
- 贡献流程不明确
- 文档缺失或过时
risks:
- 单点故障风险高
- 无法规模化
- 贡献者流失率高
typical_projects: "个人 side project、早期原型"
level_1_benevolent_dictator:
name: "仁慈独裁者 (BDFL)"
characteristics:
- 有明确的项目负责人
- 基本的 CONTRIBUTING.md
- Issue/PR 流程存在但不严格
- 维护者团队初步形成
benefits:
- 决策效率高
- 方向一致性强
limitations:
- 过度依赖关键人物
- 权力交接困难
typical_projects: "Linux (早期)、Python、大多数中小型开源项目"
level_2_meritocracy:
name: "精英治理 (Meritocracy)"
characteristics:
- 基于贡献的权限晋升
- 维护者团队有明确职责分工
- Code Review 制度化
- Release 流程规范化
benefits:
- 能者上庸者下
- 激励持续贡献
limitations:
- 可能形成小圈子
- 新人进入门槛高
typical_projects: "Apache 基金会项目、Kubernetes、Rust"
level_3_foundation:
name: "基金会治理"
characteristics:
- 独立法律实体
- 多公司/多组织参与
- 正式的董事会/技术委员会
- 完善的知识产权管理
benefits:
- 中立性和可持续性
- 企业友好
- 法律保障完善
limitations:
- 运营成本高
- 决策可能较慢
typical_projects: "Linux Foundation 项目、Cloud Native Computing Foundation"
level_4_community_consensus:
name: "社区共识治理"
characteristics:
- RFC 驱动的重大决策
- 透明的投票/否决机制
- 多元化的利益代表
- 自我演进的治理规则
benefits:
- 最大程度的包容性
- 抗单点故障能力强
- 社区归属感强
challenges:
- 决策周期较长
- 需要成熟的社区文化
target_for_monkeyCode: true # MonkeyCode 的目标状态
二、RFC(Request for Comments)机制详解
2.1 什么是 RFC?
RFC (Request for Comments) = 提案请求文档
┌─────────────────────────────────────────────────────────────┐
│ RFC 生命周期 │
│ │
│ ┌──────────┐ │
│ │ 📝 草案 │ ← 提案人撰写初始提案 │
│ │ (Draft) │ │
│ └────┬─────┘ │
│ ↓ │
│ ┌──────────┐ 社区讨论期 │
│ │ 💬 讨论 │ ◄────────────────────────┐ │
│ │(Discuss) │ ──────────────────────────►│ │
│ └────┬─────┘ │ │
│ ↓ │ │
│ ┌──────────┐ 根据反馈修改 │ │
│ │ ✏️ 修订 │ ◄─────────────────────────┘ │
│ │(Revised) │ │
│ └────┬─────┘ │
│ ↓ │
│ ┌──────────┐ 最终审查 │
│ │ ✅ 审查 │ │
│ │(Review) │ │
│ └────┬─────┘ │
│ ↓ │
│ ┌──────────┐ │
│ │ 🗳️ 投票 │ ← 核心维护者投票决定 │
│ │ (Vote) │ │
│ └────┬─────┘ │
│ ↓ │
│ ┌──────────┐ │
│ │ 📋 结果 │ │
│ │ │ │
│ │ 通过 → 实施 │ │
│ │ 拒绝 → 归档 │ (附拒绝理由) │
│ │ 撤回 → 关闭 │ (提案人主动撤回) │
│ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2.2 MonkeyCode RFC 分类体系
# ===== monkeycode/governance/rfc_types.py =====
"""
MonkeyCode RFC 分类系统
每种类型有不同的审批流程和投票门槛
"""
from dataclasses import dataclass
from enum import Enum
from typing import Optional, List
from datetime import timedelta
class RFCCategory(Enum):
"""RFC 分类"""
PROCESS = "process" # 流程变更(治理规则、贡献流程等)
TECHNICAL = "technical" # 技术设计(架构、API、协议等)
FEATURE = "feature" # 功能提案(新功能、增强等)
DEPRECATION = "deprecation" # 废弃计划(移除旧功能)
RELEASE = "release" # 发布策略(版本规划、时间表等)
GOVERNANCE = "governance" # 治理变更(权限、角色、规则等)
META = "meta" # 元提案(关于 RFC 本身的变更)
class RFCStatus(Enum):
"""RFC 状态"""
DRAFT = "draft" # 草案中
DISCUSSING = "discussing" # 讨论中
REVISED = "revised" # 已修订
REVIEWING = "reviewing" # 审查中
VOTING = "voting" # 投票中
ACCEPTED = "accepted" # 已通过
REJECTED = "rejected" # 已拒绝
WITHDRAWN = "withdrawn" # 已撤回
SUPERSEDED = "superseded" # 已被替代
IMPLEMENTED = "implemented" # 已实施
@dataclass
class RFCTemplate:
"""RFC 模板配置"""
category: RFCCategory
title_prefix: str
discussion_period: timedelta # 讨论期长度
voting_period: timedelta # 投票期长度
quorum_required: int # 法定人数(最少参与投票数)
approval_threshold: float # 通过阈值(赞成比例)
veto_enabled: bool # 是否允许否决权
auto_merge_pr: bool # 是否自动合并实施 PR
def get_voting_rules(self) -> dict:
return {
'discussion_days': self.discussion_period.days,
'voting_days': self.voting_period.days,
'quorum': self.quorum_required,
'threshold': f"{self.approval_threshold * 100:.0f}%",
'veto': 'enabled' if self.veto_enabled else 'disabled',
}
# MonkeyCode RFC 类型定义
RFC_TYPES = {
RFCCategory.PROCESS: RFCTemplate(
category=RFCCategory.PROCESS,
title_prefix="P-", # Process
discussion_period=timedelta(days=14),
voting_period=timedelta(days=7),
quorum_required=5,
approval_threshold=0.67, # 67% 赞成
veto_enabled=True,
auto_merge_pr=False,
),
RFCCategory.TECHNICAL: RFCTemplate(
category=RFCCategory.TECHNICAL,
title_prefix="T-", # Technical
discussion_period=timedelta(days=21),
voting_period=timedelta(days=7),
quorum_required=5,
approval_threshold=0.67,
veto_enabled=True,
auto_merge_pr=False,
),
RFCCategory.FEATURE: RFCTemplate(
category=RFCCategory.FEATURE,
title_prefix="F-", # Feature
discussion_period=timedelta(days=14),
voting_period=timedelta(days=5),
quorum_required=3,
approval_threshold=0.60, # 60% 赞成
veto_enabled=False,
auto_merge_pr=True,
),
RFCCategory.DEPRECATION: RFCTemplate(
category=RFCCategory.DEPRECATION,
title_prefix="D-", # Deprecation
discussion_period=timedelta(days=30), # 废弃需更长讨论
voting_period=timedelta(days=10),
quorum_required=7,
approval_threshold=0.75, # 75% 赞成(更高门槛)
veto_enabled=True,
auto_merge_pr=False,
),
RFCCategory.RELEASE: RFCTemplate(
category=RFCCategory.RELEASE,
title_prefix="R-", # Release
discussion_period=timedelta(days=7),
voting_period=timedelta(days=3),
quorum_required=3,
approval_threshold=0.60,
veto_enabled=False,
auto_merge_pr=True,
),
RFCCategory.GOVERNANCE: RFCTemplate(
category=RFCCategory.GOVERNANCE,
title_prefix="G-", # Governance
discussion_period=timedelta(days=30), # 治理变更需充分讨论
voting_period=timedelta(days=14),
quorum_required=10, # 最高法定人数
approval_threshold=0.80, # 80% 赞成
veto_enabled=True,
auto_merge_pr=False,
),
RFCCategory.META: RFCTemplate(
category=RFCCategory.META,
title_prefix="M-", # Meta
discussion_period=timedelta(days=14),
voting_period=timedelta(days=7),
quorum_required=5,
approval_threshold=0.67,
veto_enabled=True,
auto_merge_pr=False,
),
}
def get_rfc_template(category: RFCCategory) -> RFCTemplate:
"""获取指定类型的 RFC 模板"""
if category not in RFC_TYPES:
raise ValueError(f"Unknown RFC category: {category}")
return RFC_TYPES[category]
def format_rfc_number(category: RFCCategory, number: int) -> str:
"""格式化 RFC 编号"""
prefix = RFC_TYPES[category].title_prefix
return f"{prefix}{number:04d}"
# 使用示例
if __name__ == '__main__':
print("=== MonkeyCode RFC 类型体系 ===\n")
for cat, template in RFC_TYPES.items():
rules = template.get_voting_rules()
print(f"{template.title_prefix} ({cat.value})")
print(f" 讨论期: {rules['discussion_days']} 天")
print(f" 投票期: {rules['voting_days']} 天")
print(f" 法定人数: ≥{rules['quorum']} 人")
print(f" 通过阈值: {rules['threshold']}")
print(f" 否决权: {rules['veto']}")
print(f" 自动合并: {'是' if template.auto_merge_pr else '否'}")
print()
2.3 RFC 文档模板
---
title: "RFC-0001: MonkeyCode 多语言支持架构设计"
status: discussing
category: technical
created: 2026-06-15
author: "@contributor-name"
reviewers: ["@maintainer-a", "@maintainer-b"]
discussions-to: https://github.com/monkeycode-ai/monkeycode/discussions/123
---
# RFC-0001: MonkeyCode 多语言支持架构设计
## 摘要 (Summary)
一句话概括本提案的核心内容和目标。
*本 RFC 提出 MonkeyCode 支持多编程语言的统一抽象层设计方案,
使 AI 编程助手能够同时支持 Python、JavaScript、Go、Rust 等
主流编程语言,并通过插件机制支持扩展新语言。*
## 动机 (Motivation)
### 当前问题
- [ ] 问题 1 的详细描述
- [ ] 问题 2 的详细描述
- [ ] 受影响的用户群体
### 为什么现在需要解决?
- [ ] 时间窗口/紧迫性说明
- [ ] 不解决的后果
## 详细设计 (Detailed Design)
### 设计概述
[架构图 / 流程图 / 数据流]
### 核心组件
1. **组件 A**: 功能描述
2. **组件 B**: 功能描述
3. **组件 C**: 功能描述
### 接口定义
```typescript
// 接口伪代码或实际代码示例
interface LanguageSupport {
name: string;
extensions: string[];
parse(code: string): AST;
generate(ast: AST): string;
}
数据模型
# 配置文件格式示例
languages:
python:
parser: tree-sitter-python
extensions: [.py]
version_support: [3.8, 3.9, 3.10, 3.11, 3.12]
javascript:
parser: tree-sitter-javascript
extensions: [.js, .ts, .jsx, .tsx]
version_support: [ES2020+, TypeScript 5.x]
替代方案 (Alternatives)
| 方案 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|
| 方案 A | ... | ... | ⭐⭐⭐ |
| 方案 B | ... | ... | ⭐⭐ |
| 方案 C | ... | ... | ⭐ |
向后兼容性 (Backwards Compatibility)
破坏性变更
迁移路径
[用户从旧版本迁移到新版本的步骤]
安全影响 (Security Considerations)
测试策略 (Testing Strategy)
实施计划 (Implementation Plan)
Phase 1: 基础设施 (Week 1-2)
Phase 2: 核心功能 (Week 3-4)
Phase 3: 文档与发布 (Week 5-6)
未解决问题 (Unresolved Questions)
- 问题 A: 描述 + 可能的解决方案
- 问题 B: 描述 + 可能的解决方案
未来展望 (Future Possibilities)
本 RFC 通过后可能的后续工作:
致谢 (Acknowledgments)
感谢以下人员对本 RFC 的贡献:
- @reviewer-a: 提供了 X 方面的建议
- @reviewer-b: 帮助评审了 Y 部分
参考资料 (References)
- [相关链接 1]
- [相关论文/标准]
- [类似项目的实现参考]
---
## 三、社区自治实践
### 3.1 角色与权限体系
┌─────────────────────────────────────────────────────────────┐
│ MonkeyCode 社区角色层级 │
│ │
│ Level 0: 访客 (Visitor) │
│ ├── 可以: 阅读 Issues/PRs/Discussions │
│ ├── 可以: Star/Fork 仓库 │
│ ├── 不可以: 创建 Issue / 提交 PR │
│ └── 升级条件: 注册 GitHub 账号 │
│ ↓ │
│ Level 1: 贡献者 (Contributor) │
│ ├── 可以: 创建 Issue、提交 PR │
│ ├── 可以: 参与 Discussions 讨论 │
│ ├── 可以: 评论和 Review PR │
│ ├── 不可以: 合并 PR / 关闭 Issue │
│ └── 升级条件: 至少 1 个 PR 被合并 │
│ ↓ │
│ Level 2: 活跃贡献者 (Active Contributor) │
│ ├── 可以: 标记 Label、指派 Assignee │
│ ├── 可以: 管理自己负责模块的 Issue │
│ ├── 不可以: 合并他人代码 / 发布版本 │
│ └── 升级条件: 连续 3 个月活跃 + 5+ PR 合并 │
│ ↓ │
│ Level 3: 模块维护者 (Module Maintainer) │
│ ├── 可以: 合并指定模块的 PR │
│ ├── 可以: 发布 Patch 版本 │
│ ├── 负责: 特定模块的质量和进度 │
│ └── 升级条件: RFC 提名 + 社区投票通过 │
│ ↓ │
│ Level 4: 核心维护者 (Core Maintainer) │
│ ├── 可以: 合并所有 PR │
│ ├── 可以: 发布 Minor/Major 版本 │
│ ├── 可以: 对 RFC 行使否决权 │
│ ├── 负责: 项目整体方向和技术决策 │
│ └── 任命方式: 现任核心维护者提名 + 社区投票 │
│ ↓ │
│ Level 5: 技术委员会 (Technical Committee / TSC) │
│ ├── 可以: 修改治理规则 │
│ ├── 可以: 任命/罢免核心维护者 │
│ ├── 负责: 项目长期战略和法律事务 │
│ └── 组成: 核心维护者 + 企业代表 + 社区选举代表 │
│ │
│ ════════════════════════════════════════════════════════ │
│ │
│ 特殊角色 (跨层级): │
│ ├── Release Manager: 版本发布管理 │
│ ├── Security Lead: 安全漏洞响应 │
│ ├── Community Manager: 社区运营 │
│ ├── Docs Lead: 文档质量把控 │
│ └── Triager: Issue 分类和优先级标记 │
│ │
└─────────────────────────────────────────────────────────────┘
### 3.2 权限矩阵
```typescript
// ===== monkeycode/governance/permissions.ts =====
/**
* MonkeyCode 社区权限矩阵
* 定义每个角色可以执行的操作
*/
export interface Permission {
name: string;
description: string;
scope: 'global' | 'module' | 'self';
}
export interface RolePermissions {
role: string;
level: number;
permissions: Permission[];
canPromoteTo: string[]; // 可以提名升级到的角色
}
export const PERMISSION_MATRIX: RolePermissions[] = [
{
role: 'visitor',
level: 0,
permissions: [
{ name: 'read', description: '阅读公开内容', scope: 'global' },
{ name: 'star', description: 'Star 仓库', scope: 'global' },
{ name: 'fork', description: 'Fork 仓库', scope: 'global' },
],
canPromoteTo: ['contributor'],
},
{
role: 'contributor',
level: 1,
permissions: [
// 继承 visitor 所有权限...
{ name: 'create_issue', description: '创建 Issue', scope: 'global' },
{ name: 'create_pr', description: '提交 Pull Request', scope: 'global' },
{ name: 'comment', description: '评论 Issue 和 PR', scope: 'global' },
{ name: 'participate_discussion', description: '参与 Discussions', scope: 'global' },
{ name: 'submit_rfc', description: '提交 RFC 提案', scope: 'global' },
],
canPromoteTo: ['active_contributor'],
},
{
role: 'active_contributor',
level: 2,
permissions: [
// 继承 contributor 所有权限...
{ name: 'label_issue', description: '为 Issue 添加标签', scope: 'global' },
{ name: 'assign_issue', description: '指派 Issue 给他人', scope: 'global' },
{ name: 'manage_own_module_issues', description: '管理自己关注模块的 Issue', scope: 'module' },
{ name: 'request_review', description: '请求代码审查', scope: 'global' },
],
canPromoteTo: ['module_maintainer'],
},
{
role: 'module_maintainer',
level: 3,
permissions: [
// 继承 active_contributor 所有权限...
{ name: 'merge_pr_module', description: '合并负责模块的 PR', scope: 'module' },
{ name: 'release_patch', description: '发布补丁版本', scope: 'global' },
{ name: 'manage_branches', description: '管理分支保护规则', scope: 'module' },
{ name: 'assign_reviewer', description: '指派审查者', scope: 'module' },
],
canPromoteTo: ['core_maintainer'],
},
{
role: 'core_maintainer',
level: 4,
permissions: [
// 继承 module_maintainer 所有权限...
{ name: 'merge_pr_all', description: '合并所有 PR', scope: 'global' },
{ name: 'release_minor_major', description: '发布主要版本', scope: 'global' },
{ name: 'veto_rfc', description: '对 RFC 行使否决权', scope: 'global' },
{ name: 'manage_team', description: '管理团队成员', scope: 'global' },
{ name: 'modify_ci_cd', description: '修改 CI/CD 配置', scope: 'global' },
{ name: 'nominate_maintainer', description: '提名新的维护者', scope: 'global' },
],
canPromoteTo: ['tsc_member'],
},
{
role: 'tsc_member',
level: 5,
permissions: [
// 继承 core_maintainer 所有权限...
{ name: 'modify_governance', description: '修改治理规则', scope: 'global' },
{ name: 'appoint_core', description: '任命/罢免核心维护者', scope: 'global' },
{ name: 'handle_legal', description: '处理法律事务', scope: 'global' },
{ name: 'set_strategic_direction', description: '设定战略方向', scope: 'global' },
],
canPromoteTo: [], // 最高级别
},
];
// 权限检查函数
export function hasPermission(
userRole: string,
requiredPermission: string,
scope?: string
): boolean {
const roleConfig = PERMISSION_MATRIX.find(r => r.role === userRole);
if (!roleConfig) return false;
return roleConfig.permissions.some(
p => p.name === requiredPermission &&
(!scope || p.scope === scope || p.scope === 'global')
);
}
// 角色升级检查
export function canPromote(fromRole: string, toRole: string): boolean {
const fromConfig = PERMISSION_MATRIX.find(r => r.role === fromRole);
if (!fromConfig) return false;
return fromConfig.canPromoteTo.includes(toRole);
}
3.3 决策流程图
┌─────────────────────────────────────────────────────────────────────┐
│ │
│ MonkeyCode 决策流程图 │
│ │
│ ┌──────────────┐ │
│ │ 有想法? │ │
│ └──────┬───────┘ │
│ ↓ │
│ ┌──────────────┐ 小改动? ┌──────────────┐ │
│ │ 创建 Issue │ ──────────→ │ 直接提 PR │ │
│ │ 或 Discussion│ (Bug Fix/Doc) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ ↓ ↓ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 社区讨论反馈 │ │ Code Review │ │
│ │ 收集意见 │ │ (≥1 Maintainer│ │
│ └──────┬───────┘ │ Approve) │ │
│ ↓ └──────┬───────┘ │
│ ┌──────────────┐ ↓ │
│ │ 影响范围? │ ┌──────────────┐ │
│ └──────┬───────┘ │ 自动合并 ✅ │ │
│ ↓ └──────────────┘ │
│ ┌───────┴───────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────┐ ┌────────────┐ │
│ │仅本地 │ │涉及API/架构 │ │
│ │配置变更 │ │/重大功能 │ │
│ └───┬────┘ └─────┬──────┘ │
│ ↓ ↓ │
│ ┌────────┐ ┌────────────┐ │
│ │PR+Review│ │ 提交 RFC │ │
│ └───┬────┘ └─────┬──────┘ │
│ ↓ ↓ │
│ └──────┬──────┘ │
│ ↓ │
│ ┌────────────┐ │
│ │ RFC 流程 │ │
│ │ (见上文) │ │
│ └─────┬──────┘ │
│ ↓ │
│ ┌────────────┐ │
│ │ RFC 通过? │ │
│ └─────┬──────┘ │
│ ↙ ↘ ↖ │
│ 是 否 撤回 │
│ ↓ ↓ ↓ │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │实施│ │归档│ │关闭│ │
│ │PR │ │(附 │ │(附 │ │
│ │ │ │理由│ │原因│ │
│ └──┬─┘ └────┘ └────┘ │
│ ↓ │
│ ┌────────────┐ │
│ │ 实施完成 │ │
│ │ 更新状态 │ │
│ │ RFC→Done │ │
│ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
四、投票与共识机制
4.1 投票类型与规则
# ===== monkeycode/governance/voting.py =====
"""
MonkeyCode 投票系统
支持多种投票类型和计票方式
"""
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, List, Dict
from datetime import datetime, timedelta
class VoteType(Enum):
"""投票类型"""
APPROVAL = "approval" # 赞成/反对/弃权
PREFERENCE = "preference" # 偏好排序(用于多选一)
RANKING = "ranking" # 评分排序(用于优先级)
CONSENSUS = "consensus" # 共识寻求(延迟反对)
class VoteValue(Enum):
"""投票值"""
STRONGLY_APPROVE = 2 # 强烈赞成
APPROVE = 1 # 赞成
ABSTAIN = 0 # 弃权
OPPOSE = -1 # 反对
STRONGLY_OPPOSE = -2 # 强烈反对
@dataclass
class Voter:
"""投票人信息"""
github_username: str
role_level: int # 角色等级 (0-5)
weight: float = 1.0 # 投票权重(默认 1.0)
voted_at: Optional[datetime] = None
@dataclass
class Vote:
"""单次投票"""
voter: Voter
value: VoteValue
comment: Optional[str] = None # 投票说明
timestamp: datetime = field(default_factory=datetime.now)
@dataclass
class VotingResult:
"""投票结果"""
total_votes: int
approve_count: int
oppose_count: int
abstain_count: int
weighted_approve: float
weighted_oppose: float
quorum_reached: bool
threshold_met: bool
passed: bool
veto_used: bool = False
veto_by: Optional[str] = None
details: Dict = field(default_factory=dict)
class VotingEngine:
"""投票引擎"""
def __init__(self):
self.votes: List[Vote] = []
self.voters: Dict[str, Voter] = {}
def register_voter(self, voter: Voter):
"""注册投票人"""
self.voters[voter.github_username] = voter
def cast_vote(self, vote: Vote) -> bool:
"""提交投票"""
username = vote.voter.github_username
# 检查是否已注册
if username not in self.voters:
return False
# 检查是否已投票
existing = next((v for v in self.votes
if v.voter.github_username == username), None)
if existing:
# 允许修改投票(替换旧的)
self.votes.remove(existing)
self.votes.append(vote)
return True
def calculate_result(self,
threshold: float = 0.67,
quorum: int = 5,
allow_veto: bool = False,
veto_role_level: int = 4) -> VotingResult:
"""计算投票结果"""
if not self.votes:
return VotingResult(
total_votes=0, approve_count=0, oppose_count=0,
abstain_count=0, weighted_approve=0, weighted_oppose=0,
quorum_reached=False, threshold_met=False, passed=False
)
# 统计各类票数
approve_votes = [v for v in self.votes
if v.value.value > 0]
oppose_votes = [v for v in self.votes
if v.value.value < 0]
abstain_votes = [v for v in self.votes
if v.value.value == 0]
# 加权计算
weighted_approve = sum(
v.value.value * v.voter.weight for v in approve_votes
)
weighted_oppose = abs(sum(
v.value.value * v.voter.weight for v in oppose_votes
))
total_valid = len(approve_votes) + len(oppose_votes)
approve_rate = (
len(approve_votes) / total_valid if total_valid > 0 else 0
)
# 检查法定人数
quorum_reached = len(self.votes) >= quorum
# 检查通过阈值
threshold_met = approve_rate >= threshold
# 检查否决权
veto_used = False
veto_by = None
if allow_veto:
for v in oppose_votes:
if v.voter.role_level >= veto_role_level:
veto_used = True
veto_by = v.voter.github_username
break
# 最终结果
passed = quorum_reached and threshold_met and not veto_used
return VotingResult(
total_votes=len(self.votes),
approve_count=len(approve_votes),
oppose_count=len(oppose_votes),
abstain_count=len(abstain_votes),
weighted_approve=weighted_approve,
weighted_oppose=weighted_oppose,
quorum_reached=quorum_reached,
threshold_met=threshold_met,
passed=passed,
veto_used=veto_used,
veto_by=veto_by,
details={
'approve_rate': f"{approve_rate * 100:.1f}%",
'valid_votes': total_valid,
}
)
def get_vote_summary(self) -> str:
"""获取投票摘要(用于展示)"""
lines = []
lines.append("📊 投票统计\n")
lines.append(f"总投票数: {len(self.votes)}\n")
for val in [VoteValue.STRONGLY_APPROVE, VoteValue.APPROVE,
VoteValue.ABSTAIN, VoteValue.OPPOSE,
VoteValue.STRONGLY_OPPOSE]:
count = sum(1 for v in self.votes if v.value == val)
emoji = {2: "👍👍", 1: "👍", 0: "⚪",
-1: "👎", -2: "👎👎"}[val.value]
lines.append(f" {emoji} {val.name}: {count}")
return "\n".join(lines)
# 使用示例
if __name__ == '__main__':
engine = VotingEngine()
# 注册投票人(模拟)
roles = {
'alice': 4, # Core Maintainer
'bob': 4, # Core Maintainer
'carol': 3, # Module Maintainer
'dave': 2, # Active Contributor
'eve': 2, # Active Contributor
'frank': 1, # Contributor
}
for username, level in roles.items():
engine.register_voter(Voter(
github_username=username,
role_level=level,
weight=1.0 + level * 0.1 # 高等级略高权重
))
# 模拟投票
from random import seed, choice
seed(42)
values = [VoteValue.APPROVE, VoteValue.STRONGLY_APPROVE,
VoteValue.ABSTAIN, VoteValue.OPPOSE]
for username in roles.keys():
engine.cast_vote(Vote(
voter=engine.voters[username],
value=choice(values),
comment=f"{username}'s vote"
))
# 计算结果
result = engine.calculate_result(
threshold=0.67,
quorum=5,
allow_veto=True
)
print(engine.get_vote_summary())
print(f"\n法定人数达标: {'✅' if result.quorum_reached else '❌'}")
print(f"通过阈值达成: {'✅' if result.threshold_met else '❌'}")
print(f"否决权使用: {'⚠️ 是 (' + result.veto_by + ')' if result.veto_used else '❌ 否'}")
print(f"\n最终结果: {'🟢 通过 ✅' if result.passed else '🔴 未通过 ❌'}")
4.2 共识寻求机制(Lazy Consensus)
## Lazy Consensus(延迟共识)规则
对于低风险的日常决策,MonkeyCode 采用 Lazy Consensus 机制:
### 适用场景
- 文档改进(非 API 文档)
- 代码风格调整
- 测试用例增加
- 依赖库版本更新(Patch/Minor 版本)
- typo 修复
- CI/CD 配置微调
### 规则
1. **默认通过**: 如果在规定时间内(通常 72 小时)无人提出反对,则视为通过
2. **沉默即同意**: 不表态 = 同意
3. **明确反对**: 任何维护者级别的成员都可以提出反对
4. **反对必须附理由**: 反对时必须给出建设性的替代方案
### 流程
提议发布
│
├─→ 72小时内无人反对 → ✅ 自动通过
│
└─→ 有人反对
│
├─→ 反对理由可解决 → 修改后重新计时
│
└─→ 存在根本分歧 → 升级为完整 RFC 流程
### 与完整 RFC 的对比
| 维度 | Lazy Consensus | 完整 RFC |
|------|---------------|---------|
| 适用范围 | 低风险变更 | 架构/策略变更 |
| 讨论期 | 72 小时 | 14-30 天 |
| 投票要求 | 无(沉默同意) | 正式投票 |
| 否决权 | 任何 Maintainer | 仅 Core Maintainer |
| 文档要求 | PR 描述即可 | 完整 RFC 文档 |
| 典型案例 | 修复 typo | 新增多语言支持 |
五、冲突解决机制
5.1 冲突分级处理
# monkeycode/governance/conflict-resolution.yaml
conflict_resolution:
level_1_technical_disagreement:
name: "技术分歧"
triggers:
- PR Review 中出现不同技术观点
- RFC 讨论中方案无法达成一致
resolution_process:
step_1:
action: "双方各自列出优缺点对比表"
owner: "争议双方"
timeline: "3天内"
step_2:
action: "邀请第三方中立专家评审"
owner: "任意 Core Maintainer"
timeline: "5天内"
step_3:
action: "基于数据/基准测试做决策"
owner: "Module Maintainer"
decision_criteria: "性能数据、兼容性、维护成本"
escalation: "如果仍无法解决,升级到 Level 2"
level_2_process_dispute:
name: "流程争议"
triggers:
- 对治理规则的解释产生分歧
- 权限边界不清导致的冲突
resolution_process:
step_1:
action: "查阅现有文档寻找先例"
owner: "争议双方"
step_2:
action: "Community Manager 调解"
owner: "Community Manager"
timeline: "7天"
step_3:
action: "TSC 裁决"
owner: "Technical Committee"
decision_binding: true # TSC 裁决具有约束力
appeal: "可向更广泛的社区申诉"
level_3_conduct_violation:
name: "行为准则违反"
triggers:
- 违反 Code of Conduct
- 骚扰、歧视、不当言论
resolution_process:
step_1:
action: "私下警告"
owner: "任何受影响的成员"
documentation: "记录事件详情"
step_2:
action: "公开警告 + 暂时禁言"
owner: "Core Maintainer 团队"
duration: "7-30天"
step_3:
action: "永久禁止参与"
owner: "TSC"
requirements: "TSC 全体投票 ≥80%"
appeals_process: "可在 30 天内向 TSC 申诉"
level_4_governance_crisis:
name: "治理危机"
triggers:
- 核心维护者集体离职
- 项目分叉 (Fork) 危机
- 法律诉讼威胁
emergency_measures:
- "激活紧急响应小组"
- "冻结所有合并操作"
- "发布公告说明情况"
resolution:
- "召开全体社区会议"
- "考虑引入基金会托管"
- "必要时进行治理架构重组"
5.2 申诉流程
┌─────────────────────────────────────────────────────────────┐
│ MonkeyCode 申诉流程 │
│ │
│ 1️⃣ 申诉发起 │
│ ├── 申诉人提交正式申诉文档 │
│ ├── 包含: 原始决策、申诉理由、期望结果 │
│ └── 提交至: governance-appeals@monkeycode.dev │
│ ↓ │
│ 2️⃣ 初步审核 │
│ ├── Community Manager 在 48h 内确认受理 │
│ ├── 补充材料要求(如需要) │
│ └── 不符合申诉条件的予以驳回并说明理由 │
│ ↓ │
│ 3️⃣ 申诉审理 │
│ ├── 组建 3 人申诉委员会(不含原决策方) │
│ ├── 双方提交陈述材料 │
│ ├── 公开听证会(可选,视情况而定) │
│ └── 委员会内部评议 │
│ ↓ │
│ 4️⃣ 裁决宣布 │
│ ├── 书面裁决 + 详细理由 │
│ ├── 三种可能结果: │
│ │ ✅ 维持原决定 │
│ │ 🔄 部分推翻,要求重新审议 │
│ │ ❌ 完全推翻,撤销原决定 │
│ └── 裁决在社区公告 │
│ ↓ │
│ 5️⃣ 最终上诉(可选) │
│ ├── 如对申诉委员会裁决不服 │
│ ├── 可在 14 天内向 TSC 提起最终上诉 │
│ └── TSC 裁决为最终裁决,不可再上诉 │
│ │
│ ⏱️ 时限要求: │
│ ├── 整个申诉流程应在 30 天内完成 │
│ ├── 复杂案件可延长至 60 天 │
│ └── 紧急情况可走快速通道(7 天) │
│ │
└─────────────────────────────────────────────────────────────┘
六、工具与自动化
6.1 GitHub Actions 自动化
# .github/workflows/rfc-bot.yml
name: RFC Bot
on:
issues:
types: [opened, edited, labeled, unlabeled]
pull_request:
types: [opened, ready_for_review, review_requested]
jobs:
rfc-lifecycle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check RFC Status
uses: monkeycode/rfc-action@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
rfc-directory: './rfc'
- name: Update RFC Labels
run: |
# 根据 RFC 状态自动添加标签
gh issue edit ${{ github.event.issue.number }} \
--add-label "status:${{ steps.rfc-check.outputs.status }}" \
--add-label "category:${{ steps.rfc-check.outputs.category }}"
- name: Check Discussion Period
id: period-check
run: |
# 检查讨论期是否满足
created=$(gh issue view ${{ github.event.issue.number }} \
--json createdAt -q '.createdAt')
# 计算是否达到最小讨论期
- name: Remind Voting
if: steps.period-check.outputs.ready-to-vote == 'true'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## 📢 RFC 投票提醒
此 RFC 的讨论期已满,现进入投票阶段。
请各位核心维护者在 7 天内完成投票。
- 👍 表示赞成
- 👎 表示反对
- ⚪ 表示弃权
[点击这里投票](${context.payload.issue.html_url})`
})
6.2 RFC Dashboard
<!-- monkeycode/governance/rfc-dashboard.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>MonkeyCode RFC Dashboard</title>
<style>
:root {
--mc-primary: #3b82f6;
--mc-success: #10b981;
--mc-warning: #f59e0b;
--mc-error: #ef4444;
--mc-gray-100: #f3f4f6;
--mc-gray-800: #1f2937;
}
body { font-family: 'Inter', sans-serif; padding: 2rem; background: #f9fafb; }
.dashboard { max-width: 1200px; margin: 0 auto; }
h1 { color: var(--mc-gray-800); border-bottom: 3px solid var(--mc-primary);
padding-bottom: 0.5rem; display: flex; align-items: center; gap: 0.5rem; }
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem; margin: 1.5rem 0; }
.stat-card { background: white; border-radius: 12px; padding: 1.5rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1); text-align: center; }
.stat-number { font-size: 2.5rem; font-weight: 800; }
.stat-label { color: #6b7280; font-size: 0.875rem; margin-top: 0.25rem; }
.filters { display: flex; gap: 1rem; margin-bottom: 1rem; flex-wrap: wrap; }
.filter-btn { padding: 0.5rem 1rem; border-radius: 8px; border: 1px solid #e5e7eb;
background: white; cursor: pointer; transition: all 0.2s; }
.filter-btn.active { background: var(--mc-primary); color: white;
border-color: var(--mc-primary); }
table { width: 100%; border-collapse: collapse; background: white;
border-radius: 12px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
th { background: var(--mc-gray-100); padding: 1rem; text-align: left;
font-weight: 600; font-size: 0.875rem; color: #6b7280; }
td { padding: 1rem; border-top: 1px solid #f3f4f6; }
tr:hover { background: #fafafa; }
.badge { display: inline-block; padding: 0.25rem 0.75rem; border-radius: 9999px;
font-size: 0.75rem; font-weight: 600; }
.badge-draft { background: #dbeafe; color: #1d4ed8; }
.badge-discussing { background: #fef3c7; color: #d97706; }
.badge-voting { background: #ede9fe; color: #7c3aed; }
.badge-accepted { background: #d1fae5; color: #065f46; }
.badge-rejected { background: #fee2e2; color: #991b1b; }
.progress-bar { height: 6px; background: #e5e7eb; border-radius: 3px;
overflow: hidden; margin-top: 0.5rem; }
.progress-fill { height: 100%; border-radius: 3px; transition: width 0.3s; }
</style>
</head>
<body>
<div class="dashboard">
<h1>📋 MonkeyCode RFC Dashboard</h1>
<div class="stats">
<div class="stat-card">
<div class="stat-number">24</div>
<div class="stat-label">总 RFC 数</div>
</div>
<div class="stat-card">
<div class="stat-number" style="color: var(--mc-warning)">5</div>
<div class="stat-label">讨论中</div>
</div>
<div class="stat-card">
<div class="stat-number" style="color: #7c3aed">3</div>
<div class="stat-label">投票中</div>
</div>
<div class="stat-card">
<div class="stat-number" style="color: var(--mc-success)">16</div>
<div class="stat-label">已通过</div>
</div>
</div>
<div class="filters">
<button class="filter-btn active">全部</button>
<button class="filter-btn">技术 (T-)</button>
<button class="filter-btn">功能 (F-)</button>
<button class="filter-btn">流程 (P-)</button>
<button class="filter-btn">治理 (G-)</button>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>标题</th>
<th>分类</th>
<th>状态</th>
<th>作者</th>
<th>创建日期</th>
<th>投票进度</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>T-0025</strong></td>
<td>多语言支持架构设计</td>
<td>技术</td>
<td><span class="badge badge-voting">投票中</span></td>
<td>@alice</td>
<td>2026-06-15</td>
<td style="width: 200px">
<div class="progress-bar">
<div class="progress-fill" style="width: 75%; background: #7c3aed;"></div>
</div>
<small>6/8 赞成 (75%)</small>
</td>
</tr>
<tr>
<td><strong>F-0018</strong></td>
<td>VSCode 插件实时协作功能</td>
<td>功能</td>
<td><span class="badge badge-discussing">讨论中</span></td>
<td>@bob</td>
<td>2026-06-20</td>
<td>
<div class="progress-bar">
<div class="progress-fill" style="width: 0%; background: #d97706;"></div>
</div>
<small>讨论期剩余 8 天</small>
</td>
</tr>
<tr>
<td><strong>G-0003</strong></td>
<td>新增企业顾问委员会角色</td>
<td>治理</td>
<td><span class="badge badge-accepted">已通过</span></td>
<td>@tsc</td>
<td>2026-05-10</td>
<td>
<div class="progress-bar">
<div class="progress-fill" style="width: 92%; background: var(--mc-success);"></div>
</div>
<small>11/12 赞成 (92%)</small>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
七、案例研究:真实的 RFC 实例
案例 1:T-0001 — 插件系统架构设计
## RFC T-0001: MonkeyCode 插件系统架构设计
**状态**: ✅ Implemented (2026-03-15)
**作者**: @core-team
**讨论期**: 21 天
**投票结果**: 9/10 赞成 (90%) — 通过
### 背景
MonkeyCode 最初是单体架构,所有功能硬编码在核心代码中。
随着用户需求多样化,需要一种扩展机制让社区开发者能够
自定义功能。
### 最终方案
采用 **Provider + Hook** 双模式插件架构:
┌─────────────────────────────────────────────┐
│ MonkeyCode Core │
│ │
│ ┌───────────┐ ┌───────────┐ │
│ │ Provider │ │ Hook │ │
│ │ Registry │ │ System │ │
│ └─────┬─────┘ └─────┬─────┘ │
│ │ │ │
│ ┌─────┴─────┐ ┌─────┴─────┐ │
│ │ LLM │ │ Pre/Post │ │
│ │ Provider │ │ Callback │ │
│ └───────────┘ └───────────┘ │
│ │ │ │
│ ┌─────┴──────────────┴─────┐ │
│ │ Plugin Sandbox │ │
│ │ (Isolated Runtime) │ │
│ └──────────────────────────┘ │
│ │
└─────────────────────────────────────────────┘
### 关键决策点
| 决策点 | 选项 A | 选项 B | 最终选择 | 理由 |
|--------|--------|--------|---------|------|
| 插件语言 | JavaScript only | WASM + JS | WASM + JS | 性能 + 安全 |
| 沙箱机制 | 进程隔离 | V8 Isolate | V8 Isolate | 轻量级 |
| API 风格 | 声明式 | 命令式 | 声明式为主 | 易于理解 |
| 分发方式 | npm registry | 内置市场 | 内置市场 | 体验统一 |
### 实施效果
- 发布后 3 个月内,社区开发了 **47 个插件**
- 最受欢迎的插件:主题切换器(2.3K 安装)、代码格式化器(1.8K 安装)
- 2 个企业级插件被纳入官方推荐列表
案例 2:G-0001 — 引入企业顾问委员会
## RFC G-0001: 引入企业顾问委员会 (EAC)
**状态**: ✅ Accepted & Implemented (2026-04-01)
**作者**: @tsc-secretary
**讨论期**: 30 天
**投票结果**: 11/12 赞成 (92%) — 通过
### 背景
随着越来越多的企业使用 MonkeyCode,需要在治理层面
给予企业用户正式的参与渠道,同时保持项目的独立性和
社区驱动特性。
### 最终方案
┌─────────────────────────────────────────────────────────┐
│ MonkeyCode 治理结构 (更新后) │
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Technical Committee (TSC) │ │
│ │ 7 人: 3 Core Maintainers + 2 EAC + 2 Community│ │
│ └───────────────────┬───────────────────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────────┐ ┌────────────┐ │
│ │ Core │ │ Enterprise │ │ Community │ │
│ │ Team │ │ Advisory │ │ Council │ │
│ │ (5人) │ │ Council │ │ (5人) │ │
│ └─────────┘ │ (5人) │ └────────────┘ │
│ └─────────────┘ │
│ │
│ EAC 权利: │
│ ✓ 参与技术路线图讨论 │
│ ✓ 对 RFC 提出正式意见 │
│ ✓ 获得 6 个月提前通知(重大变更) │
│ ✗ 无直接投票权(但 TSC 中有 2 个席位) │
│ ✗ 无代码合并权 │
│ │
│ EAC 成员资格: │
│ • 企业年使用规模 ≥ 100 开发者 │
│ • 至少 1 名全职 MonkeyCode 用户 │
│ • 承诺每年至少参加 2 次 EAC 会议 │
│ • 签署利益冲突声明 │
│ │
└─────────────────────────────────────────────────────────┘
### 社区反馈亮点
**支持方观点**:
> "这让企业在投入 MonkeyCode 时更有信心,
> 知道他们的声音能被听到。" — @enterprise-user-1
**担忧方观点**:
> "需要确保 EAC 不会让项目偏向大企业需求,
> 忽视个人开发者的诉求。" — @individual-contributor
**最终平衡措施**:
- TSC 中社区代表席位固定 ≥ 2 个
- EAC 席位上限 ≤ TSC 总席位的 30%
- 所有 EAC 会议纪要公开
- 个人开发者可通过 Community Council 平衡影响力
八、快速启动你的项目治理
8.1 治理初始化 Checklist
## ☑️ 开源项目治理初始化清单
### 第一阶段:基础文档(第 1 周)
- [ ] 创建 `GOVERNANCE.md` — 治理概述文档
- [ ] 创建 `CODE_OF_CONDUCT.md` — 行为准则
- [ ] 创建 `CONTRIBUTING.md` — 贡献指南
- [ ] 创建 `MAINTAINERS.md` — 维护者名单及职责
- [ ] 创建 `rfc/` 目录和 `rfc/0000-template.md` — RFC 模板
### 第二阶段:流程建立(第 2-3 周)
- [ ] 定义角色层级(Visitor → Contributor → Maintainer)
- [ ] 建立 Issue/PR 处理 SLA
- [ ] 设定 Code Review 标准
- [ ] 制定 Release 流程
- [ ] 创建 SECURITY.md 安全政策
### 第三阶段:工具配置(第 4 周)
- [ ] 配置 GitHub Branch Protection Rules
- [ ] 设置 REQUIRED_STATUS_CHECKS
- [ ] 配置 CODEOWNERS 文件
- [ ] 设置 ISSUE_TEMPLATES 和 PR_TEMPLATES
- [ ] 配置自动化 Bot(如需要)
### 第四阶段:社区培养(持续)
- [ ] 识别和培养潜在维护者
- [ ] 定期举办 Community Call
- [ ] 发布月度治理报告
- [ ] 建立新人 Mentorship 项目
- [ ] 记录和分享决策理由(Decision Log)
### 第五阶段:持续优化(每季度回顾)
- [ ] 回顾治理规则的有效性
- [ ] 收集社区反馈
- [ ] 根据项目发展阶段调整治理模式
- [ ] 处理积累的技术债务
- [ ] 规划下一阶段的治理演进
结语
"好的治理不是限制自由,而是让自由有序地生长。"
开源社区的治理是一门平衡艺术——在效率与包容之间、在速度与质量之间、在创新与稳定之间找到最佳平衡点。MonkeyCode 的治理体系仍在不断演进中,我们相信最好的治理规则是那些能够自我更新的规则。
如果你正在为自己的开源项目设计治理机制,或者对 MonkeyCode 的治理实践有任何建议,欢迎通过 GitHub Discussions 与我们交流!
💡 相关资源:
- 📋 RFC 列表: rfc/
- 📜 治理文档: GOVERNANCE.md
- 🤝 行为准则: CODE_OF_CONDUCT.md
- 👥 维护者名单: MAINTAINERS.md
- 💬 治理讨论: Discussions > Governance
- 🐛 提交治理建议: GitHub Issues (标签:
governance)
MonkeyCode — 用透明的治理,共建可信的开源未来。 🐵⚖️✨
浙公网安备 33010602011771号