{"id":50305769,"url":"https://github.com/cybersader/portaconv","last_synced_at":"2026-05-28T16:01:45.864Z","repository":{"id":352650796,"uuid":"1215973823","full_name":"cybersader/portaconv","owner":"cybersader","description":"Terminal-native conversation extractor + MCP server for agent CLIs. Normalizes Claude Code conversations to OpenAI Chat Completions; paste-ready markdown; opt-in WSL↔Windows path rewriting.","archived":false,"fork":false,"pushed_at":"2026-04-20T14:31:04.000Z","size":125,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T16:15:14.853Z","etag":null,"topics":["agent","claude-code","cli","conversation-history","mcp","rust","terminal","wsl"],"latest_commit_sha":null,"homepage":"https://cybersader.github.io/portaconv/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cybersader.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-20T12:45:18.000Z","updated_at":"2026-04-20T14:33:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cybersader/portaconv","commit_stats":null,"previous_names":["cybersader/portaconv"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/cybersader/portaconv","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cybersader%2Fportaconv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cybersader%2Fportaconv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cybersader%2Fportaconv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cybersader%2Fportaconv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cybersader","download_url":"https://codeload.github.com/cybersader/portaconv/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cybersader%2Fportaconv/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33615490,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","claude-code","cli","conversation-history","mcp","rust","terminal","wsl"],"created_at":"2026-05-28T16:01:44.903Z","updated_at":"2026-05-28T16:01:45.856Z","avatar_url":"https://github.com/cybersader.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# portaconv\n\n**Terminal-native conversation extractor + MCP server for agent CLIs.**\n\nPaste-ready recovery for the cases `claude -r \u003cuuid\u003e` can't reach —\ncross-OS content drift, sessions whose original cwd is moved or\ndifferent, broken `/resume` pickers, and conversations you want to\ncommit into the repo.\n\nSibling to [portagenty](https://github.com/cybersader/portagenty).\n\n\u003c/div\u003e\n\n---\n\n\u003e **Status: v0.1 surface feature-complete; not yet on crates.io.**\n\u003e Claude Code adapter, `list` / `dump` / `doctor` / `rebuild-index` /\n\u003e `mcp serve`, path-rewrite transforms, per-file list cache, and\n\u003e explicit backing-file override all shipped. Full guide at\n\u003e [cybersader.github.io/portaconv](https://cybersader.github.io/portaconv/).\n\n## The problem\n\nClaude Code (and every other agent CLI) stores conversation\nhistory keyed to the **absolute filesystem path** of the working\ndirectory at launch. This breaks in three ways:\n\n1. **Storage fragmentation + cwd-strict resume.** The same project\n   accessed via WSL and Windows produces two separate encoded\n   directories under `~/.claude/projects/`. `/resume` from either\n   only sees half the history. Worse, even `claude -r \u003cuuid\u003e`\n   doesn't bypass this — it only looks in the encoded-dir of your\n   *current* cwd, not by sessionId across all encoded dirs. Move\n   the project, cd to a sibling, run from `/tmp`: *\"No conversation\n   found with session ID.\"* Empirically reproduced; tracked\n   upstream as [#5768][s5768] (open) and [#28745][s28745] (open\n   feature request for the missing `--cwd` / `--ignore-directory`\n   flag).\n\n[s5768]: https://github.com/anthropics/claude-code/issues/5768\n[s28745]: https://github.com/anthropics/claude-code/issues/28745\n\n2. **Content poisoning.** Spot-check of one 54 MB session: 9999+\n   `/mnt/c/…` and 72 `C:\\…` path references baked into\n   conversation content (`cwd`, `file_path`, prose). Merging the\n   storage layer with symlinks doesn't fix this — a\n   Windows-launched Claude that resumes a WSL-authored session\n   fails the first time it tries to `Read /mnt/c/…`.\n\n3. **Stale index.** Claude Code caches session summaries in\n   `sessions-index.json` alongside the `.jsonl`s. The picker for\n   `/resume` reads this index — but the write path only runs on\n   graceful shutdown, and ungraceful WSL closures (`wsl\n   --shutdown`, window close, machine suspend) skip it. On one\n   machine: 14 projects with the index lagging the actual jsonls\n   by up to 93 days. Upstream canonical issue: [#25032][s25032].\n\n[s25032]: https://github.com/anthropics/claude-code/issues/25032\n\nFile-level sync is folly. The content carries the OS it was\nauthored on, and the index can't be trusted to reflect reality.\n\n## The pivot\n\nportaconv reads agent-CLI conversation storage (read-only) and\nemits **paste-ready** text — optionally with `/mnt/c/` ↔ `C:\\`\npath rewriting so the output works on the other OS.\n\nYou don't try to resume in place. You extract what you said, paste\nit into a new session on whatever machine is in front of you, and\nthe new session picks up where the old one left off.\n\nAlso ships as an MCP server, so any MCP-aware agent can query past\nconversations directly.\n\n## What's in v0.1\n\n```\npconv list                     # list Claude Code conversations\npconv dump \u003csession-id\u003e        # paste-ready markdown to stdout\npconv doctor                   # detect stale sessions-index.json\npconv doctor --dump-stale      # also dump the newest session per stale project\npconv rebuild-index --all      # rewrite sessions-index.json from the jsonls\npconv mcp serve                # stdio MCP server\n```\n\nClaude Code adapter only for v0.1. OpenCode / Cursor / Aider /\ncontinue.dev adapters are separate PRs after the adapter trait\nsurvives contact with reality.\n\n### Failure modes ↔ primitives\n\n| Failure | Primitive | What it does |\n|---|---|---|\n| Cross-OS content poisoning (paths inside session won't resolve on the other OS) | `pconv dump --rewrite wsl-to-win\\|win-to-wsl` | Extracts + rewrites absolute paths; paste into a session on the other OS. |\n| Folder moved / different cwd / `claude -r \u003cuuid\u003e` says \"not found\" | `pconv list --workspace-toml auto` + `pconv dump \u003cid\u003e` | Finds sessions authored at the pre-move path via `previous_paths`; dumps to paste-ready markdown so you can resume from any cwd. |\n| Stale `sessions-index.json` (picker shows wrong/missing sessions) | `pconv doctor` + `pconv rebuild-index` | Detects lag; rebuilds the index from the `.jsonl`s with a dated `.bak` backup. |\n| Want to commit the conversation as a repo artifact | `pconv dump \u003cid\u003e \u003e docs/agent-context/…md` | Standard stdout redirect; the git repo is the store. |\n\n## Install\n\n```sh\ncargo install --git https://github.com/cybersader/portaconv\n```\n\n(Published to crates.io once v0.1 stabilizes.)\n\n## When `claude -r` is enough (and when it isn't)\n\n`claude -r \u003cuuid\u003e` is the cheap move when **all** of the following hold:\n\n- you know the session UUID,\n- you're on the same OS the session was authored on,\n- file paths inside the session still resolve from your current shell,\n- **and your current cwd matches the session's original cwd** (this one\n  catches people — verify with `find ~/.claude/projects -name \"\u003cuuid\u003e.jsonl\"`\n  and cd to the path that encodes to the same dir name).\n\nIf any of those breaks, `claude -r` returns *\"No conversation found with\nsession ID\"* and you're stuck. That's portaconv territory:\n\n| You hit… | Reach for… |\n|---|---|\n| Don't remember the UUID | `pconv list --workspace-toml auto` |\n| Folder moved / different cwd / `claude -r` \"not found\" | `pconv dump \u003cid\u003e` (paste into a fresh `claude` from anywhere) |\n| Cross-OS resume (WSL → Windows) | `pconv dump \u003cid\u003e --rewrite wsl-to-win` |\n| `/resume` picker is lying | `pconv doctor` then `pconv rebuild-index` |\n| Need a `.md` artifact in the repo | `pconv dump \u003cid\u003e \u003e docs/agent-context/…md` |\n| Agent should self-heal via tool calls | `pconv mcp serve` (3 tools, stdio JSON-RPC) |\n| Last N messages only | `pconv dump \u003cid\u003e --tail 50` |\n\nThe framing: portaconv is the layer **around** `claude -r`, not a\nreplacement. For the narrow happy-path it covers, `claude -r` + `cd`\nis right.\n\n## Usage with Claude Code\n\nThe canonical wiring is via [portagenty](https://github.com/cybersader/portagenty):\n\n```sh\npa init --with-agent-hooks   # scaffolds .mcp.json + .claude/ in your project\n```\n\nThat writes an `.mcp.json` pointing at `pconv mcp serve`. Prefer to\nhand-roll? Same shape works in `~/.claude.json` or a project-level\n`.mcp.json`:\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"portaconv\": { \"command\": \"pconv\", \"args\": [\"mcp\", \"serve\"] }\n  }\n}\n```\n\nOnce wired, the agent gets `list_conversations` + `get_conversation`\ntools and a `convos://conversation/{id}` resource template. See the\n[agents + portagenty guide](https://cybersader.github.io/portaconv/concepts/agents-and-portagenty/)\nfor usage patterns (post-compact recovery, cross-tool handoff,\ncommitted recovery artifacts).\n\n## The unique value\n\nExisting tools in this space are overwhelmingly GUI viewers. Try\n`jhlee0409/claude-code-history-viewer` or\n`d-kimuson/claude-code-viewer` if you want a browser-based UI —\nthey're good. `raine/claude-history` is a solid TUI.\n\nportaconv fills the **terminal-native extract + MCP + path-rewrite**\nniche. Specifically: no existing tool rewrites OS-specific absolute\npaths inside conversation content. That's our wedge.\n\n## Non-goals (explicit)\n\n- **No GUI, no TUI.** Unix-pipe-first. Use the viewers above for\n  browsing.\n- **No daemon, no auto-sync.** On-demand reads.\n- **No path-rewrite by default.** Opt-in transform.\n- **No search / FTS / embeddings** in v0.1. Get-by-ID only.\n\n## Related projects\n\n| Project | Role |\n|---|---|\n| [portagenty](https://github.com/cybersader/portagenty) | Workspace launcher. Uses the workspace `id` field that portaconv will (eventually) leverage for folder-move recovery. |\n| [mcp-workflow-and-tech-stack](https://github.com/cybersader/mcp-workflow-and-tech-stack) | Has the original Docker `claudecode-project-sync` tool — the approach we stepped away from. Will get a banner pointing at portaconv. |\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcybersader%2Fportaconv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcybersader%2Fportaconv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcybersader%2Fportaconv/lists"}