Skip to content

Commit 161df01

Browse files
committed
feat: add scoped cross-project memory
1 parent 5886bb4 commit 161df01

10 files changed

Lines changed: 330 additions & 51 deletions

File tree

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ STARKS_REVIEW_MODEL_CLAUDE=
1616
STARKS_REVIEW_TIMEOUT_SECONDS=600
1717

1818
# Project-memory directory (e.g. a subfolder of your Obsidian vault).
19-
# Configuring this only enables per-task read/write opt-in prompts.
19+
# Configuring this only enables task-scoped, budgeted read/write opt-in prompts.
2020
# Memory is never read or written automatically; unset skips the option entirely.
2121
# Example: ~/Obsidian/your-vault/starks-skill
2222
STARKS_MEMORY_DIR=

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ A single model has systematic blind spots — it tends to miss the same edge cas
2727
- **Truthful status board** — the PM remains responsive, posts live progress in commentary, and accepts `QUERY`, `ADD`, `CHANGE`, `REPLACE`, and `PRIORITY` messages while work continues.
2828
- **Two-stage review** — a reviewer checks spec compliance, then a reviewer checks code quality; failures loop back.
2929
- **Verification gate** — no "done / passing / fixed" claim without freshly-run evidence on the spot.
30-
- **Read opt-in / write opt-in** — Obsidian memory is never read or written automatically. When history may help, starks asks before reading; after reusable progress, it asks separately before writing.
30+
- **Scoped shared memory**Claude and Codex can share cross-project Obsidian facts, but nothing is searched, listed, read, or written automatically. Read access is task-scoped and budgeted; write access is separately enumerated and approved.
3131
- **Dual-platform** — one `SKILL.md`, symlinked into both Claude Code and Codex.
3232
- **Anti-recursion guard** — when invoked as a cross-reviewer, starks answers once and exits instead of re-entering its own flow.
3333

@@ -59,7 +59,7 @@ starks reads a few optional environment variables (all have defaults or degrade
5959
| `STARKS_REVIEW_MODEL_CODEX` | reviewer model when Codex reviews the plan (Claude→Codex) | unset → codex default |
6060
| `STARKS_REVIEW_MODEL_CLAUDE` | reviewer model when Claude reviews the plan (Codex→Claude) | unset → claude default |
6161
| `STARKS_REVIEW_TIMEOUT_SECONDS` | cross-review timeout in seconds | `600` |
62-
| `STARKS_MEMORY_DIR` | project-memory dir (e.g. an Obsidian vault subfolder); configuration only makes opt-in available | unset |
62+
| `STARKS_MEMORY_DIR` | shared project-memory root (e.g. an Obsidian vault subfolder); configuration only makes scoped opt-in available | unset |
6363
| `STARKS_STYLE_NOTE` | optional note the memory writer reads first to match your style | unset |
6464

6565
Export sub-agent and memory settings into the primary agent process. Reviewer settings may also live in `.env`; `scripts/cross-review.sh` reads them automatically and already-exported values take precedence.
@@ -72,7 +72,7 @@ starks doesn't run the same heavyweight pipeline on everything. When real work s
7272
- **light** — a single clear concern across a few files. Do it (or confirm in one line) and skip the parallel / cross-review machinery, but the verification gate still applies.
7373
- **full** — multi-file, architectural, large behavior change, or genuinely uncertain. This runs the whole flow.
7474

75-
For a full-tier task the flow is: **ask whether to recall project memory** when history may help (default: skip; after approval, read the short summary first and expand only as needed) → **grill** the requirements — multiple-choice first, batching independent questions — to surface hidden assumptions, edges, and success criteria → **draft** a plan → **present it for one decision** (a hard gate: start now / cross-review first / revise). Only if you pick cross-review does the plan go to the other model; the revised version comes back for sign-off. After approval the PM uses work-conserving scheduling: whenever a slot opens, safe Ready work from the dependency DAG starts without waiting for the whole wave, but work is never force-split merely to raise concurrency. The PM stays responsive, posts a truthful status board in commentary, and accepts new `QUERY`, `ADD`, `CHANGE`, `REPLACE`, and `PRIORITY` messages while work continues. It then runs the **two-stage review**, holds the **verification gate**, and asks separately before writing reusable progress to project memory. Read approval never implies write approval. See the [PM orchestration reference](references/pm-orchestration.md) for the detailed scheduling protocol.
75+
For a full-tier task the flow is: **ask whether to route shared project memory** when history may help (default: skip; the task-scoped approval names the metadata scan, files, and context budget) → **grill** the requirements — multiple-choice first, batching independent questions — to surface hidden assumptions, edges, and success criteria → **draft** a plan → **present it for one decision** (a hard gate: start now / cross-review first / revise). Only if you pick cross-review does the plan go to the other model; the revised version comes back for sign-off. After approval the PM uses work-conserving scheduling, runs the **two-stage review**, and holds the **verification gate**. At task end, reusable facts are offered as a separate, enumerated write; read approval never implies write approval. See the [PM orchestration reference](references/pm-orchestration.md) and [memory protocol](references/memory.md) for details.
7676

7777
Cross-review uses one stable wrapper; the full plan always travels over stdin:
7878

README.zh-CN.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
- **真实进度看板**——主 PM 保持响应,在 commentary 展示实时进度,并在执行中继续接收 `QUERY``ADD``CHANGE``REPLACE``PRIORITY` 类消息。
2626
- **两阶段审查**——先查规格合规,再查代码质量;不过则回炉。
2727
- **完成门禁**——宣称「完成 / 通过 / 修好」之前,必须有当场跑出的验证证据。
28-
- **读取前询问 / 写入前询问**——Obsidian 记忆默认不读不写;历史可能有帮助时先问是否读取,有可复用进展时再单独询问是否写入
28+
- **受控跨项目记忆**——Claude 与 Codex 可共享 Obsidian 事实,但默认不搜索、不列举、不读写;读取按任务授权并受预算约束,写入须另行枚举和确认
2929
- **双平台**——Claude Code 与 Codex CLI 共用同一份 skill 契约。
3030
- **防递归守卫**——被另一端模型调起做一次性互审时,自动跳过主流程,不会无限套娃。
3131

@@ -57,7 +57,7 @@ starks 从环境变量读取以下设置(都可选,有默认值或在缺失
5757
| `STARKS_REVIEW_MODEL_CODEX` | Codex 当 reviewer 时(Claude→Codex)使用的模型 | 未设用 Codex 默认 |
5858
| `STARKS_REVIEW_MODEL_CLAUDE` | Claude 当 reviewer 时(Codex→Claude)使用的模型 | 未设用 Claude 默认 |
5959
| `STARKS_REVIEW_TIMEOUT_SECONDS` | 跨模型互审超时秒数 | `600` |
60-
| `STARKS_MEMORY_DIR` | 项目记忆目录(如某 Obsidian vault 的子目录);配置后仅提供按次询问选项 | 未设置 |
60+
| `STARKS_MEMORY_DIR` | 共享项目记忆根目录(如某 Obsidian vault 子目录);配置后仅提供按任务授权选项 | 未设置 |
6161
| `STARKS_STYLE_NOTE` | 可选:记忆写手在动笔前先读的文风笔记路径 | 未设置 |
6262

6363
子代理和记忆配置需导出到主代理进程。reviewer 配置也可写入 `.env``scripts/cross-review.sh` 会自动读取,调用进程已导出的值优先。
@@ -70,16 +70,16 @@ starks 先对任务**分档**,再决定走多重:
7070
- **轻量**——单一关注点、需求清晰、涉及少数文件、低不确定性。直接做或一句话确认即可;可跳过跨模型互审与并行子代理,但完成门禁仍然适用。
7171
- **完整**——跨多文件 / 架构级 / 行为大改 / 明显不确定性。走完整流程:
7272

73-
1. **读取前询问**——仅在项目历史可能有帮助时询问;未明确同意就跳过,获准后先读 `<project>/summary.md`,不足时才展开 `memory.md`
73+
1. **读取前询问**——仅在项目历史可能有帮助时询问;授权须说明元数据路由、读取范围和上下文预算,未明确同意就完全跳过
7474
2. **拷问需求**——多选优先,互不依赖的小问题合并一次问,挖出隐藏假设、边界条件与成功标准。
7575
3. **起草方案**——收口需求并做轻量任务拆解。
7676
4. **呈现方案 + 用户定夺**——把方案交给用户三选:**A 直接开干 / B 先让另一端模型互审再定 / C 修改方案**。仅当选 B 才跑跨模型互审,整合修订版后回到本步重新定夺。互审不自动触发,也不闷头跳过。
7777
5. **PM 持续调度子代理**——安全的 Ready 工作会在槽位释放后持续补位,无需等待整波完成;写集合冲突或强耦合的工作仍保持串行。
7878
6. **两阶段审查**——先查规格合规,再查代码质量;不过回炉,最多 2 次,仍不过交回用户定夺。
7979
7. **完成门禁**——当场跑出验证证据才能宣称「完成 / 通过」。
80-
8. **写入前询问**——有实质可复用进展时另行询问;只有用户明确同意本次写入且平台规则允许,才把项目总结写入知识库
80+
8. **写入前询问**——任务终局有可复用事实时,枚举目标文件和事实后单独询问;读取授权不能复用为写入授权
8181

82-
执行期间,主 PM 保持响应并在 commentary 展示真实进度看板,也能继续接收 `QUERY``ADD``CHANGE``REPLACE``PRIORITY` 类新消息。详细协议见 [PM 编排参考](references/pm-orchestration.md)
82+
执行期间,主 PM 保持响应并在 commentary 展示真实进度看板,也能继续接收 `QUERY``ADD``CHANGE``REPLACE``PRIORITY` 类新消息。详细协议见 [PM 编排参考](references/pm-orchestration.md)[记忆协议](references/memory.md)
8383

8484
跨模型互审统一走包装器,方案全文通过 stdin 传递:
8585

SKILL.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ description: Use when starting real work — building a feature, adding or chang
4242
## 全局规则与专用 skill
4343

4444
- **完成门禁**:任何档位都必须先取得当场验证证据;无证据不得宣称“完成 / 通过 / 修好”。
45-
- **读取前询问**除 trivial 外,仅在项目历史可能有帮助且配置了 `STARKS_MEMORY_DIR` 时询问用户是否读取;未明确同意就跳过,不得先读 `_index.md` 探路。获准后先读 `summary.md`,摘要不足才按需读 `memory.md`;没有同名项目才查 `_index.md`,旧快照须现场复核
45+
- **读取前询问**:仅在项目历史可能有帮助且配置了 `STARKS_MEMORY_DIR` 时询问;未明确同意就跳过,获准后按 `references/memory.md` 的任务级作用域、路由和预算执行
4646
- bug、测试失败、非预期行为 → `systematic-debugging`;写或改 skill → `writing-skills`;超大或高不确定设计 → 先 `brainstorming`,完成设计后再回 starks。
4747

4848
## <HARD-GATE>(仅完整档)
@@ -57,13 +57,13 @@ description: Use when starting real work — building a feature, adding or chang
5757

5858
有 TodoWrite / `update_plan` 就跟踪以下七步,没有则跳过工具但不跳过步骤:
5959

60-
1. **拷问 grill** — 先按需询问是否读取记忆;仅获准后读取,再读相关文件与近期 commit,集中提问隐藏假设、边界和成功标准。
60+
1. **拷问 grill** — 先按需询问是否读取记忆;仅获准后按预算读取,再读相关文件与近期 commit,集中提问隐藏假设、边界和成功标准。
6161
2. **起草方案** — 收口需求并拆解任务,不另造冗长 plan 文件。
6262
3. **呈现方案 + 一次定夺** — 让用户选 **A 直接开干 / B 先让另一个模型(Claude↔Codex)互审再定 / C 改方案**。仅 B 运行互审,整合修订后回到本步再次定夺;不得自动互审或闷头跳过不提。
6363
4. **PM 编排** — 维护依赖图与 `Ready` 队列;有安全任务且可用并发槽位空闲就立即补位,不等待整波。并行写集合必须互斥,冲突时顺序执行或使用隔离 worktree;不得为追求代理数量硬拆任务。
6464
5. **两阶段审查** — 先按 `prompts/spec-review.md` 查 spec 合规,再按 `prompts/code-review.md` 查代码质量;不过就回炉,最多回炉 2 次,仍不过则报告卡点并让用户定夺。
6565
6. **完成门禁** — 当场运行能证明验收标准的完整验证,读清结果后才可作完成声明。
66-
7. **记忆收尾**有实质可复用进展时询问是否写入;仅用户对本次写入明确同意且平台规则允许才执行,绝不碰 `private/`
66+
7. **记忆收尾**任务终局且有实质可复用进展时最多询问一次;仅用户对枚举内容明确同意且平台规则允许才写入
6767

6868
## 跨模型互审
6969

@@ -84,10 +84,11 @@ description: Use when starting real work — building a feature, adding or chang
8484
## 记忆边界
8585

8686
- 未配置 `STARKS_MEMORY_DIR` 就跳过项目记忆;
87-
- **读取前询问**:配置目录只表示功能可用,不触发自动读取;本次未获明确同意就不读任何记忆文件;
88-
- **写入前询问**:有可复用进展才询问,本次未获明确同意就不写;读取同意不等于写入同意;
89-
- 获得写入同意后,仍须平台规则允许,并通过平台规定的 memory writer 入口写入;
90-
- 失败要报告,绝不碰 `private/`。具体入口、路径与降级规则见 `references/runtime.md``prompts/memory-writer.md`
87+
- **读取前询问**:配置只表示可用;本任务未获明确同意前,对记忆库不得 `Read / rg / ls / find / stat`,也不得查看元数据;拒绝后不再询问;
88+
- **写入前询问**:读取同意不等于写入同意;询问须枚举目标文件与事实,授权仅覆盖本次枚举内容;
89+
- 读取必须受预算约束;当前直接观察永远优先于记忆;写前须重读并检测冲突;
90+
- `private/` 永不读、写、列举;禁止软链逃逸,真实路径必须在根目录内;边界不清就 fail-closed;
91+
- 失败须报告。完整协议见 `references/memory.md`,执行入口见 `prompts/memory-reader.md``prompts/memory-writer.md`
9192

9293
## 红旗清单
9394

@@ -97,4 +98,4 @@ description: Use when starting real work — building a feature, adding or chang
9798
| 自动跑互审、完全不提互审,或失败后静默略过 | 回到用户三选;失败明确报告并重新授权。 |
9899
| 超出可用槽位、并行写集合相撞,或伪称指定了不受支持的模型 | 缩小并行、隔离写集,并如实说明平台能力。 |
99100
| 没验证就说“应该没问题 / 已完成” | 回到完成门禁,取得新鲜证据。 |
100-
| 未询问就读写记忆、把读取同意当写入同意,或触碰 `private/` | 停止操作并报告;不得绕过权限。 |
101+
| 未询问就扫描/读写记忆、超预算、复用读取授权写入,或触碰 `private/` | 停止操作并报告;不得绕过权限。 |

prompts/memory-reader.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Obsidian 记忆读取器
2+
3+
你的任务是为主代理执行一次受控的 Obsidian 跨项目记忆检索。完整规则见 `references/memory.md`;本 prompt 只给出可执行步骤。不要调用其他 skill、不要派子代理、不要写入记忆库。
4+
5+
## 先检查授权,不要先碰文件
6+
7+
未收到用户对**当前任务**的明确读取同意时,立即停止。此时不得对 `$STARKS_MEMORY_DIR` 执行 `Read``rg``ls``find``stat`,不得查看 frontmatter、`_index.md` 或环境对应路径,也不得用预扫描结果决定是否询问。
8+
9+
若主代理尚未询问,返回下面这类提示供其原样或等义询问;只能使用当前任务和 repo 已知信息来填写,不能先检查记忆库:
10+
11+
```text
12+
这个任务可能受既有项目记忆影响。是否允许我在本任务内检索 Obsidian 共享记忆?
13+
- 授权模式:MEMORY_READ_OPT_IN
14+
- 元数据范围:记忆根内最多 60 个直接项目的 summary.md 白名单 frontmatter(排除 private/、_shared/、.obsidian/ 和模板)
15+
- 正文范围:当前项目及筛选出的关联项目摘要;路由输出最多 1500 字符
16+
- 普通加载:最多 3 个 summary.md 正文、正文最多 4000 字符;路由与正文合计估算不超过 2500 token
17+
- 生命周期:授权仅限当前任务;不包含深度读取,也不包含任何写入
18+
```
19+
20+
用户拒绝、含糊回应或没有明确同意:返回“本任务跳过 Obsidian 记忆”,并标记本任务不再询问普通读取授权。
21+
22+
## 获得普通读取授权后
23+
24+
1. 记录授权作用域和预算。解析 `$STARKS_MEMORY_DIR` realpath;配置缺失、路径不可解析或边界不清时 fail-closed,报告后停止。
25+
2. 当前项目名取 repo 根目录 basename。禁止读取 `_index.md`;排除 `private/``_shared/``.obsidian/`、模板目录;不跟随 symlink;任何待访问文件的 realpath 必须仍在记忆根内。
26+
3. 最多检查 60 个直接项目条目。canonical 项目只提取 `*/summary.md` frontmatter 的 `project``tags``related``depends_on``status``updated`;白名单外字段不输出。三个数组字段不是单行内联数组时标记 schema 不兼容,不猜测。
27+
4. 没有 frontmatter 的项目只输出目录名和“未迁移”。不要读取正文、自动迁移或修改文件。
28+
5. 构造候选并保留来源:当前项目;当前项目主动 `related` / `depends_on`;其他项目指向当前项目的反向边;标签重叠;legacy 项目名。`related` 无向去重,`depends_on` 有向;反向边写明 `edge_source`
29+
6. 按“当前 > 直连 > 反向 > 标签重叠数 > updated”排序,项目名稳定打破平局;没有任何当前、关系或标签匹配的未迁移候选排在所有 canonical 匹配候选之后。路由输出最多 1500 Unicode 字符;达到项目或输出上限就报告未检查/未展示数量。
30+
7. 按排序加载最多 3 个 summary:先当前项目,再候选。未迁移或 schema 不兼容项目只有是当前项目或被当前项目 canonical frontmatter 直接点名时才能加载正文。
31+
8. summary 正文合计最多 4000 Unicode 字符。路由输出和 summary 注入合计估算最多 2500 token,公式为 `CJK × 1.0 + 其他字符 ÷ 4`;路由输出同时计入全任务字符/token 累计。任一上限先到就停止并报告截断。
32+
33+
不要自动扫描 `_shared/`。只有本次授权明确点名共享主题,或已加载 summary 指向安全共享文件且授权覆盖 `_shared/` 时才能读取;读取量计入全部预算。
34+
35+
## 需要深度读取时
36+
37+
普通摘要不够时先返回缺口和新的授权问题,未明确同意不得继续:
38+
39+
```text
40+
现有摘要不足以确认 <具体缺口>。是否允许本任务追加深度读取?
41+
- 授权模式:MEMORY_DEEP_READ_OPT_IN
42+
- 新增范围:最多 1 个相关项目 memory.md,正文最多 3000 字符
43+
- history:默认不读;只有你明确要求回顾历史时,最多 2 个相关文件
44+
- 全任务硬上限:5 个正文文件、8000 字符、估算 5000 token(均包含已加载内容)
45+
- 这仍然不包含写入授权
46+
```
47+
48+
获批后仅读取问题所需的最小范围。`history/` 必须由用户明确点名“回顾历史”等需求;总量达到 5 文件、8000 字符或估算 5000 token 任一上限即停止。普通元数据扫描不计正文文件数,但路由输出计入字符和 token。
49+
50+
## 返回给主代理
51+
52+
使用紧凑结构返回:
53+
54+
```text
55+
命中:<项目与匹配原因;反向边附 edge_source>
56+
读取:<实际正文文件列表>
57+
预算:<路由字符 / 正文字符 / 估算 token / 正文文件数>
58+
截断:<无,或未检查、未展示、未读取候选数量与原因>
59+
影响:<对当前任务有用的已验证事实、假设或冲突>
60+
```
61+
62+
当前任务直接观察优先于记忆。保留事实的 `source`,不要把它与关系声明的 `edge_source` 混为一谈。过期、`assumption``deprecated` 只作线索;发现冲突只报告,读取授权绝不允许回写。

0 commit comments

Comments
 (0)