Session: YYYY-MM-DD
Started: [approximate time if known] Last Updated: [current time] Project: [project name or path] Topic: [one-line summary of what this session was about]
What We Are Building
[1-3 paragraphs describing the feature, bug fix, or task. Include enough context that someone with zero memory of this session can understand the goal. Include: what it does, why it's needed, how it fits into the larger system.]
What WORKED (with evidence)
[List only things that are confirmed working. For each item include WHY you know it works — test passed, ran in browser, Postman returned 200, etc. Without evidence, move it to "Not Tried Yet" instead.]
- [thing that works] — confirmed by: [specific evidence]
- [thing that works] — confirmed by: [specific evidence]
If nothing is confirmed working yet: "Nothing confirmed working yet — all approaches still in progress or untested."
What Did NOT Work (and why)
[This is the most important section. List every approach tried that failed. For each failure write the EXACT reason so the next session doesn't retry it. Be specific: "threw X error because Y" is useful. "didn't work" is not.]
- [approach tried] — failed because: [exact reason / error message]
- [approach tried] — failed because: [exact reason / error message]
If nothing failed: "No failed approaches yet."
What Has NOT Been Tried Yet
[Approaches that seem promising but haven't been attempted. Ideas from the conversation. Alternative solutions worth exploring. Be specific enough that the next session knows exactly what to try.]
- [approach / idea]
- [approach / idea]
If nothing is queued: "No specific untried approaches identified."
Current State of Files
[Every file touched this session. Be precise about what state each file is in.]
| File | Status | Notes |
|---|---|---|
path/to/file.ts |
PASS: Complete | [what it does] |
path/to/file.ts |
In Progress | [what's done, what's left] |
path/to/file.ts |
FAIL: Broken | [what's wrong] |
path/to/file.ts |
Not Started | [planned but not touched] |
If no files were touched: "No files modified this session."
Decisions Made
[Architecture choices, tradeoffs accepted, approaches chosen and why. These prevent the next session from relitigating settled decisions.]
- [decision] — reason: [why this was chosen over alternatives]
If no significant decisions: "No major decisions made this session."
Blockers & Open Questions
[Anything unresolved that the next session needs to address or investigate. Questions that came up but weren't answered. External dependencies waiting on.]
- [blocker / open question]
If none: "No active blockers."
Exact Next Step
[If known: The single most important thing to do when resuming. Be precise enough that resuming requires zero thinking about where to start.]
[If not known: "Next step not determined — review 'What Has NOT Been Tried Yet' and 'Blockers' sections to decide on direction before starting."]
Environment & Setup Notes
[Only fill this if relevant — commands needed to run the project, env vars required, services that need to be running, etc. Skip if standard setup.]
[If none: omit this section entirely.]
这套结构并非随意设计:会话头部与正文中的结构化章节会被 [session-manager.js 的 `parseSessionMetadata`](https://gitcode.com/GitHub_Trending/ev/ECC/blob/22e8cf01d0b54719b3a49002fab2ccbda4ff5b9e/scripts/lib/session-manager.js?utm_source=gitcode_repo_files) 用正则解析出 `title`、`date`、`started`、`lastUpdated`、`project`、`branch`、`worktree`、`completed`、`inProgress`、`notes`、`context` 等元数据。也就是说,保存时的排版越规范,后续 `/sessions list`、`/sessions info` 能提取的信息就越丰富。
## 参考示例输出
以下是命令文档中展示的一份 JWT 认证开发会话的完整示例,可作为填写各类章节的对照样本:
```markdown
# Session: 2024-01-15
**Started:** ~2pm
**Last Updated:** 5:30pm
**Project:** my-app
**Topic:** Building JWT authentication with httpOnly cookies
---
## What We Are Building
User authentication system for the Next.js app. Users register with email/password,
receive a JWT stored in an httpOnly cookie (not localStorage), and protected routes
check for a valid token via middleware. The goal is session persistence across browser
refreshes without exposing the token to JavaScript.
---
## What WORKED (with evidence)
- **`/api/auth/register` endpoint** — confirmed by: Postman POST returns 200 with user
object, row visible in Supabase dashboard, bcrypt hash stored correctly
- **JWT generation in `lib/auth.ts`** — confirmed by: unit test passes
(`npm test -- auth.test.ts`), decoded token at jwt.io shows correct payload
- **Password hashing** — confirmed by: `bcrypt.compare()` returns true in test
---
## What Did NOT Work (and why)
- **Next-Auth library** — failed because: conflicts with our custom Prisma adapter,
threw "Cannot use adapter with credentials provider in this configuration" on every
request. Not worth debugging — too opinionated for our setup.
- **Storing JWT in localStorage** — failed because: SSR renders happen before
localStorage is available, caused React hydration mismatch error on every page load.
This approach is fundamentally incompatible with Next.js SSR.
---
## What Has NOT Been Tried Yet
- Store JWT as httpOnly cookie in the login route response (most likely solution)
- Use `cookies()` from `next/headers` to read token in server components
- Write middleware.ts to protect routes by checking cookie existence
---
## Current State of Files
| File | Status | Notes |
| -------------------------------- | -------------- | ----------------------------------------------- |
| `app/api/auth/register/route.ts` | PASS: Complete | Works, tested |
| `app/api/auth/login/route.ts` | In Progress | Token generates but not setting cookie yet |
| `lib/auth.ts` | PASS: Complete | JWT helpers, all tested |
| `middleware.ts` | Not Started | Route protection, needs cookie read logic first |
| `app/login/page.tsx` | Not Started | UI not started |
---
## Decisions Made
- **httpOnly cookie over localStorage** — reason: prevents XSS token theft, works with SSR
- **Custom auth over Next-Auth** — reason: Next-Auth conflicts with our Prisma setup, not worth the fight
---
## Blockers & Open Questions
- Does `cookies().set()` work inside a Route Handler or only in Server Actions? Need to verify.
---
## Exact Next Step
In `app/api/auth/login/route.ts`, after generating the JWT, set it as an httpOnly
cookie using `cookies().set('token', jwt, { httpOnly: true, secure: true, sameSite: 'strict' })`.
Then test with Postman — the response should include a `Set-Cookie` header.
注意示例中 "What Did NOT Work" 的写法原则:必须写精确原因("threw X error because Y"),而不是笼统的 "didn't work"——后者对下一个会话毫无价值。
存储位置与目录解析:从 ~/.claude/session-data 到 ECC_AGENT_DATA_HOME
命令文档约定存储位置为 ~/.claude/session-data/。从源码看,这一路径由 scripts/lib/utils.js 的 getSessionsDir()(path.join(getClaudeDir(), 'session-data'))解析得出,而 getClaudeDir() 实际代理到 scripts/lib/agent-data-home.js 的 resolveAgentDataHome(),其解析优先级为:
- 环境变量
ECC_AGENT_DATA_HOME(显式可信覆盖); - 项目级配置
.cursor/ecc-agent-data.json中声明的agentDataHome/ECC_AGENT_DATA_HOME字段(必须是~锚定或绝对路径,且不允许..穿越,并通过assertWithinTrustedRoot校验仍处于默认 Cursor / Claude 数据目录内); - 运行环境判定:Cursor hook 运行时(检测
CURSOR_VERSION/CURSOR_PROJECT_DIR)回落到~/.cursor/ecc,其余默认~/.claude。
因此命令文档中 "canonical sessions folder in the user's Claude home directory" 的说法,在跨 harness(Cursor、Codex、Opencode)部署时会解析到对应 agent 数据主目录下的 session-data/ 子目录。
同时,读取侧保持向后兼容:getSessionSearchDirs() 返回 [getSessionsDir(), getLegacySessionsDir()] 的去重数组,其中旧目录为 ~/.claude/sessions。这正是 commands/resume-session.md 中"legacy format 文件也能被加载"以及 /sessions 支持"legacy reads from ~/.claude/sessions/"的底层原因。写入新会话文件时仍应使用 ~/.claude/session-data/ 这一规范目录。
文件名合法性的正则实现与日历级校验
会话文件命名并非仅靠文档约定——session-manager.js 顶部声明的正则对每种命名形态都有精确对应:
const SESSION_FILENAME_REGEX = /^(\d{4}-\d{2}-\d{2})(?:-([a-zA-Z0-9_][a-zA-Z0-9_-]*))?-session\.tmp$/;
逐段拆解可以看到命名约束的严谨之处:
(\d{4}-\d{2}-\d{2}):日期部分,YYYY-MM-DD;(?:-([a-zA-Z0-9_][a-zA-Z0-9_-]*))?:整个 short-id 段可选(兼容旧格式);short-id 第一个字符必须是字母、数字或下划线(不能以连字符开头),其后可跟字母、数字、下划线、连字符;-session\.tmp$:固定后缀。
该正则能匹配 2026-02-01-session.tmp、2026-02-01-a1b2c3d4-session.tmp、2026-02-01-frontend-worktree-1-session.tmp、2026-02-01-ChezMoi_2-session.tmp 四类文件名——frontend-worktree-1 之所以合法,正是因为后续连字符段由 [a-zA-Z0-9_-]* 承接。
更值得注意的是日期校验并不停留在格式层。parseSessionFilename() 会额外做日历准确性校验:月份必须在 1-12、日期必须在 1-31,然后构造 new Date(year, month - 1, day) 并反向核对 getMonth()/getDate(),以剔除诸如 2 月 31 日、4 月 31 日这类会被 Date 自动"滚过去"的非法日期。文件头解析日期时还刻意使用本地时间构造函数 new Date(year, month - 1, day) 而非 new Date(dateStr),避免负 UTC 时区下日期"显示成前一天"的问题。这些边界行为在 tests/lib/session-manager.test.js 中有成体系的用例覆盖,例如 rejects Feb 31 (calendar-inaccurate date)、rejects Feb 29 in non-leap year、accepts Feb 29 in leap year、accepts uppercase letters in short ID、accepts underscores in short ID 等。
底层读写与去重排序逻辑
会话文件的 CRUD 全部封装在 scripts/lib/session-manager.js 的导出函数中,save-session 的"写文件"动作对应其中:
writeSessionContent(sessionPath, content):以utf8同步写入;appendSessionContent(sessionPath, content):追加内容(供会话中途追加保存场景使用);sessionExists(sessionPath):判断会话是否已存在;deleteSession(sessionPath):删除会话文件。
读取侧的关键设计是多目录扫描 + 去重 + 排序:
getSessionCandidates()遍历getSessionSearchDirs()(规范目录优先),仅收集.tmp后缀且能通过文件名解析的文件;- 文件系统细节上,创建时间优先取
birthtime,当birthtimeMs为 0(如容器 overlayfs 环境)时回退到ctime; - 按文件名去重(规范目录条目优先,即便 legacy 副本更新也会被规范目录条目覆盖,测试用例
getAllSessions prefers canonical session-data duplicates over newer legacy copies即验证此行为); - 最终按
modifiedTime降序排列。
getSessionById() 的匹配方式也相当宽松:short-id 支持前缀匹配(metadata.shortId.startsWith(normalizedSessionId)),同时还支持传完整文件名、去掉 .tmp 的文件名,以及旧格式无 ID 文件的 YYYY-MM-DD-session.tmp 精确匹配。因此 /resume-session 2024-01-15、/resume-session a1b2 这类模糊用法都能命中目标。
与 /resume-session 配对:保存之后如何续接
保存的最终目的是续接。在 ECC 中,续接入口是 commands/resume-session.md(与 /save-session 互为配套命令),其加载行为与 save-session 的文件结构严格咬合:
- 无参数:默认读取
session-data中最新的实质会话文件; - 传日期
YYYY-MM-DD:先搜session-data、再搜 legacysessions,应用候选排序后取当日最高排名文件; - 传文件路径:原样精确读取该文件,不参与候选排序、不被其他更新文件替代。
续接前会对自动发现(非显式路径)的候选做内容质量排名:先剔除空文件、纯占位符文件(如只有 headings / metadata / [Session context goes here] / 孤立的 - [ ])以及"仅含单一任务且无实质填充字段"的摘要回声;随后在实质候选间按修改时间取新,时间相同时依次比较填充章节数、非占位内容量、字节数、字典序更小的解析路径,从而让选择结果可确定。这解释了 save-session 文档为何反复强调"每个章节都要诚实填写"——文件不完整,续接时就会被排名机制淘汰。
恢复时,Agent 会以固定简报格式输出 SESSION LOADED、PROJECT、WHAT WE'RE BUILDING、CURRENT STATE、WHAT NOT TO RETRY、OPEN QUESTIONS / BLOCKERS、NEXT STEP,然后等待用户指令,绝不自动动工。其中 "What Not To Retry" 被刻意要求必须展示(即使为空)——与保存模板中 "What Did NOT Work (and why) 是最重要章节" 的定位前后呼应,因为"失败原因"是防止未来会话盲目重试失败方案的关键护栏。
保存与恢复的另一条纪律是:续接时只读、绝不修改历史会话文件,它是一份只读历史记录;新会话结束时应再次运行 /save-session 生成一份新的带日期文件,而不是追加到旧文件。
会话的日常管理与别名
当 session-data 中的文件积累变多后,可用 commands/sessions.md 管理会话历史(列表、加载、别名、信息、删除别名)。其常用命令:
/sessions # 列出全部会话(默认)
/sessions list --limit 10 # 仅显示 10 条
/sessions list --date 2026-02-01 # 按日期过滤
/sessions list --search abc # 按会话 ID 搜索
/sessions load a1b2c3d4 # 按 short ID 加载(前缀足够短也常可用)
/sessions alias 2026-02-01 today # 给会话创建别名
/sessions load today # 按别名加载
/sessions info today # 显示会话统计
/sessions alias --remove today # 删除别名
/sessions aliases # 列出全部别名
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00