session-chronicle
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSession Chronicle
会话编年史
Excavate Claude Code session logs to capture complete provenance for research findings, ADR decisions, and code contributions. Traces UUID chains across multiple auto-compacted sessions.
CRITICAL PRINCIPLE: Registry entries must be self-contained. Record ALL session UUIDs (main + subagent) at commit time. Future maintainers should not need to run archaeology to understand provenance.
S3 Artifact Sharing: Artifacts can be uploaded to S3 for team access. See S3 Sharing ADR.
挖掘Claude Code会话日志,为研究成果、ADR决策和代码贡献捕获完整溯源信息。跨多个自动压缩的会话追踪UUID链。
核心原则:注册表条目必须自包含。在提交时记录所有会话UUID(主会话+子代理会话)。未来的维护者无需重新执行会话考古即可理解溯源信息。
S3工件共享:工件可上传至S3供团队访问。查看S3共享ADR。
When to Use This Skill
何时使用此技能
- User asks "who created this?" or "where did this come from?"
- User says "document this finding" with full session context
- ADR or research finding needs provenance tracking
- Git commit needs session UUID references
- Tracing edits across auto-compacted sessions
- Creating a registry entry for a research session
- 用户询问“谁创建了这个?”或“这个来自哪里?”
- 用户要求“记录此研究成果”并提供完整会话上下文
- ADR或研究成果需要溯源追踪
- Git提交需要会话UUID参考
- 跨自动压缩会话追踪编辑记录
- 为研究会话创建注册表条目
File Ownership Model
文件所有权模型
| Directory | Committed? | Purpose |
|---|---|---|
| YES | Master index (small, append-only NDJSON) |
| YES | Iteration records (small, append-only) |
| NO | Research artifacts (large, gitignored) |
| NO | Temporary archives before S3 upload |
S3 | N/A | Permanent team-shared archive |
Key Principle: Only is committed. Research artifacts go to gitignored and S3.
findings/outputs/| 目录 | 是否提交? | 用途 |
|---|---|---|
| 是 | 主索引(小型、仅追加的NDJSON格式) |
| 是 | 迭代记录(小型、仅追加) |
| 否 | 研究工件(大型、已加入git忽略) |
| 否 | S3上传前的临时归档 |
S3 | 不适用 | 永久的团队共享归档 |
核心原则:仅目录会被提交。研究工件存于已加入git忽略的目录和S3中。
findings/outputs/Part 0: Preflight Check
第0部分:预检检查
Step 1: Verify Session Storage Location
步骤1:验证会话存储位置
bash
/usr/bin/env bash << 'PREFLIGHT_EOF'
set -euo pipefailbash
/usr/bin/env bash << 'PREFLIGHT_EOF'
set -euo pipefailCheck Claude session storage
检查Claude会话存储
PROJECT_DIR="$HOME/.claude/projects"
if [[ ! -d "$PROJECT_DIR" ]]; then
echo "ERROR: Session storage not found at $PROJECT_DIR" >&2
echo " Expected: ~/.claude/projects/" >&2
echo " This directory is created by Claude Code on first use." >&2
exit 1
fi
PROJECT_DIR="$HOME/.claude/projects"
if [[ ! -d "$PROJECT_DIR" ]]; then
echo "ERROR: Session storage not found at $PROJECT_DIR" >&2
echo " Expected: ~/.claude/projects/" >&2
echo " This directory is created by Claude Code on first use." >&2
exit 1
fi
Count project folders (0 is valid - just means no sessions yet)
统计项目文件夹数量(0是有效状态 - 仅表示尚无会话)
PROJECT_COUNT=$(ls -1d "$PROJECT_DIR"/*/ 2>/dev/null | wc -l || echo "0")
if [[ "$PROJECT_COUNT" -eq 0 ]]; then
echo "WARNING: No project sessions found in $PROJECT_DIR"
echo " This may be expected if Claude Code hasn't been used in any projects yet."
else
echo "✓ Found $PROJECT_COUNT project folders in $PROJECT_DIR"
fi
echo "Ready for session archaeology"
PREFLIGHT_EOF
undefinedPROJECT_COUNT=$(ls -1d "$PROJECT_DIR"/*/ 2>/dev/null | wc -l || echo "0")
if [[ "$PROJECT_COUNT" -eq 0 ]]; then
echo "WARNING: No project sessions found in $PROJECT_DIR"
echo " This may be expected if Claude Code hasn't been used in any projects yet."
else
echo "✓ Found $PROJECT_COUNT project folders in $PROJECT_DIR"
fi
echo "Ready for session archaeology"
PREFLIGHT_EOF
undefinedStep 2: Find Current Project Sessions
步骤2:查找当前项目会话
bash
/usr/bin/env bash << 'FIND_SESSIONS_EOF'
set -euo pipefailbash
/usr/bin/env bash << 'FIND_SESSIONS_EOF'
set -euo pipefailEncode current working directory path (Claude Code path encoding)
编码当前工作目录路径(Claude Code路径编码规则)
CWD=$(pwd)
ENCODED_PATH=$(echo "$CWD" | tr '/' '-')
PROJECT_SESSIONS="$HOME/.claude/projects/$ENCODED_PATH"
if [[ -d "$PROJECT_SESSIONS" ]]; then
Count main sessions vs agent sessions (handle empty glob safely)
MAIN_COUNT=$(ls -1 "$PROJECT_SESSIONS"/.jsonl 2>/dev/null | grep -v "agent-" | wc -l | tr -d ' ' || echo "0")
AGENT_COUNT=$(ls -1 "$PROJECT_SESSIONS"/agent-.jsonl 2>/dev/null | wc -l | tr -d ' ' || echo "0")
if [[ "$MAIN_COUNT" -eq 0 && "$AGENT_COUNT" -eq 0 ]]; then
echo "ERROR: Session directory exists but contains no .jsonl files" >&2
echo " Location: $PROJECT_SESSIONS" >&2
exit 1
fi
echo "✓ Found $MAIN_COUNT main sessions + $AGENT_COUNT subagent sessions"
echo " Location: $PROJECT_SESSIONS"
Show main sessions with line counts
echo -e "\n=== Main Sessions ==="
for f in "$PROJECT_SESSIONS"/*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
[[ "$name" =~ ^agent- ]] && continue
lines=$(wc -l < "$f" | tr -d ' ')
echo " $name ($lines entries)"
done
Show agent sessions summary
echo -e "\n=== Subagent Sessions ==="
for f in "$PROJECT_SESSIONS"/agent-*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
lines=$(wc -l < "$f" | tr -d ' ')
echo " $name ($lines entries)"
done
else
echo "ERROR: No sessions found for current project" >&2
echo " Expected: $PROJECT_SESSIONS" >&2
echo "" >&2
echo "Available project folders:" >&2
ls -1 "$HOME/.claude/projects/" 2>/dev/null | head -10 || echo " (none)"
exit 1
fi
FIND_SESSIONS_EOF
undefinedCWD=$(pwd)
ENCODED_PATH=$(echo "$CWD" | tr '/' '-')
PROJECT_SESSIONS="$HOME/.claude/projects/$ENCODED_PATH"
if [[ -d "$PROJECT_SESSIONS" ]]; then
统计主会话与代理会话数量(安全处理空glob)
MAIN_COUNT=$(ls -1 "$PROJECT_SESSIONS"/.jsonl 2>/dev/null | grep -v "agent-" | wc -l | tr -d ' ' || echo "0")
AGENT_COUNT=$(ls -1 "$PROJECT_SESSIONS"/agent-.jsonl 2>/dev/null | wc -l | tr -d ' ' || echo "0")
if [[ "$MAIN_COUNT" -eq 0 && "$AGENT_COUNT" -eq 0 ]]; then
echo "ERROR: Session directory exists but contains no .jsonl files" >&2
echo " Location: $PROJECT_SESSIONS" >&2
exit 1
fi
echo "✓ Found $MAIN_COUNT main sessions + $AGENT_COUNT subagent sessions"
echo " Location: $PROJECT_SESSIONS"
显示主会话及行数统计
echo -e "\n=== Main Sessions ==="
for f in "$PROJECT_SESSIONS"/*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
[[ "$name" =~ ^agent- ]] && continue
lines=$(wc -l < "$f" | tr -d ' ')
echo " $name ($lines entries)"
done
显示代理会话摘要
echo -e "\n=== Subagent Sessions ==="
for f in "$PROJECT_SESSIONS"/agent-*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
lines=$(wc -l < "$f" | tr -d ' ')
echo " $name ($lines entries)"
done
else
echo "ERROR: No sessions found for current project" >&2
echo " Expected: $PROJECT_SESSIONS" >&2
echo "" >&2
echo "Available project folders:" >&2
ls -1 "$HOME/.claude/projects/" 2>/dev/null | head -10 || echo " (none)"
exit 1
fi
FIND_SESSIONS_EOF
undefinedStep 3: Verify Required Tools
步骤3:验证所需工具
bash
/usr/bin/env bash << 'TOOLS_EOF'
set -euo pipefailbash
/usr/bin/env bash << 'TOOLS_EOF'
set -euo pipefailAll tools are REQUIRED - fail loudly if missing
所有工具均为必需项 - 若缺失则直接报错
MISSING=0
MISSING=0
Check for jq (required for JSONL parsing)
检查jq(JSONL解析必需)
if ! command -v jq &>/dev/null; then
echo "ERROR: jq not installed (brew install jq)" >&2
MISSING=1
fi
if ! command -v jq &>/dev/null; then
echo "ERROR: jq not installed (brew install jq)" >&2
MISSING=1
fi
Check for brotli (required for compression)
检查brotli(压缩必需)
if ! command -v brotli &>/dev/null; then
echo "ERROR: brotli not installed (brew install brotli)" >&2
MISSING=1
fi
if ! command -v brotli &>/dev/null; then
echo "ERROR: brotli not installed (brew install brotli)" >&2
MISSING=1
fi
Check for aws (required for S3 upload)
检查aws(S3上传必需)
if ! command -v aws &>/dev/null; then
echo "ERROR: aws CLI not installed (brew install awscli)" >&2
MISSING=1
fi
if ! command -v aws &>/dev/null; then
echo "ERROR: aws CLI not installed (brew install awscli)" >&2
MISSING=1
fi
Check for op (required for 1Password credential injection)
检查op(1Password凭证注入必需)
if ! command -v op &>/dev/null; then
echo "ERROR: 1Password CLI not installed (brew install 1password-cli)" >&2
MISSING=1
fi
if [[ $MISSING -eq 1 ]]; then
echo "" >&2
echo "PREFLIGHT FAILED: Missing required tools. Install them and retry." >&2
exit 1
fi
echo "✓ All required tools available: jq, brotli, aws, op"
TOOLS_EOF
---if ! command -v op &>/dev/null; then
echo "ERROR: 1Password CLI not installed (brew install 1password-cli)" >&2
MISSING=1
fi
if [[ $MISSING -eq 1 ]]; then
echo "" >&2
echo "PREFLIGHT FAILED: Missing required tools. Install them and retry." >&2
exit 1
fi
echo "✓ All required tools available: jq, brotli, aws, op"
TOOLS_EOF
---Part 1: AskUserQuestion Flows
第1部分:用户提问流程
Flow A: Identify Target for Provenance
流程A:确定溯源目标
When the skill is triggered, first identify what the user wants to trace:
AskUserQuestion:
question: "What do you want to trace provenance for?"
header: "Target"
multiSelect: false
options:
- label: "Research finding/session"
description: "Document a research session with full session context for reproducibility"
- label: "Specific code/feature"
description: "Trace who created a specific function, feature, or code block"
- label: "Configuration/decision"
description: "Trace when and why a configuration or architectural decision was made"
- label: "Custom search"
description: "Search session logs for specific keywords or patterns"触发技能后,首先确定用户想要追踪的对象:
AskUserQuestion:
question: "你想要追踪什么的溯源信息?"
header: "目标"
multiSelect: false
options:
- label: "研究成果/会话"
description: "记录研究会话及完整上下文以确保可复现性"
- label: "特定代码/功能"
description: "追踪特定函数、功能或代码块的创建者"
- label: "配置/决策"
description: "追踪配置或架构决策的制定时间及原因"
- label: "自定义搜索"
description: "搜索会话日志中的特定关键词或模式"Flow B: Confirm GitHub Attribution
流程B:确认GitHub归属
CRITICAL: Every registry entry MUST have GitHub username attribution.
AskUserQuestion:
question: "Who should be attributed as the creator?"
header: "Attribution"
multiSelect: false
options:
- label: "Use git config user (Recommended)"
description: "Attribute to $(git config user.name) / $(git config user.email)"
- label: "Specify GitHub username"
description: "I'll provide the GitHub username manually"
- label: "Team attribution"
description: "Multiple contributors - list all GitHub usernames"核心要求:每个注册表条目必须包含GitHub用户名归属信息。
AskUserQuestion:
question: "应将谁标记为创建者?"
header: "归属信息"
multiSelect: false
options:
- label: "使用git config用户(推荐)"
description: "归属给$(git config user.name) / $(git config user.email)"
- label: "指定GitHub用户名"
description: "我将手动提供GitHub用户名"
- label: "团队归属"
description: "多位贡献者 - 列出所有GitHub用户名"Flow C: Confirm Session Scope
流程C:确认会话范围
CRITICAL: Default to ALL sessions. Registry must be self-contained.
AskUserQuestion:
question: "Which sessions should be recorded in the registry?"
header: "Sessions"
multiSelect: false
options:
- label: "ALL sessions (main + subagent) (Recommended)"
description: "Record every session file - complete provenance for future maintainers"
- label: "Main sessions only"
description: "Exclude agent-* subagent sessions (loses context)"
- label: "Manual selection"
description: "I'll specify which sessions to include"IMPORTANT: Always default to recording ALL sessions. Subagent sessions ()
contain critical context from Explore, Plan, and specialized agents. Omitting them
forces future maintainers to re-run archaeology.
agent-*核心要求:默认包含所有会话。注册表必须自包含。
AskUserQuestion:
question: "哪些会话应记录到注册表中?"
header: "会话范围"
multiSelect: false
options:
- label: "所有会话(主会话+子代理会话)(推荐)"
description: "记录每个会话文件 - 为未来维护者提供完整溯源信息"
- label: "仅主会话"
description: "排除agent-*子代理会话(会丢失上下文)"
- label: "手动选择"
description: "我将指定要包含的会话"重要提示:始终默认记录所有会话。子代理会话()包含来自Explore、Plan和专业代理的关键上下文。省略这些会话会迫使未来的维护者重新执行会话考古。
agent-*Flow D: Preview Session Contexts Array
流程D:预览session_contexts数组
Before writing, show the user exactly what will be recorded:
AskUserQuestion:
question: "Review the session_contexts array that will be recorded:"
header: "Review"
multiSelect: false
options:
- label: "Looks correct - proceed"
description: "Write this to the registry"
- label: "Add descriptions"
description: "Let me add descriptions to some sessions"
- label: "Filter some sessions"
description: "Remove sessions that aren't relevant"
- label: "Cancel"
description: "Don't write to registry yet"Display the full session_contexts array before this question:
json
{
"session_contexts": [
{
"session_uuid": "abc123",
"type": "main",
"entries": 980,
"description": "..."
},
{
"session_uuid": "agent-xyz",
"type": "subagent",
"entries": 113,
"description": "..."
}
]
}写入前,向用户展示将被记录的具体内容:
AskUserQuestion:
question: "查看将被记录的session_contexts数组:"
header: "预览"
multiSelect: false
options:
- label: "内容正确 - 继续"
description: "将此内容写入注册表"
- label: "添加描述"
description: "我要为部分会话添加描述"
- label: "过滤部分会话"
description: "移除不相关的会话"
- label: "取消"
description: "暂不写入注册表"在此问题前显示完整的session_contexts数组:
json
{
"session_contexts": [
{
"session_uuid": "abc123",
"type": "main",
"entries": 980,
"description": "..."
},
{
"session_uuid": "agent-xyz",
"type": "subagent",
"entries": 113,
"description": "..."
}
]
}Flow E: Choose Output Format
流程E:选择输出格式
AskUserQuestion:
question: "What outputs should be generated?"
header: "Outputs"
multiSelect: true
options:
- label: "registry.jsonl entry (Recommended)"
description: "Master index entry with ALL session UUIDs and GitHub attribution"
- label: "iterations.jsonl entries"
description: "Detailed iteration records in sessions/<id>/"
- label: "Full session chain archive (.jsonl.br)"
description: "Compress sessions with Brotli for archival"
- label: "Markdown finding document"
description: "findings/<name>.md with embedded provenance table"
- label: "Git commit with provenance"
description: "Structured commit message with session references"
- label: "Upload to S3 for team sharing"
description: "Upload artifacts to S3 with retrieval command in commit"AskUserQuestion:
question: "应生成哪些输出?"
header: "输出选项"
multiSelect: true
options:
- label: "registry.jsonl条目(推荐)"
description: "包含所有会话UUID和GitHub归属信息的主索引条目"
- label: "iterations.jsonl条目"
description: "sessions/<id>/目录下的详细迭代记录"
- label: "完整会话链归档文件(.jsonl.br)"
description: "使用Brotli压缩会话以进行归档"
- label: "Markdown研究成果文档"
description: "findings/<name>.md,包含嵌入的溯源表格"
- label: "带溯源信息的Git提交"
description: "包含会话参考的结构化提交信息"
- label: "上传至S3供团队共享"
description: "将工件上传至S3,并在提交中包含检索命令"Flow F: Link to Existing ADR
流程F:关联现有ADR
When creating a research session registry entry:
AskUserQuestion:
question: "Link this to an existing ADR or design spec?"
header: "ADR Link"
multiSelect: false
options:
- label: "No ADR link"
description: "This is standalone or ADR doesn't exist yet"
- label: "Specify ADR slug"
description: "Link to an existing ADR (e.g., 2025-12-15-feature-name)"
- label: "Create new ADR"
description: "This finding warrants a new ADR"创建研究会话注册表条目时:
AskUserQuestion:
question: "是否关联到现有ADR或设计规范?"
header: "ADR关联"
multiSelect: false
options:
- label: "不关联ADR"
description: "此条目为独立内容,或ADR尚未创建"
- label: "指定ADR标识"
description: "关联到现有ADR(例如:2025-12-15-feature-name)"
- label: "创建新ADR"
description: "此研究成果需要创建新的ADR"Part 2: Session Archaeology Process
第2部分:会话考古流程
Step 1: Full Project Scan
步骤1:完整项目扫描
Scan ALL session files (main + subagent) to build complete index:
bash
/usr/bin/env bash << 'SCAN_EOF'
set -euo pipefail
CWD=$(pwd)
ENCODED_PATH=$(echo "$CWD" | tr '/' '-')
PROJECT_SESSIONS="$HOME/.claude/projects/$ENCODED_PATH"
if [[ ! -d "$PROJECT_SESSIONS" ]]; then
echo "ERROR: Project sessions directory not found: $PROJECT_SESSIONS" >&2
exit 1
fi
echo "=== Building Session Index ==="
MAIN_COUNT=0
AGENT_COUNT=0扫描所有会话文件(主会话+子代理会话)以构建完整索引:
bash
/usr/bin/env bash << 'SCAN_EOF'
set -euo pipefail
CWD=$(pwd)
ENCODED_PATH=$(echo "$CWD" | tr '/' '-')
PROJECT_SESSIONS="$HOME/.claude/projects/$ENCODED_PATH"
if [[ ! -d "$PROJECT_SESSIONS" ]]; then
echo "ERROR: Project sessions directory not found: $PROJECT_SESSIONS" >&2
exit 1
fi
echo "=== 构建会话索引 ==="
MAIN_COUNT=0
AGENT_COUNT=0Main sessions
主会话
echo "Main sessions:"
for f in "$PROJECT_SESSIONS"/*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
[[ "$name" =~ ^agent- ]] && continue
lines=$(wc -l < "$f" | tr -d ' ')
first_ts=$(head -1 "$f" | jq -r '.timestamp // "unknown"') || first_ts="parse-error"
last_ts=$(tail -1 "$f" | jq -r '.timestamp // "unknown"') || last_ts="parse-error"
if [[ "$first_ts" == "parse-error" ]]; then
echo " WARNING: Failed to parse timestamps in $name" >&2
fi
echo " $name|main|$lines|$first_ts|$last_ts"
((MAIN_COUNT++)) || true
done
echo "主会话:"
for f in "$PROJECT_SESSIONS"/*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
[[ "$name" =~ ^agent- ]] && continue
lines=$(wc -l < "$f" | tr -d ' ')
first_ts=$(head -1 "$f" | jq -r '.timestamp // "unknown"') || first_ts="parse-error"
last_ts=$(tail -1 "$f" | jq -r '.timestamp // "unknown"') || last_ts="parse-error"
if [[ "$first_ts" == "parse-error" ]]; then
echo " WARNING: Failed to parse timestamps in $name" >&2
fi
echo " $name|main|$lines|$first_ts|$last_ts"
((MAIN_COUNT++)) || true
done
Subagent sessions
子代理会话
echo "Subagent sessions:"
for f in "$PROJECT_SESSIONS"/agent-*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
lines=$(wc -l < "$f" | tr -d ' ')
first_ts=$(head -1 "$f" | jq -r '.timestamp // "unknown"') || first_ts="parse-error"
echo " $name|subagent|$lines|$first_ts"
((AGENT_COUNT++)) || true
done
echo ""
echo "✓ Indexed $MAIN_COUNT main + $AGENT_COUNT subagent sessions"
if [[ $MAIN_COUNT -eq 0 && $AGENT_COUNT -eq 0 ]]; then
echo "ERROR: No sessions found to index" >&2
exit 1
fi
SCAN_EOF
undefinedecho "子代理会话:"
for f in "$PROJECT_SESSIONS"/agent-*.jsonl; do
[[ ! -f "$f" ]] && continue
name=$(basename "$f" .jsonl)
lines=$(wc -l < "$f" | tr -d ' ')
first_ts=$(head -1 "$f" | jq -r '.timestamp // "unknown"') || first_ts="parse-error"
echo " $name|subagent|$lines|$first_ts"
((AGENT_COUNT++)) || true
done
echo ""
echo "✓ 已索引$MAIN_COUNT个主会话 + $AGENT_COUNT个子代理会话"
if [[ $MAIN_COUNT -eq 0 && $AGENT_COUNT -eq 0 ]]; then
echo "ERROR: No sessions found to index" >&2
exit 1
fi
SCAN_EOF
undefinedStep 2: Build session_contexts Array
步骤2:构建session_contexts数组
CRITICAL: This array must contain ALL sessions. Example output:
json
{
"session_contexts": [
{
"session_uuid": "8c821a19-e4f4-45d5-9338-be3a47ac81a3",
"type": "main",
"entries": 980,
"timestamp_start": "2026-01-03T21:25:07.435Z",
"description": "Primary session - research iterations, PR preparation"
},
{
"session_uuid": "agent-a728ebe",
"type": "subagent",
"entries": 113,
"timestamp_start": "2026-01-02T07:25:47.658Z",
"description": "Explore agent - codebase analysis"
}
]
}核心要求:此数组必须包含所有会话。示例输出:
json
{
"session_contexts": [
{
"session_uuid": "8c821a19-e4f4-45d5-9338-be3a47ac81a3",
"type": "main",
"entries": 980,
"timestamp_start": "2026-01-03T21:25:07.435Z",
"description": "主会话 - 研究迭代、PR准备"
},
{
"session_uuid": "agent-a728ebe",
"type": "subagent",
"entries": 113,
"timestamp_start": "2026-01-02T07:25:47.658Z",
"description": "Explore代理 - 代码库分析"
}
]
}Step 3: Trace UUID Chain (Optional)
步骤3:追踪UUID链(可选)
For detailed provenance of specific edits:
bash
/usr/bin/env bash << 'TRACE_EOF'
set -euo pipefail
trace_uuid_chain() {
local uuid="$1"
local session_file="$2"
local depth=0
local max_depth=100
if [[ -z "$uuid" ]]; then
echo "ERROR: UUID argument required" >&2
return 1
fi
if [[ ! -f "$session_file" ]]; then
echo "ERROR: Session file not found: $session_file" >&2
return 1
fi
echo "Tracing UUID chain from: $uuid"
while [[ -n "$uuid" && $depth -lt $max_depth ]]; do
# Use jq with explicit error handling
entry=$(jq -c "select(.uuid == \"$uuid\")" "$session_file" 2>&1) || {
echo "ERROR: jq failed parsing $session_file" >&2
return 1
}
if [[ -n "$entry" ]]; then
parent=$(echo "$entry" | jq -r '.parentUuid // empty') || parent=""
timestamp=$(echo "$entry" | jq -r '.timestamp // "unknown"') || timestamp="unknown"
type=$(echo "$entry" | jq -r '.type // "unknown"') || type="unknown"
echo " [$depth] $uuid ($type) @ $timestamp"
echo " -> parent: ${parent:-<root>}"
uuid="$parent"
((depth++)) || true
else
echo " UUID $uuid not in current session, searching others..."
found=false
for session in "$PROJECT_SESSIONS"/*.jsonl; do
[[ ! -f "$session" ]] && continue
if grep -q "\"uuid\":\"$uuid\"" "$session"; then
session_file="$session"
echo " ✓ Found in $(basename "$session")"
found=true
break
fi
done
if [[ "$found" == "false" ]]; then
echo " WARNING: UUID chain broken - $uuid not found in any session" >&2
break
fi
fi
done
if [[ $depth -ge $max_depth ]]; then
echo "WARNING: Reached max chain depth ($max_depth) - chain may be incomplete" >&2
fi
echo "✓ Chain depth: $depth"
}
TRACE_EOF针对特定编辑的详细溯源:
bash
/usr/bin/env bash << 'TRACE_EOF'
set -euo pipefail
trace_uuid_chain() {
local uuid="$1"
local session_file="$2"
local depth=0
local max_depth=100
if [[ -z "$uuid" ]]; then
echo "ERROR: UUID argument required" >&2
return 1
fi
if [[ ! -f "$session_file" ]]; then
echo "ERROR: Session file not found: $session_file" >&2
return 1
fi
echo "Tracing UUID chain from: $uuid"
while [[ -n "$uuid" && $depth -lt $max_depth ]]; do
# 使用jq并添加显式错误处理
entry=$(jq -c "select(.uuid == \"$uuid\")" "$session_file" 2>&1) || {
echo "ERROR: jq failed parsing $session_file" >&2
return 1
}
if [[ -n "$entry" ]]; then
parent=$(echo "$entry" | jq -r '.parentUuid // empty') || parent=""
timestamp=$(echo "$entry" | jq -r '.timestamp // "unknown"') || timestamp="unknown"
type=$(echo "$entry" | jq -r '.type // "unknown"') || type="unknown"
echo " [$depth] $uuid ($type) @ $timestamp"
echo " -> parent: ${parent:-<root>}"
uuid="$parent"
((depth++)) || true
else
echo " UUID $uuid not in current session, searching others..."
found=false
for session in "$PROJECT_SESSIONS"/*.jsonl; do
[[ ! -f "$session" ]] && continue
if grep -q "\"uuid\":\"$uuid\"" "$session"; then
session_file="$session"
echo " ✓ Found in $(basename "$session")"
found=true
break
fi
done
if [[ "$found" == "false" ]]; then
echo " WARNING: UUID chain broken - $uuid not found in any session" >&2
break
fi
fi
done
if [[ $depth -ge $max_depth ]]; then
echo "WARNING: Reached max chain depth ($max_depth) - chain may be incomplete" >&2
fi
echo "✓ Chain depth: $depth"
}
TRACE_EOFPart 3: Registry Schema
第3部分:注册表 Schema
registry.jsonl (Master Index)
registry.jsonl(主索引)
Each line is a complete, self-contained JSON object:
json
{
"id": "2026-01-01-multiyear-momentum",
"type": "research_session",
"title": "Multi-Year Cross-Sectional Momentum Strategy Validation",
"project": "alpha-forge",
"branch": "feat/2026-01-01-multiyear-cs-momentum-research",
"created_at": "2026-01-03T01:00:00Z",
"created_by": {
"github_username": "terrylica",
"model": "claude-opus-4-5-20251101",
"session_uuid": "8c821a19-e4f4-45d5-9338-be3a47ac81a3"
},
"strategy_type": "cross_sectional_momentum",
"date_range": { "start": "2022-01-01", "end": "2025-12-31" },
"session_contexts": [
{
"session_uuid": "8c821a19-...",
"type": "main",
"entries": 1128,
"description": "Primary session - research iterations, PR preparation"
},
{
"session_uuid": "agent-a728ebe",
"type": "subagent",
"entries": 113,
"timestamp_start": "2026-01-02T07:25:47.658Z",
"description": "Explore agent - codebase analysis"
}
],
"metrics": {
"sharpe_2bps": 1.05,
"sharpe_13bps": 0.31,
"max_drawdown": -0.18
},
"tags": ["momentum", "cross-sectional", "multi-year", "validated"],
"artifacts": {
"adr": "docs/adr/2026-01-02-multiyear-momentum-vs-ml.md",
"strategy_config": "examples/02_strategies/cs_momentum_multiyear.yaml",
"research_log": "outputs/research_sessions/2026-01-01-multiyear-momentum/research_log.md",
"iteration_configs": "outputs/research_sessions/2026-01-01-multiyear-momentum/",
"s3": "s3://eonlabs-findings/sessions/2026-01-01-multiyear-momentum/"
},
"status": "validated",
"finding": "BiLSTM time-series models show no predictive edge (49.05% hit rate). Simple CS momentum outperforms.",
"recommendation": "Deploy CS Momentum 120+240 strategy. Abandon ML-based approaches for this market regime."
}Required Fields:
- - Unique identifier (format:
id)YYYY-MM-DD-slug - -
type|research_session|findingdecision - - ISO8601 timestamp
created_at - - MANDATORY - GitHub username
created_by.github_username - - MANDATORY - Array of ALL session UUIDs
session_contexts
Optional Fields:
- - Human-readable title
title - - Project/repository name
project - - Git branch name
branch - - Strategy classification (for research_session type)
strategy_type - -
date_rangedate range covered{start, end} - - Key performance metrics object
metrics - - Searchable tags array
tags - - Object with paths (see Artifact Paths below)
artifacts - -
status|draft|validated|productionarchived - - Summary of what was discovered
finding - - What to do next
recommendation
Artifact Paths:
| Key | Location | Purpose |
|---|---|---|
| | Committed ADR document |
| | Committed strategy example |
| | Gitignored research log |
| | Gitignored config files |
| | S3 archive for team sharing |
每一行是一个完整的自包含JSON对象:
json
{
"id": "2026-01-01-multiyear-momentum",
"type": "research_session",
"title": "Multi-Year Cross-Sectional Momentum Strategy Validation",
"project": "alpha-forge",
"branch": "feat/2026-01-01-multiyear-cs-momentum-research",
"created_at": "2026-01-03T01:00:00Z",
"created_by": {
"github_username": "terrylica",
"model": "claude-opus-4-5-20251101",
"session_uuid": "8c821a19-e4f4-45d5-9338-be3a47ac81a3"
},
"strategy_type": "cross_sectional_momentum",
"date_range": { "start": "2022-01-01", "end": "2025-12-31" },
"session_contexts": [
{
"session_uuid": "8c821a19-...",
"type": "main",
"entries": 1128,
"description": "Primary session - research iterations, PR preparation"
},
{
"session_uuid": "agent-a728ebe",
"type": "subagent",
"entries": 113,
"timestamp_start": "2026-01-02T07:25:47.658Z",
"description": "Explore agent - codebase analysis"
}
],
"metrics": {
"sharpe_2bps": 1.05,
"sharpe_13bps": 0.31,
"max_drawdown": -0.18
},
"tags": ["momentum", "cross-sectional", "multi-year", "validated"],
"artifacts": {
"adr": "docs/adr/2026-01-02-multiyear-momentum-vs-ml.md",
"strategy_config": "examples/02_strategies/cs_momentum_multiyear.yaml",
"research_log": "outputs/research_sessions/2026-01-01-multiyear-momentum/research_log.md",
"iteration_configs": "outputs/research_sessions/2026-01-01-multiyear-momentum/",
"s3": "s3://eonlabs-findings/sessions/2026-01-01-multiyear-momentum/"
},
"status": "validated",
"finding": "BiLSTM time-series models show no predictive edge (49.05% hit rate). Simple CS momentum outperforms.",
"recommendation": "Deploy CS Momentum 120+240 strategy. Abandon ML-based approaches for this market regime."
}必填字段:
- - 唯一标识符(格式:
id)YYYY-MM-DD-slug - -
type|research_session|findingdecision - - ISO8601时间戳
created_at - - 必填 - GitHub用户名
created_by.github_username - - 必填 - 所有会话UUID的数组
session_contexts
可选字段:
- - 人类可读标题
title - - 项目/仓库名称
project - - Git分支名称
branch - - 策略分类(针对research_session类型)
strategy_type - -
date_range覆盖的日期范围{start, end} - - 关键性能指标对象
metrics - - 可搜索标签数组
tags - - 包含路径的对象(见下文工件路径)
artifacts - -
status|draft|validated|productionarchived - - 发现内容摘要
finding - - 后续建议
recommendation
工件路径:
| 键名 | 位置 | 用途 |
|---|---|---|
| | 已提交的ADR文档 |
| | 已提交的策略示例 |
| | 已加入git忽略的研究日志 |
| | 已加入git忽略的配置文件 |
| | 供团队共享的S3归档 |
iterations.jsonl (Detailed Records)
iterations.jsonl(详细记录)
Located at . For iteration-level tracking:
findings/sessions/<id>/iterations.jsonljson
{
"id": "iter-001",
"registry_id": "2026-01-01-multiyear-momentum",
"type": "iteration",
"created_at": "2026-01-01T10:00:00Z",
"created_by": {
"github_username": "terrylica",
"model": "claude-opus-4-5-20251101",
"session_uuid": "8c821a19-e4f4-45d5-9338-be3a47ac81a3"
},
"hypothesis": "Test BiLSTM with conservative clip",
"config": { "strategy": "bilstm", "clip": 0.05 },
"results": { "train_sharpe": 0.31, "test_sharpe": -1.15 },
"finding": "BiLSTM shows no edge",
"status": "FAILED"
}位于。用于迭代级别的追踪:
findings/sessions/<id>/iterations.jsonljson
{
"id": "iter-001",
"registry_id": "2026-01-01-multiyear-momentum",
"type": "iteration",
"created_at": "2026-01-01T10:00:00Z",
"created_by": {
"github_username": "terrylica",
"model": "claude-opus-4-5-20251101",
"session_uuid": "8c821a19-e4f4-45d5-9338-be3a47ac81a3"
},
"hypothesis": "Test BiLSTM with conservative clip",
"config": { "strategy": "bilstm", "clip": 0.05 },
"results": { "train_sharpe": 0.31, "test_sharpe": -1.15 },
"finding": "BiLSTM shows no edge",
"status": "FAILED"
}Part 4: Output Generation
第4部分:输出生成
Compressed Session Context
压缩会话上下文
For archival, compress sessions with Brotli:
bash
/usr/bin/env bash << 'COMPRESS_EOF'
set -euo pipefail归档时,使用Brotli压缩会话:
bash
/usr/bin/env bash << 'COMPRESS_EOF'
set -euo pipefailValidate required variables
验证所需变量
if [[ -z "${TARGET_ID:-}" ]]; then
echo "ERROR: TARGET_ID variable not set" >&2
exit 1
fi
if [[ -z "${SESSION_LIST:-}" ]]; then
echo "ERROR: SESSION_LIST variable not set" >&2
exit 1
fi
if [[ -z "${PROJECT_SESSIONS:-}" ]]; then
echo "ERROR: PROJECT_SESSIONS variable not set" >&2
exit 1
fi
OUTPUT_DIR="outputs/research_sessions/${TARGET_ID}"
mkdir -p "$OUTPUT_DIR" || {
echo "ERROR: Failed to create output directory: $OUTPUT_DIR" >&2
exit 1
}
if [[ -z "${TARGET_ID:-}" ]]; then
echo "ERROR: TARGET_ID variable not set" >&2
exit 1
fi
if [[ -z "${SESSION_LIST:-}" ]]; then
echo "ERROR: SESSION_LIST variable not set" >&2
exit 1
fi
if [[ -z "${PROJECT_SESSIONS:-}" ]]; then
echo "ERROR: PROJECT_SESSIONS variable not set" >&2
exit 1
fi
OUTPUT_DIR="outputs/research_sessions/${TARGET_ID}"
mkdir -p "$OUTPUT_DIR" || {
echo "ERROR: Failed to create output directory: $OUTPUT_DIR" >&2
exit 1
}
NOTE: This directory is gitignored. Artifacts are preserved in S3, not git.
注意:此目录已加入git忽略。工件将保存在S3中,而非git。
Compress each session
压缩每个会话
ARCHIVED_COUNT=0
FAILED_COUNT=0
for session_id in $SESSION_LIST; do
SESSION_PATH="$PROJECT_SESSIONS/${session_id}.jsonl"
if [[ -f "$SESSION_PATH" ]]; then
if brotli -9 -o "$OUTPUT_DIR/${session_id}.jsonl.br" "$SESSION_PATH"; then
echo "✓ Archived: ${session_id}"
((ARCHIVED_COUNT++)) || true
else
echo "ERROR: Failed to compress ${session_id}" >&2
((FAILED_COUNT++)) || true
fi
else
echo "WARNING: Session file not found: $SESSION_PATH" >&2
fi
done
if [[ $ARCHIVED_COUNT -eq 0 ]]; then
echo "ERROR: No sessions were archived" >&2
exit 1
fi
if [[ $FAILED_COUNT -gt 0 ]]; then
echo "ERROR: $FAILED_COUNT session(s) failed to compress" >&2
exit 1
fi
ARCHIVED_COUNT=0
FAILED_COUNT=0
for session_id in $SESSION_LIST; do
SESSION_PATH="$PROJECT_SESSIONS/${session_id}.jsonl"
if [[ -f "$SESSION_PATH" ]]; then
if brotli -9 -o "$OUTPUT_DIR/${session_id}.jsonl.br" "$SESSION_PATH"; then
echo "✓ Archived: ${session_id}"
((ARCHIVED_COUNT++)) || true
else
echo "ERROR: Failed to compress ${session_id}" >&2
((FAILED_COUNT++)) || true
fi
else
echo "WARNING: Session file not found: $SESSION_PATH" >&2
fi
done
if [[ $ARCHIVED_COUNT -eq 0 ]]; then
echo "ERROR: No sessions were archived" >&2
exit 1
fi
if [[ $FAILED_COUNT -gt 0 ]]; then
echo "ERROR: $FAILED_COUNT session(s) failed to compress" >&2
exit 1
fi
Create manifest with proper JSON
创建包含正确JSON格式的清单文件
cat > "$OUTPUT_DIR/manifest.json" << MANIFEST
{
"target_id": "$TARGET_ID",
"sessions_archived": $ARCHIVED_COUNT,
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
MANIFEST
echo "✓ Archived $ARCHIVED_COUNT sessions to $OUTPUT_DIR"
COMPRESS_EOF
undefinedcat > "$OUTPUT_DIR/manifest.json" << MANIFEST
{
"target_id": "$TARGET_ID",
"sessions_archived": $ARCHIVED_COUNT,
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
MANIFEST
echo "✓ Archived $ARCHIVED_COUNT sessions to $OUTPUT_DIR"
COMPRESS_EOF
undefinedGit Commit Message Template
Git提交信息模板
feat(finding): <short description>
Session-Chronicle Provenance:
registry_id: <registry_id>
github_username: <github_username>
main_sessions: <count>
subagent_sessions: <count>
total_entries: <total>
Artifacts:
- findings/registry.jsonl
- findings/sessions/<id>/iterations.jsonl
- S3: s3://eonlabs-findings/sessions/<id>/feat(finding): <简短描述>
Session-Chronicle Provenance:
registry_id: <registry_id>
github_username: <github_username>
main_sessions: <数量>
subagent_sessions: <数量>
total_entries: <总数>
Artifacts:
- findings/registry.jsonl
- findings/sessions/<id>/iterations.jsonl
- S3: s3://eonlabs-findings/sessions/<id>/S3 Artifact Retrieval
S3工件检索
Download compressed artifacts from S3
从S3下载压缩后的工件
export AWS_ACCESS_KEY_ID=$(op read "op://Claude Automation/ise47dxnkftmxopupffavsgby4/access key id")
export AWS_SECRET_ACCESS_KEY=$(op read "op://Claude Automation/ise47dxnkftmxopupffavsgby4/secret access key")
export AWS_DEFAULT_REGION="us-west-2"
aws s3 sync s3://eonlabs-findings/sessions/<id>/ ./artifacts/
for f in ./artifacts/*.br; do brotli -d "$f"; done
Co-authored-by: Claude noreply@anthropic.com
---export AWS_ACCESS_KEY_ID=$(op read "op://Claude Automation/ise47dxnkftmxopupffavsgby4/access key id")
export AWS_SECRET_ACCESS_KEY=$(op read "op://Claude Automation/ise47dxnkftmxopupffavsgby4/secret access key")
export AWS_DEFAULT_REGION="us-west-2"
aws s3 sync s3://eonlabs-findings/sessions/<id>/ ./artifacts/
for f in ./artifacts/*.br; do brotli -d "$f"; done
Co-authored-by: Claude noreply@anthropic.com
---Part 5: Confirmation Workflow
第5部分:确认工作流
Final Confirmation Before Write
写入前的最终确认
ALWAYS show the user what will be written before appending:
AskUserQuestion:
question: "Ready to write to registry. Confirm the entry:"
header: "Confirm"
multiSelect: false
options:
- label: "Write to registry"
description: "Append this entry to findings/registry.jsonl"
- label: "Edit first"
description: "Let me modify some fields before writing"
- label: "Cancel"
description: "Don't write anything"Before this question, display:
- Full JSON entry (pretty-printed)
- Count of session_contexts entries
- GitHub username attribution
- Target file path
始终在追加前向用户展示将写入的内容:
AskUserQuestion:
question: "准备写入注册表。确认条目内容:"
header: "确认"
multiSelect: false
options:
- label: "写入注册表"
description: "将此条目追加至findings/registry.jsonl"
- label: "先编辑"
description: "写入前让我修改部分字段"
- label: "取消"
description: "不写入任何内容"在此问题前显示:
- 完整的JSON条目(格式化输出)
- session_contexts条目的数量
- GitHub用户名归属信息
- 目标文件路径
Post-Write Verification
写入后验证
After writing, verify:
bash
undefined写入完成后进行验证:
bash
undefinedValidate NDJSON format
验证NDJSON格式
tail -1 findings/registry.jsonl | jq . > /dev/null && echo "Valid JSON"
tail -1 findings/registry.jsonl | jq . > /dev/null && echo "Valid JSON"
Show what was written
显示已写入的内容
echo "Entry added:"
tail -1 findings/registry.jsonl | jq '.id, .created_by.github_username, (.session_contexts | length)'
---echo "Entry added:"
tail -1 findings/registry.jsonl | jq '.id, .created_by.github_username, (.session_contexts | length)'
---Part 6: Workflow Summary
第6部分:工作流摘要
1. PREFLIGHT
├── Verify session storage location
├── Find ALL sessions (main + subagent)
└── Check required tools (jq, brotli)
2. ASK: TARGET TYPE
└── AskUserQuestion: What to trace?
3. ASK: GITHUB ATTRIBUTION
└── AskUserQuestion: Who created this?
4. ASK: SESSION SCOPE
└── AskUserQuestion: Which sessions? (Default: ALL)
5. BUILD session_contexts ARRAY
├── Enumerate ALL main sessions
├── Enumerate ALL subagent sessions
└── Collect metadata (entries, timestamps)
6. ASK: PREVIEW session_contexts
└── AskUserQuestion: Review before writing
7. ASK: OUTPUT FORMAT
└── AskUserQuestion: What to generate?
8. ASK: ADR LINK
└── AskUserQuestion: Link to ADR?
9. GENERATE OUTPUTS
├── Build registry.jsonl entry (with iterations_path, iterations_count)
├── Build iterations.jsonl entries (if applicable)
└── Prepare commit message
10. ASK: FINAL CONFIRMATION
└── AskUserQuestion: Ready to write?
11. WRITE & VERIFY
├── Append to registry.jsonl
├── Append to sessions/<id>/iterations.jsonl
└── Validate NDJSON format
12. (OPTIONAL) S3 UPLOAD
└── Upload compressed archives1. 预检检查
├── 验证会话存储位置
├── 查找所有会话(主会话+子代理会话)
└── 检查所需工具(jq, brotli)
2. 询问:目标类型
└── AskUserQuestion: 要追踪什么?
3. 询问:GitHub归属
└── AskUserQuestion: 谁创建了这个?
4. 询问:会话范围
└── AskUserQuestion: 包含哪些会话?(默认:所有)
5. 构建session_contexts数组
├── 枚举所有主会话
├── 枚举所有子代理会话
└── 收集元数据(条目数、时间戳)
6. 询问:预览session_contexts
└── AskUserQuestion: 写入前确认
7. 询问:输出格式
└── AskUserQuestion: 生成哪些输出?
8. 询问:ADR关联
└── AskUserQuestion: 是否关联到ADR?
9. 生成输出
├── 构建registry.jsonl条目(包含iterations_path、iterations_count)
├── 构建iterations.jsonl条目(如适用)
└── 准备提交信息
10. 询问:最终确认
└── AskUserQuestion: 准备好写入了吗?
11. 写入并验证
├── 追加至registry.jsonl
├── 追加至sessions/<id>/iterations.jsonl
└── 验证NDJSON格式
12. (可选)S3上传
└── 上传压缩归档文件Success Criteria
成功标准
- Complete session enumeration - ALL main + subagent sessions recorded
- GitHub attribution - always present
created_by.github_username - Self-contained registry - Future maintainers don't need archaeology
- User confirmation - Every step has AskUserQuestion confirmation
- Valid NDJSON - All entries pass validation
jq - Reproducible - Session UUIDs enable full context retrieval
- 完整会话枚举 - 记录所有主会话+子代理会话
- GitHub归属 - 始终存在
created_by.github_username - 自包含注册表 - 未来维护者无需执行会话考古
- 用户确认 - 每个步骤都有AskUserQuestion确认
- 有效NDJSON - 所有条目通过验证
jq - 可复现 - 会话UUID支持完整上下文检索
References
参考资料
- S3 Sharing ADR
- S3 Retrieval Guide
- NDJSON Specification
- jq Manual
- Brotli Compression
- S3 Sharing ADR
- S3 Retrieval Guide
- NDJSON Specification
- jq Manual
- Brotli Compression
Troubleshooting
故障排除
| Issue | Cause | Solution |
|---|---|---|
| Session storage not found | Claude Code not initialized | Start a Claude Code session first |
| No sessions in project | Wrong path encoding | Check encoded path matches ~/.claude/projects/ |
| jq parse error | Malformed JSONL | Validate each line with |
| brotli not found | Missing dependency | Install with |
| S3 upload fails | Missing AWS credentials | Configure AWS CLI or use 1Password injection |
| UUID chain broken | Session compacted | Check related sessions for continuation |
| GitHub username missing | Attribution not set | Always require github_username in registry entry |
| Registry entry invalid | Missing required fields | Verify id, type, created_at, session_contexts exist |
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 会话存储未找到 | Claude Code未初始化 | 先启动一个Claude Code会话 |
| 项目中无会话 | 路径编码错误 | 检查编码路径是否与~/.claude/projects/匹配 |
| jq解析错误 | JSONL格式错误 | 使用 |
| brotli未找到 | 缺少依赖项 | 使用 |
| S3上传失败 | 缺少AWS凭证 | 配置AWS CLI或使用1Password凭证注入 |
| UUID链中断 | 会话已压缩 | 检查相关会话以寻找后续内容 |
| GitHub用户名缺失 | 未设置归属信息 | 始终要求注册表条目中包含github_username |
| 注册表条目无效 | 缺少必填字段 | 验证id、type、created_at、session_contexts是否存在 |