Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# 复制为 .env 并按需修改(start-all.sh 自动加载)
# 复制为 .env 并按需修改(start.sh 自动加载)
TTMUX_WEB_PASSWORD=pwd
TTMUX_WEB_BIND=0.0.0.0:8080
# TTMUX_BIN=/path/to/ttmux
# 可选:Claude Code 精美 UI kanna 的地址(需自行安装运行且对本网可达),设置后任务页 Agent 行会出现入口
# TTMUX_KANNA_URL=http://192.168.130.19:3210
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,30 @@ your local command line or browser was closed.

## Install And Start

Install the CLI and build the Web console with one line:

```bash
curl -fsSL https://raw.githubusercontent.com/ybz21/ttmux/main/install.sh | bash
```

`install.sh` is a thin orchestrator over `scripts/` — a preflight system check
plus three modules: **[1]** ttmux CLI + skills, **[2]** chrome + Node + Playwright,
**[3]** the backend build (frontend `dist` + Go binary). It installs `ttmux` and
`chrome` to `~/.local/bin` and builds the Web console artifacts, but **does not
start anything**. Run through `curl | bash` it fetches the modules from GitHub on
demand; inside a clone it sources them locally. `TTMUX_SKIP_BACKEND=1` installs
only the CLI/chrome.

Then start the Web console from a checkout:

```bash
cp .env.example .env
./start-all.sh
./start.sh # start the built artifacts (no recompile)
# ./start.sh --dev # development: rebuild frontend + backend each run
```

`start.sh` also takes `stop` / `status` / `logs` / `fg`.

By default the Web console listens on `0.0.0.0:13579`, so devices on the same LAN
can reach it. Change the password before real use:

Expand All @@ -110,6 +125,10 @@ For remote access, prefer Tailscale, Cloudflare Tunnel, SSH forwarding, or frp.
Do not expose the Web console directly to the public Internet without a tunnel,
a strong password, and 2FA.

Exposing Roam through **frp with HTTPS** — required so mobile voice input and
clipboard keep working through the tunnel — is covered in
[docs/deploy/frp.md](docs/deploy/frp.md).

Full deployment notes are in [docs/install/README.md](docs/install/README.md).

## For Claude Code And Codex
Expand Down Expand Up @@ -164,7 +183,7 @@ bash cli/chrome-cli/build.sh
Build and run the Web console:

```bash
./start-all.sh fg
./start.sh --dev fg
```

Frontend only:
Expand Down
20 changes: 17 additions & 3 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,34 @@ Roam 的重点不是“多一个终端工具”,而是让开发机变成一个

## 安装与启动

一行安装 CLI 并构建 Web 控制台:

```bash
# 一键安装
curl -fsSL https://raw.githubusercontent.com/ybz21/ttmux/main/install.sh | bash
```

`install.sh` 是 `scripts/` 之上的瘦编排器——先做系统检查,再跑三个模块:
**[1]** ttmux CLI + skills、**[2]** chrome + Node + Playwright、**[3]** 构建后端
(前端 `dist` + Go 二进制)。它把 `ttmux`/`chrome` 装到 `~/.local/bin` 并构建好
产物,但**不启动任何服务**。经 `curl | bash` 运行时按需从 GitHub 拉各模块,在
clone 里则直接 source 本地模块。`TTMUX_SKIP_BACKEND=1` 只装 CLI/chrome。

然后在仓库目录里启动 Web 控制台:

```bash
# 启动 Web 控制台
cp .env.example .env
./start-all.sh
./start.sh # 直接启动已构建产物(不重新编译)
# ./start.sh --dev # 开发模式:每次重新编译前端+后端
```

`start.sh` 还支持 `stop` / `status` / `logs` / `fg`。

默认监听 `0.0.0.0:13579`,局域网设备可以直接访问。正式使用前请修改 `.env` 里的
访问口令;远程访问建议走 Tailscale、Cloudflare Tunnel、SSH forwarding 或 frp。

通过 **frp 暴露并保持 HTTPS**(让手机语音输入、剪贴板经隧道仍可用)的配置见
**[docs/deploy/frp.md](docs/deploy/frp.md)**(中英双语)。

完整安装、部署、远程访问和命令行自动化说明见 **[docs/install/](docs/install/)**。

## 给 Claude Code / Codex 用
Expand Down
2 changes: 1 addition & 1 deletion backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ ttmux 的 Web 控制台后端,是 ttmux CLI 的薄封装:读 = 调 `ttmux <c

```bash
# 在仓库根目录(构建前端 → 编译后端 → 启动)
./start-all.sh
./start.sh --dev
```

配置走仓库根目录的 **`.env`**(见 `.env.example`),真实环境变量优先于 `.env`
Expand Down
22 changes: 18 additions & 4 deletions backend/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import (

type API struct {
TT *ttmux.Client
KannaURL string // 可选:Claude Code 精美 UI(kanna)的地址;为空则前端不显示入口
BrowserHome string // 浏览器导航起始页地址(供前端设为默认主页)
Football *FootballStore
Speech *SpeechStore // 语音识别(ASR)配置 + 转录
}

func New(tt *ttmux.Client, kannaURL, browserHome string) *API {
return &API{TT: tt, KannaURL: kannaURL, BrowserHome: browserHome, Football: NewFootballStore()}
func New(tt *ttmux.Client, browserHome, dataDir string) *API {
return &API{TT: tt, BrowserHome: browserHome, Football: NewFootballStore(), Speech: NewSpeechStore(dataDir)}
}

// json 透传 ttmux 的 --json 输出
Expand All @@ -47,7 +47,7 @@ func (a *API) text(c *gin.Context, args ...string) {
}

func (a *API) Me(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"data": gin.H{"authed": true, "kanna": a.KannaURL, "browserHome": a.BrowserHome}})
c.JSON(http.StatusOK, gin.H{"data": gin.H{"authed": true, "browserHome": a.BrowserHome}})
}
func (a *API) Info(c *gin.Context) { a.json(c, "info", "--json") }

Expand Down Expand Up @@ -172,6 +172,20 @@ func (a *API) SessionCwd(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"data": gin.H{"dir": dir}})
}

// SessionType POST /sessions/:name/type —— 把文本字面量打进当前 pane(不追加回车)。
// 供终端页语音识别后回填用:内容停在输入行,用户复查/编辑后自行按 Enter 发送。
func (a *API) SessionType(c *gin.Context) {
name := c.Param("name")
var b struct {
Text string `json:"text"`
}
if err := c.ShouldBindJSON(&b); err != nil || b.Text == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": gin.H{"code": "BAD_REQUEST"}})
return
}
a.text(c, "send-keys", "-t", name, "-l", b.Text)
}

// Tasks(命令 + Agent 统一)
func (a *API) Tasks(c *gin.Context) { a.json(c, "group", "ls", "--json") }
func (a *API) TaskStatus(c *gin.Context) { a.json(c, "status", c.Param("g"), "--json") }
Expand Down
27 changes: 25 additions & 2 deletions backend/api/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"text/template"
)

//go:embed prompts/*.tmpl
//go:embed prompts/*.tmpl prompts/roles/*.md
var promptFS embed.FS

// promptCtx 是模板渲染上下文。
Expand All @@ -23,9 +23,11 @@ type promptCtx struct {
Task, Deps, Workdir, SkillsDir string
MasterName string
Peers []string
Subrole, SubroleLabel, Duty string // 细分角色 key/中文 + 长期职责
RoleTrait string // prompts/roles/<subrole>.md 渲染前注入(角色工作方式)
}

// skillsDir 返回 agent 自动加载 skill 的目录(install.sh / start-all.sh 同步到此)。
// skillsDir 返回 agent 自动加载 skill 的目录(install.sh / start.sh --dev 同步到此)。
func skillsDir() string {
if d := os.Getenv("TTMUX_SKILLS_DIR"); d != "" {
return d
Expand All @@ -35,14 +37,35 @@ func skillsDir() string {
}

// renderMemberPrompt 按角色选模板并渲染;失败时返回空串(调用方回退到原始任务)。
// 渲染前把细分角色归一、补 label,并读入 prompts/roles/<key>.md 角色片段 → RoleTrait。
func renderMemberPrompt(ctx promptCtx) string {
if ctx.Subrole != "" {
ctx.Subrole = subroleNorm(ctx.Subrole)
ctx.SubroleLabel = subroleLabel(ctx.Subrole)
ctx.RoleTrait = roleTrait(ctx.Subrole)
}
name := "worker.md.tmpl"
if ctx.Role == "leader" || ctx.Role == "master" {
name = "master.md.tmpl"
}
return renderPrompt(name, ctx)
}

// roleTrait 读取 prompts/roles/<key>.md(自定义/未命中 → 空串)。
// 支持 TTMUX_PROMPT_DIR 覆盖;内置嵌入到二进制。
func roleTrait(key string) string {
rel := "prompts/roles/" + key + ".md"
if dir := os.Getenv("TTMUX_PROMPT_DIR"); dir != "" {
if data, err := os.ReadFile(filepath.Join(dir, "roles", key+".md")); err == nil {
return strings.TrimSpace(string(data))
}
}
if data, err := promptFS.ReadFile(rel); err == nil {
return strings.TrimSpace(string(data))
}
return ""
}

// renderLeaderKickoff 渲染「自动拉起的 Leader」开场白(swarm new / adopt 时用)。
// 与 master.md.tmpl 不同:它没有起步任务,要从目标走完整生命周期(拆任务→派活→巡检→集成),
// 所以单独用 auto_leader.md.tmpl,并强调「编排而非单干」。失败返回空串,CLI 回退到 /cc-swarm。
Expand Down
8 changes: 6 additions & 2 deletions backend/api/prompts/auto_leader.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@

1. **建需求**:把目标写成清晰规格(范围 / 验收标准 / 约束)。目标模糊就先扫项目或问 human,**别拿模糊目标硬开会话**。
2. **拆任务上看板**:拆成可并行 / 有依赖的子任务 —— `ttmux swarm task add {{.Swarm}} "<子任务>" [--deps tN]`。
3. **派活**:每个子任务开一个子会话 —— `ttmux swarm add {{.Swarm}} <成员> --type agent "<任务>"`(有依赖加 `--depends-on`),再 `ttmux swarm task assign {{.Swarm}} <卡> <成员>`。
- **严禁自己一个人闷头实现**:可并行的部分必须分给子会话,你只负责编排与验收。
3. **派活**:每个子任务开一个子会话,并给它定**细分角色 + 职责** ——
`ttmux swarm add {{.Swarm}} <成员> --type agent --subrole <pm|architect|frontend|backend|fullstack|qa|designer|reviewer|devops|docs> --duty "<长期负责什么>" "<起步任务>"`
(依赖加 `--depends-on`,但注意:**依赖是软的——成员一建出来就立即开工,不会挂起**;缺上游产出时它自己去广场等/问),
再 `ttmux swarm task assign {{.Swarm}} <卡> <成员>`。
- 像组建一支班子:产品/架构/前后端/测试各司其职;`--subrole` 决定子会话拿到的角色化 prompt,**务必给每个成员带 `--subrole` 和 `--duty`**。
- 一次把成员加全,让它们**并行开工**、靠广场+看板协调;**严禁自己一个人闷头实现**。
4. **巡检**:持续读增量 —— `ttmux swarm listen {{.Swarm}} --as leader --once` / `feed` / `board`。human、`@leader`、`@all` 消息最高优先级,即使群已完成也要判断是否需重开 / 派活 / 答复。
5. **推进解锁**:成员完成 → 验收 → `ttmux swarm done {{.Swarm}} <成员>` 解锁下游。Web 类成果用 `chrome` 真跑一遍(开页面 / 点按钮 / 断言文本),别只读代码。
6. **集成验收**:全部完成后集成、对照验收标准检查,再 `ttmux swarm done {{.Swarm}}` 收尾并向 human 汇报。
Expand Down
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/architect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 先定**接口契约 / 数据结构 / 分层**,把它冻结并广播,让前后端能并行而不互相阻塞。
- 选型给理由,权衡复杂度与工期;避免过度设计。
- 契约一旦变更,立刻 `swarm say --kind note` 通知受影响成员;你为「能并行、不返工」负责。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 按 architect 的接口契约实现服务/数据层;对外行为以契约为准,内部实现自由。
- 边界与错误要处理:输入校验、失败返回、并发与幂等;别只写主流程。
- 给前端可联调的接口(mock/示例),完成前自测关键路径,再 `swarm done`。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/designer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 产出视觉/交互规范(布局、配色、状态、间距),给前端可直接落地的标注,别只给模糊描述。
- 兼顾可用性与一致性;复用既有设计语言,不无谓造新样式。
- 和前端确认实现边界(哪些可做、成本如何),把稿子落到文档供对照。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/devops.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 负责构建/部署/CI 与运行环境;产出可复现的脚本/配置,别留只在你机器上能跑的步骤。
- 改动基础设施前评估影响面,危险操作(删数据/改线上)先确认再做。
- 把启动/部署方式写清供他人复用,完成前实跑一遍验证。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 写面向读者的文档:怎么用、为什么这么设计、边界与坑;与实际代码/行为对齐,别写过时内容。
- 示例可复制可运行;术语统一。改动涉及他人模块先核实事实再落笔。
- 文档落到仓库 `docs/` 或既有位置,完成后广播让相关成员校对。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/frontend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 严格按 architect 冻结的接口/契约取数,不自造字段;契约不清就 `--to leader --kind ask`。
- 像素级还原设计;**loading / 空 / 错误** 状态都要覆盖,别只做 happy path。
- 自检用 `chrome` 真跑:开页面、点按钮、断言文本,别只读代码就报完成。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/fullstack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 端到端负责:从接口到 UI 打通一条可用链路,优先让主流程跑通再补边界。
- 跨层改动注意契约一致性;涉及他人负责的层先对齐,别擅自改公共契约。
- Web 成果用 `chrome` 真跑验收(开页面、点按钮、断言文本)。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/pm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 先把目标写清:范围、用户故事、**验收标准**(可勾选的检查项),模糊就先问 human,别让工程师猜。
- 产出落到看板/文档,供架构与工程对齐;需求变更要显式广播 `swarm say --kind note`
- 不写实现代码;你的交付是「清晰、可验收的需求」。验收阶段对照标准逐条核。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/qa.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 先读被测产物的**验收标准**,再动手;用例覆盖正常 / 边界 / 异常三类。
- Web 类成果用 `chrome` 真跑断言(开页面、点按钮、读文本),别只读代码。
- 发现缺陷用 `swarm say --kind block` 回报给负责人,**不替对方改实现**;复测通过再放行。
3 changes: 3 additions & 0 deletions backend/api/prompts/roles/reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- 架构级 review:正确性、边界、可维护性、与契约/需求是否一致;不纠结无关风格。
- 发现问题用 `swarm say --kind block`/`ask` 提具体可执行的 challenge,指明位置与改法。
- 你不替作者改实现;确认修复后再放行。高风险改动(删库/force push)必须拦。
14 changes: 10 additions & 4 deletions backend/api/prompts/worker.md.tmpl
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
# {{.Member}} · Member
# {{.Member}} · {{with .SubroleLabel}}{{.}}{{else}}Member{{end}}

**蜂群**:{{.Swarm}}{{if .Goal}}
**目标**:{{.Goal}}{{end}}
**目标**:{{.Goal}}{{end}}{{if .Duty}}
**职责**:{{.Duty}}{{end}}

## 你的任务
## 你的起步任务

{{.Task}}
{{if .Deps}}
> 依赖:{{.Deps}}(依赖就绪后才轮到你)
> 你依赖:**{{.Deps}}**。现在就开工——能并行的部分(脚手架、接口约定、mock、自测)先做起来;
> 真正需要 {{.Deps}} 的产出时,去广场看它是否已播报/`swarm done`,没有就 `--to leader|{{.Deps}} --kind ask` 问,**别凭空臆造接口**。
{{end}}{{if .RoleTrait}}
## 你的工作方式({{.SubroleLabel}})

{{.RoleTrait}}
{{end}}
## 协作方式(务必遵循 swarm 格式)

Expand Down
Loading
Loading