feat: conversation projection — toolpath as agent session interchange#22
Merged
feat: conversation projection — toolpath as agent session interchange#22
Conversation
Defines architecture for projecting toolpath documents back into functional agent conversation sessions, enabling conversation portability between AI coding agents (Claude, Codex, Gemini). Key decisions: - Conversation sub-protocol in toolpath-convo (structural change vocabulary: conversation.init, conversation.append, tool.invoke) - ConversationProjector trait with AnyProjector type-erasing wrapper - Enriched derive in toolpath-claude for round-trip fidelity - Tool invocations modeled as separate steps with per-tool actors
- Replace claude:// with agent://claude/<session-id> hierarchy - Document non-file artifacts as "virtual artifacts" - Call out breaking changes in migration section (URN scheme, tool steps, full UUID step IDs) - Resolve artifact URN open question
9 tasks covering the full pipeline: 1. Add toolpath dep to toolpath-convo 2. ConversationProjector trait + AnyProjector 3. extract_conversation function 4. Enriched derive in toolpath-claude 5. ClaudeProjector implementation 6. Round-trip integration test 7. CLI project command 8. Version bumps and changelog 9. Final verification
Update derive_path() to produce sub-protocol-compliant output: - Change conversation artifact key from claude:// to agent://claude/ - Use full entry UUID as step ID instead of truncated 8-char prefix - Preserve full text (remove truncation) - Add model, stop_reason, and token usage fields to conversation.append extra - Separate thinking from text in conversation.append extra - Emit tool invocation steps (one per tool type, grouped) with tool.invoke structural changes, correct actor strings, and category mapping - Tool steps use file_path as artifact key for file tools, agent:// URI for others - Tool steps do not advance the parent chain Updated all existing tests and added new tests for: tool invocation actors, token usage capture, full text preservation, multiple tool uses (same and different types), non-file tool artifact keys, thinking inclusion/exclusion, tool step parent chain behavior, and tool input preservation.
toolpath-convo 0.5.0 → 0.6.0 (new API + new dependency) toolpath-claude 0.6.2 → 0.7.0 (breaking derive changes + new API) toolpath-cli 0.3.0 → 0.3.1 (new project command)
Tool result content and is_error flags are now verified to survive the full Claude JSONL → derive → Path → extract → project pipeline.
…on-mode The ClaudeProjector now emits a permission-mode preamble entry as the first line (matching real Claude JSONL) and populates per-entry metadata (cwd, gitBranch, version, userType, requestId, entrypoint, isMeta, slug, etc.) from Turn.environment and Turn.extra["claude"]. Tool-result entries inherit metadata from their parent turn and include sourceToolAssistantUUID.
Non-message JSONL entries (attachment, system, file-history-snapshot, permission-mode, etc.) are now derived as steps with structural change type `conversation.event` instead of being silently skipped. Each event step records the entry_type, metadata fields, and entry extras for round-trip fidelity. Event steps use actor `tool:claude-code` and do not advance the conversation parent chain.
Real Claude JSONL permission-mode lines have only type/permissionMode/ sessionId. ConversationEntry always serializes uuid/timestamp/isSidechain which caused Claude Code to reject the projected file. Add Conversation.preamble field for raw JSON entries that don't fit the ConversationEntry shape. CLI serializes preamble before entries.
Reads a toolpath document (file or stdin), projects it into Claude JSONL, and writes it to ~/.claude/projects/ so Claude Code can load and resume it. Supports piping: path derive ... | path incept Usage: path derive claude --project /path | path incept --project /target path incept --input doc.json --project /target
Claude Code calls .map() on assistant message content, expecting an array. Simple text-only assistant turns now emit Parts([Text]) instead of Text(string).
|
🔍 Preview deployed: https://32ae43be.toolpath.pages.dev |
eliothedeman
added a commit
that referenced
this pull request
Apr 20, 2026
Resolves conflicts with the conversation-projection changes (PR #22) that landed on main while this PR was in review: - Cargo.toml workspace deps: keep toolpath 0.2.0 (this branch) alongside the toolpath-claude 0.7.0 bump from main. - crates/toolpath-cli/Cargo.toml and site/_data/crates.json: keep toolpath-cli 0.4.0 (higher bump supersedes main's 0.3.1). - Cargo.lock: take main's version and regenerate via cargo build. - Add `graph_ref: None` to four new PathIdentity struct literals introduced by main: - crates/toolpath-cli/src/cmd_incept.rs - crates/toolpath-cli/src/cmd_project.rs - crates/toolpath-cli/tests/roundtrip.rs - crates/toolpath-convo/src/extract.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Enables projecting toolpath documents back into functional agent conversation sessions. A toolpath document derived from a Claude session can be projected into Claude JSONL that Claude Code loads and resumes — verified empirically.
This is the "serialize" half of a serde-like pattern for conversation portability:
ConversationProvider(existing) reads native formats intoConversationViewConversationProjector(new) writesConversationViewinto native formatsConversationViewas the narrow waist — M providers = M+N, not M×NWhat's new
toolpath-convo:
ConversationProjectortrait +AnyProjectortype-erasing wrapperextract_conversation()— reconstructsConversationViewfrom a toolpathPathusing the conversation sub-protocolConversationEventtype for non-message session entries (hooks, snapshots, metadata)conversation.init,conversation.append,tool.invoke,conversation.eventstructural change types;agent://<provider>/<session>URN scheme; actor patterns (human:*,agent:*,agent:*/tool:*,tool:*)toolpath-claude:
ClaudeProjector— projectsConversationViewinto ClaudeConversationagent:claude-code/tool:<Name>actors,agent://claude/<session>URNs, full UUID step IDs, token usage, stop_reason, model,conversation.initsteps, per-entry metadata, non-message event captureto_view()before derive)Conversation.preamblefor raw JSON entries (permission-mode) that don't fitConversationEntrytoolpath-cli:
path project claude— project a toolpath document into Claude JSONLpath incept— project and write directly to~/.claude/projects/so Claude Code canclaude -rit. Reads from file or stdin, supports piping:path derive claude ... | path incept --project /targetBreaking changes (toolpath-claude, pre-1.0)
claude://<id>→agent://claude/<id>tool.invokeTest plan
path project claudeCLI integration testpath inceptwrites to correct~/.claude/projects/pathpath derive claude ... | path incept ...thenclaude -rloads the session in Claude Code