session.jsonl stores tool records with a dot inserted into absolute paths

Author: samflorentineCreated Sep 17, 2026Updated Sep 17, 2026

session.jsonl stores tool records with a . inserted into absolute paths

Product: Craft Agents desktop app Version: 0.13.3 (CFBundleShortVersionString / CFBundleVersion) OS: macOS 26.6.2 (25G83), Apple Silicon Repo: craft-ai-agents/craft-agents-oss Severity: Low functional impact, high evidence-integrity impact Labels suggestion: bug

Summary

The app-persisted transcript sessions/<slug>/session.jsonl stores a single arbitrarily inserted . inside some absolute paths in tool records. The same values are correct everywhere else — the raw runtime log, live process argv, and the filesystem. Only the persisted transcript is affected, which makes it unusable as evidence: any agent or human reading session.jsonl to verify paths gets paths that do not exist.

Scope

  • Affects tool call records only — both tool inputs and tool outputs.
  • Does not affect assistant message text in the same file (an absolute path written in assistant prose is stored verbatim).
  • Does not affect sessions/<slug>/.pi-sessions/*.jsonl (the raw runtime log).

That last point is the key diagnostic: the same tool call appears clean in the runtime log and mangled in session.jsonl.

Minimal reproduction

  1. Run this in the Bash tool:

    bash
    echo "MARKER_A=/Volumes/home/Drive"
    echo "MARKER_B=/Users/samflorentine/.craft-agent"
    echo "MARKER_C=/Volumes./home"
    echo "MARKER_D=//[email protected]/home"
    echo "MARKER_E=/opt/homebrew"
  2. Compare sessions/<slug>/.pi-sessions/*.jsonl with sessions/<slug>/session.jsonl.

Marker Runtime log (correct) session.jsonl (mangled)
A /Volumes/home/Drive /Volumes./home/Drive
B /Users/samflorentine/.craft-agent ./Users/samflorentine/.craft-agent
C /Volumes./home /Volumes../home
D //[email protected]/home //[email protected]./home
E /opt/homebrew ./opt/homebrew

Note marker C: an input that already contained a . gained a second one, i.e. exactly one . is inserted per path.

Further samples (ground truth → persisted)

Ground truth Persisted in session.jsonl
/Users/x ./Users/x
/Users/samflorentine/x ./Users/samflorentine/x
/etc/hosts ./etc/hosts
/var/log/x ./var/log/x
/Volumes/home/Databases /Volumes./home/Databases
/private/tmp/x /private./tmp/x
//[email protected]/home //[email protected]./home
/Volumes/Databases/Eagle (unchanged)
/Volumes/Media/x, /Volumes/Sam/x (unchanged)
/Applications/x, /Library/x, /System/x (unchanged)
/bin/ls, /usr/bin/env (unchanged)
/a/bbb, /aaa/bbb, /Volumes/x, /Volumes (unchanged)
~/x, relative/path/x (unchanged)

Characterisation

The transform is deterministic but opaque from the outside:

  • Not length-based (/Users/x mangles, /a/bbb does not).
  • Not depth-based (/private/tmp/x mangles, /usr/bin/env does not).
  • Not existence-based (/etc/hosts mangles, /Library/x does not; /Volumes/Databases/Eagle is untouched while /Volumes/home/Databases is mangled).
  • Exactly one . is inserted per affected path. The insertion position varies: leading (./Users/...), after the first component (/Volumes./home/...), or after a host token (//host./share).

Because no rule can be derived, consumers cannot safely reverse it with a regex — a generic "strip the dot" repair would corrupt correctly-stored paths. Repair currently requires validating each candidate against the filesystem and failing closed, which is what we implemented as a workaround.

Ruled out

  • Not rtk. rtk 0.49.0 is an output-filtering CLI proxy; its help output and binary strings expose no path-rewriting feature. dist/interceptor.cjs contains zero references to rtk, and its sanitize*/redact* functions handle OpenAI cache-control blocks and proxy-credential redaction only.
  • Not execution-time. The mangled form never reaches the shell: the live process argv for a command whose transcript entry is mangled shows the correct path.
  • Not the runtime log. .pi-sessions/*.jsonl is consistently correct while session.jsonl for the same call is mangled.

Impact

  1. Evidence integrity. Any workflow that reads stored transcripts to verify what a session actually did — audits, plan reviews, post-mortems — ingests paths that do not exist and can conclude that folders are missing/empty. We observed an agent audit session misdiagnosing empty results as a path typo because of this.
  2. Workaround cost. Consumers must know to ignore session.jsonl and read .pi-sessions/*.jsonl instead; that is undocumented behaviour a user cannot reasonably discover.
  3. There is no functional/data-corruption impact on task execution.

Requested resolution

Either:

  • (a) persist tool records in session.jsonl verbatim (matching the runtime log), or
  • (b) if the transform is intentional (e.g. sanitisation for sharing/export), document it, scope it to an explicit export/sanitise path rather than the on-disk default, and expose the inverse so stored transcripts remain usable.

Notes

  • Reproduced on 2026-09-16/17 EDT; observed in three independent sessions (different models). The transform is stable across them.
  • Related: any UI feature that copies a path from the transcript would copy the mangled form.

Drafted with Craft Agent (session 260916-light-birch) from a live reproduction on the reporter's machine.

Source: craft-ai-agents/craft-agents-oss