Tuneloop:本地CLI分析编码代理会话转录
评分
66填补了编码代理分析工具的空缺,但同类概念已有少量探索,信息增量中等偏上。
工具功能明确,文档与展示清晰,但尚处初期,缺乏大规模使用验证。
对使用AI编程助手的开发者和代理开发者具有直接调试和优化价值。
发布于2025年,恰逢AI代理工具爆发期,需求迫切。
Hacker News热门展示,GitHub开源,代码可审查,但项目尚新。
基础分 73 × T2 信源权重 ×0.9 = 66
精选线 70未达精选线
精选理由
工具虽小但精准切中当前 AI 代理可观测性痛点,实用价值高,但尚处早期阶段,生态未成型。
AI 点评
「这个工具虽然小巧,但直击当前AI编程代理大规模落地中的可观测性盲区。如果你是重度使用AI助手写代码的开发者,或者正在开发自己的Agent工具,Tuneloop值得一试——能让你从‘信任黑箱’走向‘理解过程’。目前仅支持解析有限格式,但愿社区能快速贡献适配更多框架。」
速览
Tuneloop 是一个开源的本地命令行工具,旨在帮助开发者分析和理解编码代理(如 AI 编程助手)的会话记录。它能够解析代理交互日志,提取关键上下文、工具调用、决策步骤和错误修复模式,从而提升代理行为的透明度和可调试性。该项目适合使用 AI 编程助手的团队、Agent 工具开发者以及研究编码代理行为的学者。目前已在 GitHub 上线,支持本地部署以保护隐私。
- Tuneloop 是本地 CLI,无需远程服务即可分析编码代理的会话转录
- 它能提取工具调用序列、决策步骤和错误恢复模式
- 开源项目,地址为 github.com/tuneloop/tuneloop
- 有助于理解代理逻辑,提升 AI 编程工具的可解释性和调试效率
正文
tuneloop
Local analytics for your AI coding sessions. Understand and improve your coding agent usage.
tuneloop turns the session transcripts your AI coding tools already write into a local dashboard that gives you cost attribution (what each PR / feature cost) and recommendations for more effective usage grounded in your sessions.
Concretely, it enriches each session with:
- Outcome links — merged PRs, features shipped, files changed
- Granular cost attribution to outcomes
- Task complexity
- Agent autonomy
- Work type
- Key decisions
- Tool error categories
and across sessions, identifies:
- Agent re-work / re-steer themes
- Patterns of deviations from best practices
Combined with the data already in the transcript — model, agent harness, repo, and more — this data lets you answer questions like:
- How much of my AI spend went into PR #2, or feature X?
- Are my agents getting more autonomous over time on complex tasks?
- What's my success rate on repo X vs. repo Y — or any other dimension you care about?
Works with Claude Code, Codex, OpenCode, and Pi. Everything runs and stays on your machine; enrichments that need an LLM can use your own provider key or a local model. The built-ins above are just the defaults — tuneloop is extensible, and adding your own enrichment is straightforward.
Built by the team at Tuneloop.
Quick start
Requires Node.js >= 22.19 (npx runs on whatever node your shell resolves —
check with node -v).
npx tuneloop analyze
This scans typical session folders like ~/.claude/projects, builds a local
store, and prints a summary like this:
Scanned 336 file(s), parsed 334 session(s) into 118 unique session(s), 118 new/changed.
Sessions 118
Total spend $1566.56
Tokens 1,769,497,264
Range 2026-04-16 → 2026-07-27
Cost / merged PR $15.31 (56 merged)
Analysis spend $6.92 (enrichment)
Analysis finished in 6m 11s (Step 1 processing 3m 28s · Step 2 detectors 2m 34s).
tuneloop dashboard http://localhost:4319
store: ~/.tuneloop/tuneloop.sqlite
Enter to open in your browser · Ctrl+C to stop
Press Enter and it opens the dashboard, where you see everything from the
What you get section below. In the summary above, Total spend is your
analyzed sessions' AI cost, while Analysis spend is what tuneloop's own LLM
calls cost to produce all of it — a few dollars, here with a Claude Haiku + Sonnet
model pair (see LLM enrichment). The first run processes
every transcript, so expect a few minutes (about 6 for ~120 sessions with
enrichment on; static-only runs are faster); later runs are incremental and only
re-process sessions that changed, so they finish quickly. Point it at other
locations with a comma-separated list:
npx tuneloop analyze ~/.claude/projects,/path/to/more/sessions
Handy flags:
--no-serve— build the store and exit, no dashboard--port <n>— serve on a different port--config <path>— a JSON file selecting which processors/detectors run (see below)npx tuneloop serve— open the dashboard over an already-analyzed store, without re-analyzing
Choosing what runs
By default analyze runs every built-in processor and detector. To run only a
subset, copy the shipped config.json — it lists everything —
delete or disable what you don't want, and pass it with --config:
npx tuneloop analyze --config ./my-config.json
Each entry is keyed by name with an enabled flag; omit a whole section
(processors or detectors) to keep all of that kind. A processor's
dependencies are pulled in automatically, so you can't accidentally starve one
of its inputs. See ARCHITECTURE.md for
the full list and what each does.
What you get
The dashboard reads everything live from a local SQLite store:
- Cost per shipped artifact — dollars of AI spend per merged PR or per shipped feature.
- Session outcome rate — how many of your sessions ended in a win (you pick what counts).
- Total spend — over time, split by model, work type, or repo.
- Tool & skill usage — call counts, error rates, and error categories across every session.
Cost, tools, files, and git/PR outcomes come from static analysis — no setup or API key. Work type, complexity, autonomy, and feature names come from LLM enrichment, which is worth setting up: much of what makes the dashboard useful depends on it.
Highlights turns the same data into plain-English insights about your recent work:
A filterable session viewer, with the full transcript and file changes behind each one.
- Easy transcript navigation (turn-by-turn, errors, free text search, and outcomes). For example: you can jump to the part of the session where you worked on a particular feature or code change.
- Filter sessions that touched a particular file / PR / feature.
A set of recommendations, grounded in evidence from across your sessions, that surface fixes for re-steering you repeatedly had to do, or deviations from best practices.
How it works
Enrichment labels each session in one LLM call:
- Work type — one of
plan·implement·debug·research·review·docs·other. - Complexity — one of
trivial·routine·substantial·open-ended. - Autonomy — how much the agent drove itself:
autonomous·guided·minimal. - Feature — links the session to a shipped feature, reusing your existing feature names and proposing new ones. The taxonomy grows as you analyze, so related work lands under one feature instead of fragmenting.
- Success — a judged outcome (
success/partial/failure), surfaced as thesession_successoutcome you can count.
PR linking connects a session to the PRs it produced, two ways:
- Explicit — the transcript shows the agent creating, merging, or reviewing a PR
(
gh pr create/gh pr review/ a GitHub MCP tool); live status comes from your localgh. - Content-match — for the common case where the agent writes the code and you
commit and push it (no
gh pr createin the transcript), tuneloop matches the lines the agent authored against your own PRs' diffs and links the best match.
See ARCHITECTURE.md for the detection rules.
Block-level cost attribution — a long session that touches several things isn't billed as one lump. tuneloop splits it into blocks and attributes token cost per block, so a per-PR or per-feature cost reflects only the work that went into it. → how blocks work
Metrics — the five dashboard headlines (outcome rate, cost per shipped artifact, total spend, sessions, tool error rate) are each explained in ARCHITECTURE.md.
Detection of recurring agent re-work / re-steer themes — LLM-based analysis that identifies patterns from across your sessions where you had to step in and course-correct. Surfaces recommendations to fix these — updates to agent files (CLAUDE.md / AGENTS.md), skills, tooling or config.
Identification of deviations from best practices — Deterministic and LLM-as-a-judge checkers that look at things like cache hit rate, context management, and unused startup bloat. Surfaces recommendations to fix these — updates to config, or simply an informational nudge.
Query it from your coding agent
Everything on the dashboard is a query over the store — and so is anything it
doesn't show. tuneloop query runs read-only SQL over that store, straight from
your terminal or your coding agent's shell:
tuneloop query "SELECT model, SUM(cost_usd) FROM usage_facts GROUP BY 1 ORDER BY 2 DESC" tuneloop query --schema # tables, facets, and measures — learn the shape first
Only SELECT / WITH … SELECT run; writes and raw transcripts are off-limits.
Because it needs no server and speaks plain SQL, it's a natural fit for Claude Code and other agents. Install the bundled skill so your agent knows the schema and the grain rules before it writes a query:
npx skills add tuneloop/tuneloop
Then just ask — "Query tuneloop: what did I spend per model last week?" — and the agent writes the SQL, runs it, and reads back the answer.
LLM enrichment
To label each session with a work type, complexity, autonomy, and an LLM-judged success signal — and to name the features you shipped — point tuneloop at your own LLM key. Your session data goes only to the provider you choose:
export TUNELOOP_LLM_PROVIDER=anthropic export ANTHROPIC_API_KEY=sk-ant-... # optional: export TUNELOOP_LLM_MODEL=claude-haiku-4-5 # base (per-session) model # optional: export TUNELOOP_LLM_MODEL_HEAVY=claude-sonnet-5 # detector model — auto-selected for anthropic; set to override npx tuneloop analyze
Or skip the env setup: run npx tuneloop analyze in a terminal and, when no
provider is configured, it offers to set one up interactively — pick a provider,
paste a key (input hidden), and that run enriches. If the provider's key is
already exported (e.g. ANTHROPIC_API_KEY), it's picked up without asking. The
key is never written to disk; the run ends by printing the export lines that
make it permanent.
Pick a preset and supply its key; the model defaults sensibly and is overridable
with TUNELOOP_LLM_MODEL (or --llm-model). Anthropic, OpenAI, and AWS Bedrock
are native; everything else speaks the OpenAI-compatible API.
TUNELOOP_LLM_PROVIDER |
Key env | Notes |
|---|---|---|
anthropic |
ANTHROPIC_API_KEY |
native |
openai |
OPENAI_API_KEY |
native |
bedrock |
AWS_BEARER_TOKEN_BEDROCK (or standard AWS credentials) |
Claude via AWS; set AWS_REGION |
openrouter |
OPENROUTER_API_KEY |
400+ models via one key |
groq |
GROQ_API_KEY |
fast; free tier |
deepseek |
DEEPSEEK_API_KEY |
|
gemini |
GEMINI_API_KEY |
Google, OpenAI-compatible endpoint |
together / fireworks / xai |
TOGETHER_API_KEY / FIREWORKS_API_KEY / XAI_API_KEY |
|
ollama |
(none) | local; http://localhost:11434 |
openai-compatible |
TUNELOOP_LLM_API_KEY |
any other host; set TUNELOOP_LLM_BASE_URL |
openai-compatible-nokey |
(none) | keyless gateway; set TUNELOOP_LLM_BASE_URL, auth via TUNELOOP_LLM_HEADERS |
# A hosted provider — name it, never type a URL:
TUNELOOP_LLM_PROVIDER=openrouter OPENROUTER_API_KEY=sk-or-... \
npx tuneloop analyze --llm-model deepseek/deepseek-chat
# Fully local, no key, nothing leaves your machine:
npx tuneloop analyze --llm-provider ollama --llm-model qwen2.5
# AWS Bedrock — a Bedrock API key, or any standard AWS credentials (SigV4):
TUNELOOP_LLM_PROVIDER=bedrock AWS_BEARER_TOKEN_BEDROCK=... AWS_REGION=us-east-1 \
npx tuneloop analyze
# The default model is a US inference profile; other regions pick theirs, e.g.
# --llm-model eu.anthropic.claude-haiku-4-5-20251001-v1:0
# Any other OpenAI-compatible host:
TUNELOOP_LLM_PROVIDER=openai-compatible TUNELOOP_LLM_BASE_URL=https://host/v1 \
TUNELOOP_LLM_API_KEY=… npx tuneloop analyze --llm-model my-model
# An intranet / self-hosted gateway with no API key, authenticated by headers
# (e.g. a LiteLLM proxy or an internal gateway):
TUNELOOP_LLM_PROVIDER=openai-compatible-nokey TUNELOOP_LLM_BASE_URL=https://gateway.internal/v1 \
TUNELOOP_LLM_HEADERS='{"x-user-id":"u-123","x-team":"platform"}' \
npx tuneloop analyze --llm-model my-model
Enrichment is one structured tool call per session, so use a
tool-call-capable model (all the hosted defaults qualify). Flags override the env
for one run; the API key is never a flag — set it in the env or paste it at the
interactive prompt. For a gateway that authenticates by request headers instead of
a key, use openai-compatible-nokey and pass the headers as a JSON object in
TUNELOOP_LLM_HEADERS (applied to every request; a malformed value warns and
enrichment stays off rather than sending unauthenticated requests). It's inexpensive: analyzing ~100 sessions runs about $6
with the default pairing — a cheap model (e.g. Claude Haiku) for the per-session
enrichment and a Sonnet-class heavy model for the cross-session recommendation
detectors. This cost shows up as Analysis spend in the summary,
priced from a built-in table with an OpenRouter public price list filling gaps
(cached under ~/.tuneloop/).
Two model tiers. The work splits into two shapes: per-session enrichment is one
call per session (the volume — a cheap model is the right call), while a few
detectors make cross-session synthesis calls where reasoning quality shows up in
the insights. Detectors opt into the stronger tier individually — today the
recurring-themes detector does; the rest stay on the base model. On the
built-in providers with a strong sibling (Anthropic, OpenAI, Bedrock, OpenRouter,
Gemini), that heavy model is selected automatically, so the recommendations
work out of the box. Override it with TUNELOOP_LLM_MODEL_HEAVY (or
--llm-model-heavy) — a sibling model on the same provider:
TUNELOOP_LLM_PROVIDER=anthropic ANTHROPIC_API_KEY=sk-ant-... \ npx tuneloop analyze --llm-model claude-haiku-4-5 --llm-model-heavy claude-sonnet-5
Same provider, key, and base URL as TUNELOOP_LLM_MODEL — only the model id
differs. Leave it unset and tuneloop uses the provider's default heavy model where
it has one (the strong siblings above) — unless your base model already clears the
Sonnet-class tier, in which case detectors just reuse it. A provider with no strong
sibling falls back to the base model, which skips recurring-themes (with a
warning) when that model is below the tier. Changing it re-analyzes the full corpus for the
detectors that use it, since extractions made by the old model aren't comparable to
the new one's.
Keeping analysis spend down. The automatic heavy model is what makes the recommendations work out of the box, but it does raise per-run spend over an enrichment-only run. Two ways to opt out:
-
Turn off the automatic heavy model — set
TUNELOOP_DISABLE_DEFAULT_LLM_HEAVY=1. Every detector then runs on your base (cheap) model, and recurring-themes skips itself with a warning (it's gated to a Sonnet-class model). This only suppresses the default — an explicitTUNELOOP_LLM_MODEL_HEAVY/--llm-model-heavystill wins, so you can disable the auto-pick yet still opt a single run into a heavy model. -
Turn off the heavy detector(s) — disable them in
config.jsonand pass it with--config.recurring-themesis the only detector that uses the heavy model, so disabling it removes all heavy-model spend while the rest of the recommendations keep running; disablekitchen-sinktoo to drop the remaining (base-model) LLM detector:{ "detectors": { "recurring-themes": { "enabled": false }, "kitchen-sink": { "enabled": false } } }
Local Ollama needs a bigger context window and a capable model: the enrichment
prompt is ~4–6k tokens but Ollama's ~2k default silently truncates it, so start the
server with OLLAMA_CONTEXT_LENGTH=8192 ollama serve and use a tool-strong ≥7B
model like qwen2.5:7b (tiny models tool-call unreliably).
Privacy
Transcripts are processed locally and results are written to a local SQLite store
(~/.tuneloop/ by default). tuneloop never posts your session data anywhere —
the only thing that ever leaves is a transcript sent to the LLM provider whose key
you supply, and only if you enable enrichment. Its other network calls are
read-only and carry none of your data: your local gh for PR status and diffs
(your own GitHub auth), and OpenRouter's public price list to cost models the
built-in table doesn't know. To avoid sending transcripts off the machine at all,
enrich against a local model (--llm-provider ollama).
Run from source
npx tuneloop is all most people need. To hack on tuneloop itself, run it from a
local checkout:
npm install npm run dev -- analyze # builds, runs the CLI (args after `--`), then serves the dashboard
Or build once and call the binary directly:
npm run build node dist/cli.js analyze
npm link gives you a global tuneloop backed by your local build. LLM
enrichment works the same way — set TUNELOOP_LLM_PROVIDER and its key before
running.
Extending
Adding new analysis is one file: implement the Processor interface, declare any
sliceable facets, and register it — it shows up in the store and the dashboard (as
a card and a filter) automatically, no migration. To support a new AI tool, write
a SourceAdapter. See ARCHITECTURE.md.
License
MIT
相关条目
92
精选OpenRouter 推出提示缓存与粘性路由,大幅降低多轮对话成本
对于高频调用 AI API 的开发者,这个功能堪称直接省钱利器。粘性路由保证了缓存命中率,配合 session_id 零配置接入,值得所有使用 OpenRouter 的团队立即尝试。
91
精选ChatGPT Work:可在跨应用和文件中执行操作的AI Agent
我认为这是AI助手从问答走向执行的关键一步。对需要自动化复杂工作流的专业人士尤其值得关注。ChatGPT Work可能成为生产力工具的新范式。
90
精选前沿实验室代理入侵事件技术时间线:2026年7月事件剖析
这篇技术时间线值得所有AI安全研究员和代理开发者细读——它不只是描述一次攻击,而是为整个行业敲响了代理系统防御体系薄弱的警钟。对正在部署自主代理的团队来说,这是必读的灾难预防手册。
90
精选更好的工具反而让Copilot代码审查更糟?GitHub这样改进
这篇博客值得所有AI产品工程师和ML从业者仔细阅读——它打破了'更强大的工具=更好的AI'的直觉,转而强调与Agent推理模式匹配的工程哲学。对正在优化代码审查或类似Agent产品的团队尤其重要。
88
精选OpenRouter 推出统一多模态 API:单端点支持图像、视频、音频、嵌入与转录
这条消息值得所有做多模态AI应用的开发者关注:OpenRouter用联合API解决了模型切换的痛点,特别适合初创团队或快速原型开发。如果你正被多个API密钥和SDK折磨,这个接口可能是你需要的统一层。
87
精选Anthropic 推出 Claude for Teachers:面向教师的教育 AI 工具
这条消息对教育工作者和AI行业观察者都很有价值。Anthropic没有选择通用聊天机器人,而是专门为教师设计了安全可控的工具,这显示出AI在垂直场景落地的正确思路——不是技术炫技,而是切实解决用户痛点。同时,产品内置的安全护栏也值得其他AI公司参考,尤其是在面向儿童或青少年的场景中。
86
精选OpenRouter发布全新Auto Router:用市场智慧优化模型路由
这条更新值得所有用API开发AI应用的人关注。以前选模型靠经验和测试,现在市场数据帮你选。虽然细节不多,但方向很对。对依赖聚合模型服务的团队尤其重要。
86
精选Claude Code v2.1.211 发布:多项修复与改进
作为一个经常使用 Claude Code 进行自动化编码的开发者,我特别关注这次的安全修复,尤其是权限预览字符绕过和自动模式覆盖钩子决策的问题——这些直接关系到团队协作时的安全边界。后台代理报告的改进也让长时间运行的任务更可靠。建议所有使用者尽快升级。



