Skip to content
42 changes: 42 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"permissions": {
"allow": [
"Bash(cd:*)",
"Bash(cd /e/Project/picoclaw && go test ./pkg/memory/... -v -count=1 2>&1)",
"Bash(cd /e/Project/picoclaw && golangci-lint run ./pkg/memory/... 2>&1)",
"Bash(cd /e/Project/picoclaw && golangci-lint run ./pkg/memory/... --fix 2>&1)",
"Bash(cd /e/Project/picoclaw && go test ./pkg/memory/... -count=1 2>&1)",
"Bash(cd /e/Project/picoclaw && go vet ./pkg/memory/... 2>&1)",
"Bash(cd /e/Project/picoclaw && go build ./... 2>&1)",
"Bash(cd /e/Project/picoclaw && go test ./pkg/memory/... -bench=. -benchmem -run=^$ 2>&1)",
"Bash(cd /e/Project/picoclaw && go test ./pkg/session/... -count=1 2>&1)",
"mcp__sequential-thinking__sequentialthinking",
"Bash(cd /e/Project/picoclaw && git push -u origin feat/jsonl-memory-store 2>&1)",
"Bash(head:*)",
"WebSearch",
"Bash(cd /e/Project/picoclaw && gh issue view 711 --comments 2>&1)",
"Bash(cd /e/Project/picoclaw && gh pr view 732 --comments 2>&1)",
"Bash(cd /e/Project/picoclaw && gh pr view 732 2>&1)",
"Bash(cd /e/Project/picoclaw && gh pr checks 732 2>&1)",
"Bash(echo no upstream remote:*)",
"Bash(cd /e/Project/picoclaw && git rebase upstream/main 2>&1)",
"Bash(cd /e/Project/picoclaw && go build ./pkg/memory/... 2>&1)",
"Bash(cd /e/Project/picoclaw && go test ./pkg/memory/... -count=1 -v 2>&1)",
"Bash(gh api:*)",
"Bash(git push:*)",
"Bash(go test:*)",
"Bash(find .:*)",
"Bash(golangci-lint run:*)",
"Bash(gh pr:*)",
"Bash(gh issue:*)",
"Bash(git fetch:*)",
"Bash(echo exit: $?:*)",
"WebFetch(domain:github.com)",
"Bash(git log:*)",
"Bash(grep:*)",
"Bash(ls:*)",
"Bash(go build:*)",
"Bash(go vet:*)"
]
}
}
161 changes: 161 additions & 0 deletions PicoClaw 26M2W3 社区开发者会议.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# PicoClaw 26M2W3 社区开发者会议

> **PicoClaw的设计目标**:轻量高效,任意部署;简单易用,普惠大众;
> **致PicoClaw开发者**:让我们携手加速AI奇点的到来,共同创造并见证历史。

---

## 26M2W3 概况

### 成果
* **Github 表现**:Star 17K+,Merge 100+ PR,Contributors 70+
* **用户规模**:微信群 1600+,Discord 1300+
* **开发者规模**:微信群 ~50,Discord ~40
* **生态进展**:PicoClaw 进入 Homebrew
* **工程进展**:Provider 完成重构
* **特别鸣谢**:daming, lxowalle 在假期的努力!

### 暴露的问题
* 第一次开展大规模社区协同开发,又是在假期期间,响应速度、社区协调、工程架构方面都暴露出了很多不足。
* PicoClaw 早期 vibe-coding 的快速实现架构在蜂拥而至的 PR 面前会迅速变成“屎山”和冲突地狱。
* 为尽快合并 PR,未充分验证社区开发者的能力,也没有提供合并指导规范,过早给予 write 权限,在上面架构问题下更暴露出问题。
* 忙于以上 PR 协调问题,拖后了文档和宣发进度。特别是宣发问题,被不放春节假的海外开发者项目 zeroclaw 趁虚而入。
* ⚠️ **警惕币圈!** 尤其是 pump.fun 空气币,不要认领参与!

> **会议核心任务**:本次周会主要需要划分项目板块,认领板块负责人,制订下周计划。以下内容社区开发者可以继续添加遗漏的地方。

---

## 开发板块

### 仓库管理
* 新建 `dev` 分支,`main` 分支推送严格化。
* 完善 `CONTRIBUTING.md`。
* **时区审核分工**:
* GMT+8 附近时区审核(中国)
* GMT+0 附近时区审核(欧洲):**Huaaudio**
* GMT-8 附近时区审核(美洲)
* 仓库权限申请:联系 **zepan** 审核。
* Readme 中公布本次会议的分工人员表格,方便开发者找寻对应人员审核。

### Provider(负责人:daming)
* **进度**:已重构完成。
* **计划**:
* 梳理支持和计划支持的 provider 协议列表及进度计划。
* **插件系统探索**:go 原生插件?(参考 [hashicorp/go-plugin](https://github.com/hashicorp/go-plugin))
* **优化思路**:现在各种系统的 LLM provider 都在重复造轮子,而且每新增一个 provider 都得再改代码、重新发版才能支持。应该把专业的事交给专业的组件来负责。我开了个新的开源项目——`open-next-router`,采用 nginx 原子化配置的思想,新增 provider 无需改代码,新增配置文件即可支持,提供了 go 的 sdk 包,可快速接入项目。PicoClaw 接入后可更聚焦于 agent 的实现而不是各种上游 provider 的适配,就能快其它 claw 一步。

### Channels(负责人:daming)
* **进度**:正在重构。
* **计划**:
* 梳理支持和计划支持的 channel 协议列表及进度计划。
* **附件支持讨论**:音频、视频、文件。
* 附件的生命周期应该由谁管理?channel 应该只负责下载文件,然后交由 Agent 消费完成后管理生命周期?
* 音频转文字是否要迁移到 agent 层?或者说附件应该在哪一层被处理?
* 发送附件的方法如何拓展?添加新的方法?拓展原有 Message?
* 群友建议的 **skill加channel**?(参考 [nanoclaw skill](https://github.com/qwibitai/nanoclaw/blob/main/.claude/skills/add-telegram/SKILL.md))
* **插件系统讨论**。
* **架构优化**:
* 抽离公共的 HTTP 服务器,采用 WebHook 通信的 channel 通过复用公共的服务器来节省资源和端口。
* Websocket 支持。
* 将路由相关字段(`peer_kind`、`peer_id`)从 metadata 中提升为 `InboundMessage` 的结构体字段。
* **状态管理**:聊天记录应该由 channel 管理还是 agent 管理?

### Agent(负责人:学欧)
* Agent Loop 机制优化。
* **记忆系统**:引入 SQLite。
* **Multi-Agent / Swarm** 支持。
* **模型能力回退链**:在主模型不支持多模态时,使用多模态模型进行辅助。

### Tools(负责人:学欧)
* 整理规范。
* 插件系统探索。

### Heartbeat / Status / Log 等(负责人:daming)
* 完善心跳、状态和日志监控。

### Skill
* 搜索 skill 的 skill,已合并 PR:[PR #332](https://github.com/sipeed/picoclaw/pull/332)。
* **安全与维护**:探讨 skill 的维护和安全性问题,防范目前常见的投毒现象。

### MCP(负责人:evo)
* **功能实现**:已有 PR [#376](https://github.com/sipeed/picoclaw/pull/376)、[#282](https://github.com/sipeed/picoclaw/pull/282)。
* 安卓手机操作支持。
* 浏览器操作 (`webmcp?` `action book?`):已有相关 PR ([agent-browser-tool](https://github.com/sipeed/picoclaw/tree/feat/agent-browser-tool))。

### 占用/效率优化(负责人:学欧)
* **目标**:优化内存占用与执行效率,希望控制在 **20M 以内**。
* **分析**:分析各个版本之间的内存占用变化,分析各个模块的内存占用情况。
* **裁剪**:裁剪出最小版本,用于宣发。

### Security
* 响应并修复安全机构发送的漏洞警示。
* 参考 openclaw 等现有仓库的安全措施,加固 PicoClaw。

### AI CI(负责人:政宇)
* 完善仓库的 CI 流程。
* 加入 AI review 等自动化流程。
* 完善发布流程、测试项目、release note、breaking change 记录。
* 根目录加上 `CLAUDE.md`?
* 增加 `loongarch` & `deb/rpm` 支持。

### UX Testing
* 对 release 版进行一般性测试。
* 站在小白用户角度对使用交互提出意见建议,比如完善 PicoClaw onboard 流程。
* 展示性优化:比如启动时刷屏 ascii-art 的 PicoClaw 标识,增加用户拍摄视频时的辨识度。

### 文档工作
* 仓库 Readme 美化,仓库文档整理、规范。
* 整理所有 Channel、Provider 的实现支持列表。
* 针对小白用户的各个 Provider、Channel 详细手把手教程文档。
* 建设 Wiki 页面(deepwiki?)。

---

## Release 待办事项 (Checklist)
- [ ] Provider
- [ ] Channel
- [ ] Agent
- [ ] Swarm
- [ ] Security
- [ ] MCP:浏览器
- [ ] 文档
- [ ] Logo
- [ ] Metadata 问题解决

---

## 关于插件系统测试方案(补充记录)
测试了以下几种方案:
1. **内置的 plugin 模块**:不考虑。不支持 Windows 等平台 ([plugin](https://pkg.go.dev/[email protected]))。
2. **hashicorp/go-plugin**:不考虑。占用资源过大,固件都增加了 20~30M。
3. **net/rpc**(client-server 模式):
* **优点**:支持热加载,插件可以保存运行状态。
* **缺点**:资源消耗较多(内存约增加 5M+,每个插件大小 10+M),每个插件占用一个端口,不太优雅。
4. **encoding/gob**(编译为可执行程序,由主程序调用并获取返回值):
* **优点**:支持热加载,消耗资源相对较少(测试固件大小增加了 376KB,内存消耗增加了 640KB)。
* **缺点**:无法保存运行状态(应该可以用 socket 等方法来优化支持)。

---

## 宣发板块

### 社区运营
* **宣发物料/策划**:负责人 **zepan**,再寻求 1~2 位有网感的社区成员。
* 制作标准 Logo, Slogan。
* 制作具有传播性的图文/视频等。
* 策划互动性、传播性强的用户活动,产生用户内容。
* KOL 建联等其它宣发手段。
* **微信群运营**:负责人 **zepan**。
* **推特运营**:负责人 **zepan**。
* **Discord运营**:负责人 **OsmiumOP**;需要再找一个国内开发者盯一下,会给予 admin 权限。
* **其他渠道开拓**:小红书、知乎、Reddit?
* **Go社区联络大使**:负责人 **卓**。

---

## 中期 TODO

* **桌面应用 / 安卓 APP**
* 架构讨论:C/S 还是单程序?接口文档规范?
* **配套硬件**
108 changes: 108 additions & 0 deletions PicoClaw贡献方向规划.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# PicoClaw 贡献方向规划(3月1日更新)

## 个人情况

- Go 开发者,会 Python,在学 AI Agent
- 已合并 PR:#173(多bug修复)、#186(安全加固)
- 已提交 PR:#732(JSONL session store,等待 review)
- 已关闭 PR:#719(SQLite 方案,被维护者建议改用 JSONL)

---

## 项目当前态势(3月1日)

### 已完成的重构
- Provider 重构:daming #492 — 完成
- Channel 重构 Phase 1:alexhoshina #662 — 完成
- Channel 重构 Phase 2:alexhoshina #877 (10,926行) — 2月27日合并
- Migrate 重构:lxowalle #910 — 2月28日合并

### 正在进行的重构
- **Tools 系统重构**:lxowalle PR #846(50个文件)— OPEN
- **Plugin 系统**:gh-xj PR #936-939(4个PR系列)— OPEN
- **Agent 系统重构**:alexhoshina Issue #772(roadmap)— 只有 issue,还没有 PR

### 我的行动记录
- 2月24日:在 #772 评论,将 PR #732 定位为 Agent 重构的 memory 子任务
- 3月1日:在 #295 评论,提出模型路由设计方案

---

## 战略方向

### 方向 1:智能模型路由(#295)— 主攻 ✅ 代码已完成

**为什么选这个**:
1. Zepan(创始人)亲自创建的 issue,roadmap 标签
2. 有大量社区讨论但零 PR
3. 独立模块 `pkg/routing/`,不碰任何重构区文件
4. 面试价值极高

**已完成(分支 feat/model-routing)**:
- `pkg/routing/features.go` — ExtractFeatures:5维结构评分,纯语言无关
- `pkg/routing/classifier.go` — Classifier 接口 + RuleClassifier(加权求和,上限 1.0)
- `pkg/routing/router.go` — Router:SelectModel,阈值默认 0.35
- `pkg/routing/router_test.go` — 34 个测试,全部通过
- `pkg/config/config.go` — RoutingConfig 添加到 AgentDefaults
- `pkg/agent/instance.go` — 预计算 Router + LightCandidates
- `pkg/agent/loop.go` — selectCandidates helper,turn 级别粘性路由

**3 个 commit,773 行新增,33 行修改,0 个新依赖**

**配置**:
```json
{
"agents": {
"defaults": {
"model": "claude-sonnet-4-6",
"routing": {
"enabled": true,
"light_model": "gemini-flash",
"threshold": 0.35
}
}
}
}
```

**下一步**:向上游 push 并开 PR,PR body 引用 issue #295

### 方向 2:JSONL Store 集成 — 等待时机

PR #732 已提交。等 Tools 重构 (#846) 合并后再做集成 PR。
已在 #772 评论建立关联。

### 方向 3:sessions CLI 子命令(#575)— 备选快速 PR

如果需要一个快速能合并的 PR 来积累信任:
- `picoclaw sessions list/clear/export`
- 不碰任何重构区文件
- 实用性强

---

## 需要避开的区域

| 区域 | 原因 |
|------|------|
| Tools 系统 | lxowalle PR #846 正在重构 |
| Plugin 系统 | gh-xj PR #936-939 正在做 |
| Channel 任何东西 | alexhoshina 刚完成大重构 |
| Provider 配置 | daming 已定型 |
| MCP | 两个竞争 PR (#282, #376) |
| Hooks 基础 | gh-xj #936 包含 pkg/hooks/ |
| AgentLoop 拆分 | SaiBalusu-usf PR #699 |
| Tool pair 修复 | QuietyAwe PR #871 |

---

## 关键人物(更新)

| 人 | GitHub | 角色 | 最近活动 |
|---|--------|------|---------|
| Zepan | @Zepan | 创始人 | #806 WebUI issue |
| daming | @yinwm | Provider/审核 | 审核 PR #877 |
| alexhoshina | @alexhoshina | Channel+Agent 重构 | #877 合并,#772 发起 |
| lxowalle | @lxowalle | Tools+审核 | #846 Tools重构中 |
| gh-xj | @gh-xj | Plugin 系统 | #936-939 四个 PR |
| nikolasdehor | @nikolasdehor | 社区活跃评论者 | 每个 issue 都有他 |
29 changes: 29 additions & 0 deletions pkg/agent/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ type AgentInstance struct {
Subagents *config.SubagentsConfig
SkillsFilter []string
Candidates []providers.FallbackCandidate

// Router is non-nil when model routing is configured and the light model
// was successfully resolved. It scores each incoming message and decides
// whether to route to LightCandidates or stay with Candidates.
Router *routing.Router
// LightCandidates holds the resolved provider candidates for the light model.
// Pre-computed at agent creation to avoid repeated model_list lookups at runtime.
LightCandidates []providers.FallbackCandidate
}

// NewAgentInstance creates an agent instance from config.
Expand Down Expand Up @@ -180,6 +188,25 @@ func NewAgentInstance(

candidates := providers.ResolveCandidatesWithLookup(modelCfg, defaults.Provider, resolveFromModelList)

// Model routing setup: pre-resolve light model candidates at creation time
// to avoid repeated model_list lookups on every incoming message.
var router *routing.Router
var lightCandidates []providers.FallbackCandidate
if rc := defaults.Routing; rc != nil && rc.Enabled && rc.LightModel != "" {
lightModelCfg := providers.ModelConfig{Primary: rc.LightModel}
resolved := providers.ResolveCandidatesWithLookup(lightModelCfg, defaults.Provider, resolveFromModelList)
if len(resolved) > 0 {
router = routing.New(routing.RouterConfig{
LightModel: rc.LightModel,
Threshold: rc.Threshold,
})
lightCandidates = resolved
} else {
log.Printf("routing: light_model %q not found in model_list — routing disabled for agent %q",
rc.LightModel, agentID)
}
}

return &AgentInstance{
ID: agentID,
Name: agentName,
Expand All @@ -200,6 +227,8 @@ func NewAgentInstance(
Subagents: subagents,
SkillsFilter: skillsFilter,
Candidates: candidates,
Router: router,
LightCandidates: lightCandidates,
}
}

Expand Down
Loading
Loading