Adding a source adapter¶
Implement model.Source in internal/sources/<source>/ and register it in
internal/cli/cli.go. Shared decoding helpers live in internal/sources/srcutil.
Name,DisplayName, andVersionidentify the source and parser version.Discover(root)returns conversation handles from the supplied path or the tool's default location. Wrapmodel.ErrNotFoundwhen a default is absent.Parse(handle, content)parses the bytes supplied by the observation log; never rereadhandle.Path, which may not exist on the projecting device.AppendOnlytells collection whether it can record just newly appended bytes.
For a shared SQLite store or export containing multiple conversations, set
Handle.Content to each conversation's serialized bytes during discovery.
Discover must open source databases read-only and close them before returning.
One-file-per-conversation sources normally leave Content nil.
Return a model.Conversation with ordered messages, typed content blocks,
metadata, and raw events. Preserve unknown structured content in payloads.
Native message identifiers are preferred; fallback identifiers must include
position, never content alone, so repeated messages remain distinct. Keep
parent references and absent versus empty values intact.
Add synthetic/sanitized input under spec/golden/inputs/, a case in
spec/golden/cases.json, and generate its expected projection with:
go test ./internal/golden -run TestGolden/YOUR_CASE -update
Review the generated JSON. Run go test ./...; update legacy-import coverage
in internal/golden/legacy_test.go when the source existed in Python.
For format drift diagnostics, implement optional model.Checker: return
problems for unreadable layouts and notes for unknown record kinds.
Never commit real transcripts or require network access to parse local data.