Summary
When Pi uses its edit tool to modify an existing file, bb renders the timeline entry as “Created” rather than “Edited.” The file is modified correctly, but the activity label and aggregate file-change summary misrepresent the operation.
Versions and environment
- bb 0.42.1 via
npx bb-app; translation repro against source commit dba32a469fd820ff6106715db0aaf6ed297d79a5
- Ubuntu 26.04 LTS, Node.js 22.22.1
- Pi provider; repository recording uses
@earendil-works/pi-coding-agent 0.84.0 (RPC), and the locally installed Pi CLI is 0.85.0
- bb worktree environment
Steps to reproduce
- Create a scratch repository containing an existing
math.js:
git init pi-edit-repro
cd pi-edit-repro
printf 'export function add(a, b) {\n return a + b;\n}\n' > math.js
git add math.js
git commit -m 'Add math fixture'
- Open the repository in bb and start a thread with the Pi provider.
- Send this prompt:
Read math.js, then add a subtract(a, b) function to it by editing the file.
- Expand the file-change activity in the thread timeline.
Smallest automated reproduction: pass a Pi tool_execution_start event for toolName: "edit" with args.path and an args.edits replacement array through the Pi delta translator. The emitted file change has kind: "add".
Expected vs actual
Actual timeline label:
Created math.js
Actual normalized file change:
{"type":"fileChange","changes":[{"path":"math.js","kind":"add"}]}
Expected timeline label:
Edited math.js
Expected normalized file change:
{"type":"fileChange","changes":[{"path":"math.js","kind":"update"}]}
Evidence
The checked-in Pi provider recording first reads the existing math.js, then receives an edit call whose arguments contain an edits array, but emits kind: "add": recording lines 8–11.
On current main at 06aeaa994942ae7527dc49d2268c1f801e8542a0, the classifier decides between add and update from top-level oldText: delta-translation.ts lines 254–264. Pi’s actual edit payload puts replacement pairs in args.edits, so top-level oldText is absent and the bridge selects add.
A focused translator regression test using the recorded payload shape failed deterministically with kind: "add" when expecting kind: "update". No public-safe investigation thread link is available; the reproducible repository evidence is linked above.
Suggested fix
Classify Pi edit tool calls as update regardless of whether top-level oldText is present. Keep content-only write calls classified as add, and add regression coverage using Pi’s actual args.edits payload shape.
What you ruled out
- The UI is not independently choosing “Created”; the Pi bridge already emits
kind: "add".
- Timeline assembly is not rewriting an update into an add; the incorrect kind is present at
item.open.
- This is not limited to a stale release: the classifier is unchanged on current
main at 06aeaa994942ae7527dc49d2268c1f801e8542a0.
- Searches of open and closed issues for Pi edit/create labels and
fileChange add/update behavior found no duplicate.
Suggested priority and effort
Medium priority, low effort — affects every Pi edit timeline entry and has no labeling workaround, but does not lose file contents or other work.
AGENT GENERATED
Summary
When Pi uses its
edittool to modify an existing file, bb renders the timeline entry as “Created” rather than “Edited.” The file is modified correctly, but the activity label and aggregate file-change summary misrepresent the operation.Versions and environment
npx bb-app; translation repro against source commitdba32a469fd820ff6106715db0aaf6ed297d79a5@earendil-works/pi-coding-agent0.84.0 (RPC), and the locally installed Pi CLI is 0.85.0Steps to reproduce
math.js:Smallest automated reproduction: pass a Pi
tool_execution_startevent fortoolName: "edit"withargs.pathand anargs.editsreplacement array through the Pi delta translator. The emitted file change haskind: "add".Expected vs actual
Evidence
The checked-in Pi provider recording first reads the existing
math.js, then receives aneditcall whose arguments contain aneditsarray, but emitskind: "add": recording lines 8–11.On current
mainat06aeaa994942ae7527dc49d2268c1f801e8542a0, the classifier decides betweenaddandupdatefrom top-leveloldText: delta-translation.ts lines 254–264. Pi’s actualeditpayload puts replacement pairs inargs.edits, so top-leveloldTextis absent and the bridge selectsadd.A focused translator regression test using the recorded payload shape failed deterministically with
kind: "add"when expectingkind: "update". No public-safe investigation thread link is available; the reproducible repository evidence is linked above.Suggested fix
Classify Pi
edittool calls asupdateregardless of whether top-leveloldTextis present. Keep content-onlywritecalls classified asadd, and add regression coverage using Pi’s actualargs.editspayload shape.What you ruled out
kind: "add".item.open.mainat06aeaa994942ae7527dc49d2268c1f801e8542a0.fileChangeadd/update behavior found no duplicate.Suggested priority and effort
Medium priority, low effort — affects every Pi
edittimeline entry and has no labeling workaround, but does not lose file contents or other work.