Metadata-Version: 2.5
Name: netcodex-agent-exporter
Version: 0.9.0
Summary: Local-first exporter for AI agent conversations (Codex, Claude Code, Copilot, Cline, Cursor, Gemini CLI, OpenCode and more) to readable Markdown, HTML and PDF, in Spanish or English.
Project-URL: Homepage, https://gitlab.com/netcodex-tech/agent-conversation-exporter
Project-URL: Repository, https://gitlab.com/netcodex-tech/agent-conversation-exporter
Project-URL: Issues, https://gitlab.com/netcodex-tech/agent-conversation-exporter/-/issues
Author: NetCodex Technology
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,claude-code,codex,copilot,cursor,export,markdown,opencode,pdf,transcripts
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Environment :: MacOS X
Classifier: Environment :: Web Environment
Classifier: Environment :: Win32 (MS Windows)
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: Text Processing :: Markup :: Markdown
Classifier: Topic :: Utilities
Requires-Python: >=3.12
Requires-Dist: markdown-it-py>=3.0
Requires-Dist: pydantic>=2.7
Requires-Dist: pygments>=2.17
Requires-Dist: rich>=13.7
Requires-Dist: typer>=0.12
Provides-Extra: desktop
Requires-Dist: claude-agent-sdk>=0.1.50; extra == 'desktop'
Requires-Dist: cryptography>=42; extra == 'desktop'
Requires-Dist: fastapi>=0.115; extra == 'desktop'
Requires-Dist: pillow>=12.1; extra == 'desktop'
Requires-Dist: pypdfium2>=5.0; extra == 'desktop'
Requires-Dist: python-multipart>=0.0.9; extra == 'desktop'
Requires-Dist: pywebview>=5.3; extra == 'desktop'
Requires-Dist: pywinauto>=0.6.9; (sys_platform == 'win32') and extra == 'desktop'
Requires-Dist: uvicorn[standard]>=0.30; extra == 'desktop'
Provides-Extra: ui
Requires-Dist: claude-agent-sdk>=0.1.50; extra == 'ui'
Requires-Dist: fastapi>=0.115; extra == 'ui'
Requires-Dist: pillow>=12.1; extra == 'ui'
Requires-Dist: pypdfium2>=5.0; extra == 'ui'
Requires-Dist: python-multipart>=0.0.9; extra == 'ui'
Requires-Dist: uvicorn[standard]>=0.30; extra == 'ui'
Provides-Extra: web
Requires-Dist: fastapi>=0.115; extra == 'web'
Requires-Dist: python-multipart>=0.0.9; extra == 'web'
Requires-Dist: uvicorn[standard]>=0.30; extra == 'web'
Description-Content-Type: text/markdown

# NetCodex Agent Conversation Exporter

Private, local-first exporter for AI agent conversations (Codex, Claude Code, Copilot, Cline,
Cursor, Gemini CLI, OpenCode and more) into **readable** Markdown, HTML, PDF and Quarkdown, in
Spanish or English: a **desktop app** that finds your AI tools by itself, a local web desk and a
CLI. Exports tell you what was talked about, in plain language, with several templates.

## Status

Version 0.9.0 — **a desktop app for everyone**. Continuing a chat in another agent now speaks
plain language: the picker shows only the destinations that really receive chats (Codex,
Claude Code in Claude Desktop, OpenCode and Antigravity; Claude Code and Codex in the terminal
under *More options*; everything else in a collapsed *Coming soon* list), and the result screen
says what happened and offers the next step as a button: **Open Codex**, **Open OpenCode**,
**Open Antigravity**, or **Restart Claude Desktop** (after a confirmation; *I'll do it later*
is always there). If Antigravity is open, NetCodex closes it politely for you (it never forces
an app to quit) and finishes the copy. Imports into Codex register the folder as a Codex
project automatically through Codex's own app server (`project/create`, idempotent) and put the
chat in it; older Codex builds get a guided step with **Copy path**. Errors say what to do; ids,
paths and verification data live in a collapsed **Technical details** area.

NetCodex is desktop-only: `netcodex ui` and `netcodex desktop --browser` are gone and the app
never opens itself in a web browser. The installer ships Microsoft's WebView2 bootstrapper and
installs WebView2 only when it is missing. **Automatic updates**: the app reads a signed release
manifest (Ed25519) at start-up and once a day, shows a small banner when a new version exists,
and *Update now* downloads the installer, checks its size and SHA-256 against the signed
manifest, installs it silently and reopens NetCodex. See [Updates and releases](#updates-and-releases).

Version 0.8.6 — **history and continuation**. The four supplied logos are local assets, and all existing agent families remain available. Native transport v2 preserves structured source data and blocks unsupported roles, tools, attachments and instructions. CLI `conversation inspect`, `validate` and `transfer` share the Desktop services. See the [eleven-agent forensic report and compatibility matrix](docs/forensics/native-transfer-v2.md).

Codex→Antigravity Desktop 2.21.0 now has real acceptance for **History and continuation**: native dialogue, PNG attachments, disclosed adaptations and complete private source archives. Both a short chat and a 138-message chat continued using earlier facts and survived an application restart. Strict native fidelity keeps its existing requirements. Other directions and content types remain pending Desktop acceptance. See [the recorded evidence and scope](docs/forensics/continuation-antigravity-2026-10-07.json).

### Desktop: your project stays with you

1. Open a project from **Proyectos**, or choose its folder with **Nuevo proyecto**.
2. Review its editable **Contexto**: goal, current state, instructions, decisions and tasks.
3. Select any images or documents in **Archivos**.
4. Choose **Continuar en…**, pick an agent and review exactly what will be sent.

Essential context is the default. Full-history and custom modes live under a collapsed
option. Context extraction uses explicit conversation text, not a hidden AI service; review
it before sending. Saved project context survives application restarts and unavailable source
chats. Full-history mode requires the original chat and never substitutes a summary silently.

**Chats** is a primary navigation destination: discover and choose an agent's local chats, analyze uploaded files, preview original or readable natural-language views,
select templates and export Markdown, PDF, Quarkdown or HTML. **¿Dónde están mis chats?**
shows all known agent locations and whether the stores are readable. Selection includes all
pages; chat lists, project lists and the artifact gallery are paginated. PDF/Quarkdown export
retains the existing Quarkdown/browser dependency checks and reports missing dependencies.

Export one chat or a selection from Chats. Filenames preserve conversation titles, Unicode and
spaces; conversation folders distinguish duplicate titles. Files has one search field, a type
selector and initially closed filters. Filters group agent families while keeping Microsoft
Copilot, GitHub Copilot and Kilo distinct. Connections live in Settings; activity lives in
Transfers. Local vendor icons are shared across filters and destinations.

**Continue in…** converts Desktop conversations into typed native sessions with separate
messages, source roles, original blocks, relationships and hashed attachments. Native codecs
prepare Claude Code local JSONL for Desktop’s documented `/resume` mechanism, Codex rollouts and OpenCode's
official import envelope. No `START-HERE.md`, paste or uploaded history document substitutes
for a Desktop conversation. Claude Desktop Chat has no accredited native importer in this
profile and returns a specific block; Claude Code is a separate destination.

Completion requires native reading, Desktop history listing, reopening, visible message
content and attachments, persistence after restart, and verified continuation. Preparing files
or launching an app never completes a transfer. Retries retain operation IDs and assets;
version, schema, ownership and hash checks prevent overwriting changed sessions. No production
writer is enabled merely by passing format or CLI tests.

The Antigravity 2.19.1 native codec stages SQLite/protobuf in an isolated copy, backs up WAL
and supports conservative publication recovery. **History and continuation** is enabled for
Codex source versions 0.158.0-alpha.2.1 and 0.160.0, with text and PNG images. Other source
versions, documents and image types require acceptance first. Strict native publication
still requires full engine-state equivalence. Certificates bind source, destination version,
modality, codec and contents; passing local reader tests alone does not enable publication.

Projects group chats from different agents by their project folder. Editor workspace metadata
and recent-folder records also contribute projects independently of chat readability. Windows
extended path aliases (`\\?\`) merge into the same project without losing saved contexts.
Trae/Windsurf conversation formats remain unverified; their discoverable project metadata is shown.
The sidebar exposes Projects, Chats, Files and Transfers, with Settings at the bottom.
Ctrl+K searches titles, chat messages and supported document content locally through SQLite FTS5,
with accent normalization and limited typo correction. No model downloads are required.
Project folders require explicit access; Temp and known agent artifact folders are registered
locally. Users can add or remove roots. Origin attribution requires folder or conversation
reference evidence; other files remain unidentified.

The existing index appears before background refresh. Inventory is persisted; files are filtered
and paginated by SQL. Schema upgrades back up the workspace database before migration.
See [native session formats, validation and Desktop blockers](docs/netcodex-native-sessions-validation.md) and the
[0.8.3 interface/search baseline](docs/netcodex-0.8.3-validation.md).

Files include paginated galleries, images, safe Markdown, code, expandable JSON, local PDF
pages, audio/video, DOCX text and ZIP contents. Saving and transfers make durable copies
without overwriting originals. Drag files onto a project to keep copies, or onto an agent to
review a transfer. The explorer has no source-file deletion action.

Installed-app inventory combines Windows registry, Appx, shortcuts, extension manifests,
known paths and PATH. Desktop and CLI capabilities remain separate. Codex CLI sessions are
verified through its app server (resume/read/list); Claude Code through the official Agent SDK
session reader. Unsupported Desktop destinations report a native importer blockage.
Detection never implies native integration. Recognition and opening are reported separately;
failed native recognition preserves the session and supports retry without creating a duplicate.

Desktop preparation lives in `<project>/.netcodex/handoff/<operation>/`: typed native session,
ID correspondence, provenance, versioned codec receipt and copied hashed attachments.
Project ZIP export includes saved context and selected files. Existing redaction rules apply.
No external publication or model request is required for preparation and offline verification.

The local SQLite index polls authorized roots every 30 seconds, reconciles files every five
minutes and checks chat sources every 90 seconds. Each root is capped at 20,000 entries with a visible notice; add a narrower root
for large folders. Legacy advanced scans cap at 100,000. Text previews are limited to 512 KB,
PDF/image input to 50 MB and images to 40 million pixels; saved copies retain the complete file.
Private environment/key files and dependency/cache directories are excluded from project indexing.

See [0.8.2 implementation and validation](docs/netcodex-0.8.2-validation.md).

### Where are my chats?

<!-- netcodex:where:start (generated by scripts/export_locations.py) -->
| Tool | Status | Windows | macOS / Linux | Import via |
| --- | --- | --- | --- | --- |
| Codex CLI / VS Code / Desktop | supported; override: `CODEX_HOME` | `%USERPROFILE%\.codex\sessions\YYYY\MM\DD\rollout-*.jsonl`<br>`%USERPROFILE%\.codex\archived_sessions\rollout-*.jsonl`<br>`%USERPROFILE%\.codex\state_*.sqlite`<br>`%USERPROFILE%\.codex\session_index.jsonl` | `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl`<br>`~/.codex/archived_sessions/rollout-*.jsonl`<br>`~/.codex/state_*.sqlite`<br>`~/.codex/session_index.jsonl` | Upload files, Local sources, CLI |
| Claude Code CLI / VS Code | supported; override: `CLAUDE_CONFIG_DIR` | `%USERPROFILE%\.claude\projects\<project>\<session>.jsonl` | `~/.claude/projects/<project>/<session>.jsonl` | Upload files, Local sources, CLI |
| Claude Desktop (Code tab) | supported; override: `CLAUDE_CONFIG_DIR` | `%APPDATA%\Claude\claude-code-sessions\**\local_*.json`<br>`%USERPROFILE%\.claude\projects\<project>\<session>.jsonl` | `<config>/Claude/claude-code-sessions/**/local_*.json`<br>`~/.claude/projects/<project>/<session>.jsonl` | Local sources, CLI |
| Claude Cowork | supported | `%APPDATA%\Claude\local-agent-mode-sessions\**\local_<id>.json`<br>`%APPDATA%\Claude\local-agent-mode-sessions\**\local_<id>\.claude\projects\**\*.jsonl` | `<config>/Claude/local-agent-mode-sessions/**/local_<id>.json`<br>`<config>/Claude/local-agent-mode-sessions/**/local_<id>/.claude/projects/**/*.jsonl` | Local sources, CLI |
| Claude.ai (official data export) | supported; override: `NETCODEX_CLAUDE_AI_EXPORT` | `%USERPROFILE%\Downloads\data-*.zip`<br>`%USERPROFILE%\Downloads\<folder>\conversations.json` | `~/Downloads/data-*.zip`<br>`~/Downloads/<folder>/conversations.json` | Local sources, CLI |
| GitHub Copilot Chat | supported | `%APPDATA%\<editor>\User\workspaceStorage\<hash>\chatSessions\*.jsonl`<br>`%APPDATA%\<editor>\User\workspaceStorage\<hash>\chatSessions\*.json`<br>`%APPDATA%\<editor>\User\globalStorage\emptyWindowChatSessions\*.json` | `<config>/<editor>/User/workspaceStorage/<hash>/chatSessions/*.jsonl`<br>`<config>/<editor>/User/workspaceStorage/<hash>/chatSessions/*.json`<br>`<config>/<editor>/User/globalStorage/emptyWindowChatSessions/*.json` | Local sources, CLI |
| GitHub Copilot CLI | supported | `%USERPROFILE%\.copilot\session-state\<id>\events.jsonl` | `~/.copilot/session-state/<id>/events.jsonl` | Local sources, CLI |
| Cline / Roo Code / Kilo Code | supported | `%APPDATA%\<editor>\User\globalStorage\saoudrizwan.claude-dev\tasks\<id>\api_conversation_history.json`<br>`%APPDATA%\<editor>\User\globalStorage\rooveterinaryinc.roo-cline\tasks\<id>\api_conversation_history.json`<br>`%APPDATA%\<editor>\User\globalStorage\kilocode.kilo-code\tasks\<id>\api_conversation_history.json` | `<config>/<editor>/User/globalStorage/saoudrizwan.claude-dev/tasks/<id>/api_conversation_history.json`<br>`<config>/<editor>/User/globalStorage/rooveterinaryinc.roo-cline/tasks/<id>/api_conversation_history.json`<br>`<config>/<editor>/User/globalStorage/kilocode.kilo-code/tasks/<id>/api_conversation_history.json` | Local sources, CLI |
| Cursor | supported | `%APPDATA%\Cursor\User\globalStorage\state.vscdb` | `<config>/Cursor/User/globalStorage/state.vscdb` | Local sources, CLI |
| Gemini CLI | supported | `%USERPROFILE%\.gemini\tmp\<hash>\chats\session-*.json`<br>`%USERPROFILE%\.gemini\tmp\<hash>\logs.json` | `~/.gemini/tmp/<hash>/chats/session-*.json`<br>`~/.gemini/tmp/<hash>/logs.json` | Local sources, CLI |
| Continue | supported | `%USERPROFILE%\.continue\sessions\*.json` | `~/.continue/sessions/*.json` | Local sources, CLI |
| Aider | supported; override: `NETCODEX_AIDER_PATHS` | `<repo>\.aider.chat.history.md` | `<repo>/.aider.chat.history.md` | Local sources, CLI |
| OpenCode | supported; override: `OPENCODE_DATA_DIR`, `XDG_DATA_HOME` | `%USERPROFILE%\.local\share\opencode\opencode.db`<br>`%USERPROFILE%\.local\share\opencode\storage\session\<projectID>\<sessionID>.json` | `~/.local/share/opencode/opencode.db`<br>`~/.local/share/opencode/storage/session/<projectID>/<sessionID>.json` | Local sources, CLI |
| Google Antigravity | best effort | `%USERPROFILE%\.gemini\antigravity\conversation_summaries.db`<br>`%USERPROFILE%\.gemini\antigravity\conversations\*.db` | `~/.gemini/antigravity/conversation_summaries.db`<br>`~/.gemini/antigravity/conversations/*.db` | Local sources, CLI |
| Trae | encrypted, not supported | `%APPDATA%\Trae\ModularData\ai-agent\database.db`<br>`%APPDATA%\Trae CN\ModularData\ai-agent\database.db` | `<config>/Trae/ModularData/ai-agent/database.db`<br>`<config>/Trae CN/ModularData/ai-agent/database.db` | - |
| Windsurf | encrypted, not supported | `%USERPROFILE%\.codeium\windsurf\cascade\*.pb` | `~/.codeium/windsurf/cascade/*.pb` | - |

`<config>` is `~/Library/Application Support` on macOS and `~/.config` on Linux. `<editor>` is any VS Code-family editor: Code, Code - Insiders, VSCodium, Cursor, Windsurf, Trae, Trae CN, Antigravity, Kiro, Positron.
<!-- netcodex:where:end -->

Find them on your machine with `netcodex where` (`--json`, `--patterns`), or open the desktop
app and click **Where are my chats?**: it lists every tool with its status, the
resolved folder on this computer (Copy path / Open folder) and what to import. Encrypted
stores (current Trae, Windsurf) are reported but cannot be exported. claude.ai chats are not
stored locally: request the official data export (Settings > Privacy > Export data) and save
the `data-*.zip` / `conversations.json` in Downloads or point `NETCODEX_CLAUDE_AI_EXPORT` at it.

Client labels written to the `tool` field: `codex-cli`, `codex-vscode`, `codex-desktop`,
`claude-code-cli`, `claude-code-vscode`, `claude-desktop`, `claude-cowork`,
`copilot-chat-<editor>`, `cline-*`, `roo-code-*`, `kilo-code-*`, `cursor`, `copilot-cli`,
`gemini-cli`, `continue`, `aider`, `claude-ai`, `antigravity`.

All parsers map to one canonical model (`Conversation` -> `Turn` -> `MessagePart`
with `text`, `tool_call`, `tool_result`, `reasoning`, `image`, `attachment`,
`system_context` and `summary` parts). Tool results are attached to their call,
injected environment/instruction/hook context is classified as system context,
and mirrored Codex `event_msg` messages are de-duplicated.

Raw conversations stay local by default. Generated exports are written under
`exports/`, which is intentionally ignored by Git.

## Install

NetCodex runs on your own machine; it reads the local conversation stores and never
uploads them. Python 3.12+ is required for the package installs.

| How | Command | Notes |
| --- | --- | --- |
| Desktop app (Windows) | Download `NetCodex-Setup-<version>-x64.exe` from the landing page (Download for Windows) | Per-user install, no admin, no Python. Portable `NetCodex-<version>-portable.exe` too. |
| Desktop app (any OS) | `pipx install "netcodex-agent-exporter[desktop]"` then `netcodex desktop` | Native window via pywebview. |
| pipx | `pipx install "netcodex-agent-exporter[desktop]"` | The desktop app plus the CLI. Drop `[desktop]` for the CLI only. |
| uv | `uv tool install "netcodex-agent-exporter[desktop]"` | Same, using uv. |
| Binary | Download `netcodex-<version>-windows-x86_64.exe` or `-linux-x86_64` from the GitLab Release | Single file, no Python needed; includes the UI. |
| From source | `git clone ... && uv sync && uv run netcodex --help` | For development. |

The PyPI package and release binaries are published from `v*` tags (first release:
v0.3.0). Extras: `[desktop]` adds pywebview, the local service and update verification for
`netcodex desktop`; `[ui]` (alias `[web]`) keeps only the FastAPI/uvicorn service used by the
development API; the core CLI only needs Pydantic and Typer. PDF export needs the external
[Quarkdown](https://github.com/iamgio/quarkdown) binary on `PATH` (no Python extra).

### Desktop app

Download the Windows installer from the landing page (or the GitLab Release), run it, and open
**NetCodex** from the Start menu. With Python on any OS:
`pipx install "netcodex-agent-exporter[desktop]"` and `netcodex desktop`.

- A native window titled NetCodex opens (Edge WebView2 on Windows, WebKit on macOS, GTK or Qt on
  Linux) over a local service on a random `127.0.0.1` port with a per-launch token. The window
  is opened on a single-use launch link that sets an HttpOnly session cookie, so the token never
  appears in a URL. Closing the window stops the service.
- **Detected on this computer**: on open it scans every supported tool through the source
  registry and shows a card per installed tool (status, conversation count, last activity,
  workspaces). Encrypted stores (Trae, Windsurf) are flagged; tools that are not installed are
  collapsed. **Export all**, per-tool **Export**, and **Choose...** (search, date range and
  workspace filters) write Markdown plus an `index.md` into the output folder, incrementally
  (unchanged conversations are skipped; untick *Incremental* to re-export). **Open output
  folder** opens it in Explorer/Finder.
- Default output folder: `Documents\NetCodex Exports` (Windows Known Folder, so OneDrive-redirected
  Documents work). Change it with **Change...**; it is remembered in `settings.json` under
  `%APPDATA%\NetCodex` (macOS `~/Library/Application Support/NetCodex`, Linux
  `~/.config/netcodex`; `NETCODEX_APP_DIR` overrides). No conversation content is stored there.
- **Upload files** and **Where are my chats?** stay available (the full export desk).
- Single instance: launching it again brings the open window to the front.
- WebView2: the installer bundles Microsoft's WebView2 Evergreen Bootstrapper (downloaded from
  Microsoft and Authenticode-checked at build time) and installs the runtime silently only when it
  is missing. If it is still missing when NetCodex starts, a native message offers to install it
  (bundled bootstrapper, or Microsoft's [download page](https://go.microsoft.com/fwlink/p/?LinkId=2124703)
  for the portable build) and the app exits; it never falls back to a browser. If the window
  cannot open, a native dialog shows the reason and the log file
  (`%APPDATA%\NetCodex\netcodex-desktop.log`).
- Automatic updates (installer builds): see [Updates and releases](#updates-and-releases).
  Settings has **Check for updates automatically** (on by default) and **Check for updates**.
- `netcodex desktop --smoke` starts the service, checks it answers and exits (used by CI).

Windows packaging lives in `packaging/windows/`: `build.ps1` (PyInstaller onedir app + portable
single-file exe, both smoke-tested, then Inno Setup 6 `netcodex.iss` -> per-user installer with
Start menu entry, optional desktop shortcut, uninstaller, icon and version metadata) and
`test-install.ps1` (silent `/VERYSILENT /CURRENTUSER` install, smoke test, silent uninstall).
Icons are generated from the brand mark by `scripts/make_icons.py`.

**SmartScreen and code signing.** The installer is not code-signed yet, so Windows SmartScreen
shows "Windows protected your PC" on first run (More info > Run anyway). The release job signs
the exes and the installer with `signtool` automatically once the masked CI/CD variables
`CODE_SIGNING_PFX_BASE64` (base64 of a code-signing .pfx) and `CODE_SIGNING_PFX_PASSWORD`
(optional `CODE_SIGNING_TIMESTAMP_URL`) exist; without them the step is skipped.

**macOS and Linux desktop builds** are not produced by CI: a macOS app bundle needs a macOS
runner (`packaging/icons/netcodex.icns` is ready), and a Linux AppImage would have to bundle
GTK/WebKit2. On both, use `pipx install "netcodex-agent-exporter[desktop]"`; on Linux also
install a pywebview backend (`sudo apt install python3-gi gir1.2-webkit2-4.1` with
`pipx inject netcodex-agent-exporter pygobject`, or `pipx inject netcodex-agent-exporter "pywebview[qt]"`).

### The desk inside the app

The window shows the Next.js desk in `web/`, built as a static site by `npm run desk:build`
(`scripts/build-desk.mjs`) into `src/netcodex/web/desk/` and shipped in the wheel. It talks to
the app's own local service on `127.0.0.1` (random port, per-launch token exchanged for an
HttpOnly, SameSite=Strict cookie; requests whose `Host` is not a loopback name are rejected).
Nothing is sent to a NetCodex server. A source checkout without that build falls back to a
minimal built-in page.

## Readable view

Exports show **what was talked about**, not a dump of commands and variables. The readable view
(default since 0.5) keeps every user and assistant message verbatim, code blocks included, and
turns the noise into plain language:

- each tool step becomes one sentence: "Leyó el archivo `src/app.py`" / "Read the file
  `src/app.py`", "Ejecutó las pruebas (`pytest`) — 42 pasaron, 1 falló", "Editó 3 archivos: …",
  "Buscó en la web: “…”", "Creó un subagente para “…”";
- consecutive steps are grouped in a collapsible **Lo que hizo el asistente / What the assistant
  did** list;
- tool outputs are summarized (exit status, test counts, number of lines or results, first line);
- system/environment context is hidden; reasoning appears only on request (`--include-reasoning`,
  `config set show_reasoning true`) as a short collapsible note;
- a header lists participants, tool, model, project, dates, duration, messages, files changed and
  commands run, followed by a **conversation summary** built *extractively* (first request, key
  follow-ups, last answer): sentences copied from the conversation, no AI involved.

Everything is deterministic and offline. `--view original` keeps the full-fidelity transcript
(every tool input and output) when you need the technical record:

```powershell
netcodex export --source codex                    # readable, default template, OS language
netcodex export --source claude --view original   # full technical detail
```

## Continue in another agent

Hand a conversation over to another agent, e.g. continue a Codex session in Claude Code:

```powershell
netcodex handoff codex 0193a2b4 --to claude                 # print the context pack
netcodex handoff codex 0193a2b4 --to claude --launch        # open Claude Code in the project with it
netcodex handoff claude 7f3e --to codex --out handoff.md --max-tokens 4000 --lang en
netcodex handoff codex 0193a2b4 --to claude --native        # EXPERIMENTAL: a resumable Claude Code session
netcodex handoff imports                                    # imports made by NetCodex
netcodex handoff undo claude-1a2b3c4d5e6f                   # remove exactly what an import created
```

The **pack** (always available) is built locally from the readable view: goal, background,
decisions taken, files touched (relative to the workspace), commands and outcomes, open items, the
assistant's last state and the last messages verbatim, fitted to a token budget. It never contains
secrets or home-folder paths unless `--include-paths` is given. `--launch` starts the target CLI in
the conversation's folder with a first prompt that points to the pack (saved under
`.netcodex/handoff/` in that folder); without the CLI, the pack goes to the clipboard and the folder
opens. `--native` (Claude Code and Codex only, experimental) creates a new session file in the
target's own store so it appears in `claude --resume` / `codex resume`; nothing existing is modified
and `netcodex handoff undo` removes it. The desk offers the same as **Continue in another agent**.

## Templates

| id | Name (es / en) | What it looks like |
| --- | --- | --- |
| `chat` | Chat | Bubbles per speaker, actions folded away (default) |
| `transcript` | Transcripción / Transcript | Interview style with the time of every line |
| `report` | Informe / Report | Summary and key facts first, dialogue, appendix of actions |
| `book` | Libro / Book | Serif edition, one chapter per day, table of contents |
| `minimal` | Mínima / Minimal | Plain and compact |
| `galactic-guide`, `technical-dossier`, `executive-brief`, `audit-trail`, `knowledge-base` | Quarkdown templates | Native Quarkdown look; MD/HTML/PDF use the closest layout |

Every template renders Markdown (`md`), self-contained HTML (`html`, light/dark, syntax
highlighting, no external resources), PDF (`pdf`) and Quarkdown (`qd`):

```powershell
netcodex templates
netcodex export --source codex --template book --formats md,html,pdf
```

**PDF without Quarkdown.** PDFs are printed from the HTML template by a Chromium browser you
already have: Microsoft Edge on Windows, Chrome/Chromium/Brave on macOS and Linux (or set
`NETCODEX_BROWSER` to its executable). It runs headless with a temporary profile. If no browser
is found, Quarkdown is used when installed; otherwise the export explains what to install.
`netcodex doctor` shows which engine will be used.

## Languages

Labels, headings, narrated steps and dates are available in **Spanish** and **English**
(`lunes, 8 de junio de 2026 · 09:00` / `Monday, June 8, 2026 · 9:00 AM`). The language is taken
from, in order: `--lang es|en`, `NETCODEX_LANG`, the saved setting (`netcodex config set lang es`,
or the desk settings) and the operating system language, falling back to English. The CLI help
follows the same rule (`netcodex --lang es --help`).

## Commands

```text
netcodex                      welcome panel with the main commands
netcodex where                where each tool keeps its chats, and what exists on this machine
netcodex export               export (readable by default) to md, html, pdf, qd
netcodex view <id>            read one conversation in the terminal (paged; id prefix or fragment)
netcodex search "text"        local full-text search with snippets (nothing leaves your computer)
netcodex stats                conversations per tool, per month, top projects (counts only; --messages)
netcodex templates            list the export templates
netcodex handoff <src> <id> --to claude   continue a conversation in another agent
netcodex doctor               WebView2, PDF browser, Quarkdown, chat stores, output folder, settings
netcodex open [exports|config|<tool>]   open a folder (--print only prints it)
netcodex config get|set|path  lang, default_view, default_template, output_dir, show_reasoning...
netcodex desktop              the desktop app
```

Every command has examples in `netcodex <command> --help`.

## License

MIT, see [LICENSE](LICENSE).

## Setup (development)

```powershell
uv sync
uv run netcodex --help
```

## Common Commands

```powershell
uv run netcodex sources                      # registered sources, found / not found
uv run netcodex where                        # where each tool keeps its chats, and what is on this machine
uv run netcodex where --json                 # same, machine-readable (also: sources --paths)
uv run netcodex scan --sources all
uv run netcodex analyze --source auto --json
uv run netcodex export --all --out exports   # every available source, every session
uv run netcodex export --all --since 7d --workspace my-repo
uv run netcodex export --source claude --formats md,qd --limit 1
uv run netcodex export --local --source codex --formats md,qd,pdf --template galactic-guide --json
uv run netcodex validate exports
uv run netcodex export --source codex --formats md,html,pdf --template report --lang es
uv run netcodex view <id> --source codex
uv run netcodex search "migration" --since 30d
uv run netcodex stats --messages
uv run netcodex doctor
```

`export` accepts `--source auto|all|<name>[,<name>]` (or `--all`), `--limit N` per
source (default `0` = all sessions), `--since`/`--until` (ISO date or an age such
as `7d`, `12h`, `2w`) and `--workspace <text>` (case-insensitive match on the
session's working directory). Tool inputs/outputs are capped per block with
`--max-tool-output-lines` (default 200) and `--max-tool-output-bytes` (default
32000); the Markdown notes how much was left out. Payloads over 200k characters
are also cut at import time, before redaction.

Exports are incremental: `<out>/.netcodex-state.json` records a fingerprint of
each session's source files (size and mtime, including subagent files), its title
and the export options. Re-running `export` into the same folder only re-renders new
or changed conversations (renamed ones replace their old folder); `--force`
re-exports everything and `--no-incremental` ignores the state file. To keep a
folder up to date continuously:

```powershell
uv run netcodex watch --out exports --interval 60   # Ctrl+C to stop
```

Large exports use worker processes (`--jobs`, default automatic, up to 4).

The "Where are my chats?" table above, `netcodex where`, the desk help panel and the public
`/where` page all come from `netcodex.sources.locations`. After changing it, regenerate the
README table and `web/lib/chat-locations.json` with `uv run python scripts/export_locations.py`
(a test fails while they are out of date).

Sources live in a registry (`netcodex.sources.registry`). Store locations come
from a per-platform path matrix (`netcodex.sources.paths`: Windows
`%APPDATA%`, macOS `~/Library/Application Support`, Linux `~/.config`) that also
enumerates VS Code-family editors (Code, Insiders, VSCodium, Cursor, Windsurf,
Trae, Antigravity, Kiro, Positron).

Each export creates one folder per conversation named
`<source>/<date>-<title-slug>-<short-id>/` containing `conversation.md`,
`metadata.json` and `netcodex-manifest.json`, plus an `index.md` table (date,
title, tool, turns, link) at the export root.

`conversation.md` (Markdown v2) starts with YAML frontmatter (`title`, `id`,
`source`, `tool`, `originator`, `model`, `workspace`, `git_branch`,
`started_at`, `ended_at`, `turn_count`, `subagent_count`, `parent_id`), uses one
`## Role · timestamp` heading per turn, keeps code fences intact and puts tool
calls/results and reasoning in collapsible `<details>` blocks. Images and
attachments become placeholders. Content switches:

```powershell
uv run netcodex export --source codex --limit 20 `
  --no-reasoning --no-tool-output --include-system-context --no-subagents `
  --max-tool-output-lines 50
```

Every export records the shared workflow `analyze -> parse -> render -> package`
inside `netcodex-manifest.json`, including generated artifact hashes without
storing transcript bodies.

PDF export prints the HTML template with Microsoft Edge/Chrome/Chromium (headless), falling
back to Quarkdown; if neither is available the export writes `pdf-export-error.txt` with
guidance instead of failing silently (see [Templates](#templates)).

## Updates and releases

**How the app updates itself.** The release manifest `latest.json` (`version`, `tag`,
`released_at`, `windows.installer|portable` with `name`, `size`, `sha256`, plus `notes`) is
signed with an Ed25519 key that never enters the repository; the detached signature is
`latest.json.sig` (base64). The public landing serves both at
`https://ace-web-qtwh5c-462d78-161-153-45-177.sslip.io/downloads/latest.json` (+ `.sig`), next
to the installers, with `Cache-Control: no-cache`. The app (`netcodex.desktop.updates`):

1. after the window is up, then every 24 hours (setting *Check for updates automatically*),
   downloads the manifest and its signature (HTTPS only; plain HTTP only for loopback test
   servers) and verifies the signature with the public key embedded in the app before reading it;
2. compares semantic versions; when newer, the desk shows a banner (*Update now* / *Later*,
   release notes);
3. *Update now* streams the installer to `%TEMP%\NetCodex-update\<version>\` with progress,
   requires the exact size and SHA-256 from the signed manifest, then starts it with
   `/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /CLOSEAPPLICATIONS /RELAUNCH=1 /CURRENTUSER` and
   closes NetCodex; the Inno Setup script reopens the app when `/RELAUNCH=1` is given.

Portable and pip installs only get the banner with a download link. No identifiers or usage
data are sent: the only request is the manifest. Offline checks fail quietly.
`NETCODEX_UPDATE_URL` points the app at another manifest (testing). A tampered manifest
(bad signature) or installer (size/hash mismatch) is rejected and nothing is installed.

**Releasing (local).** GitLab CI minutes are not required; releases run on the release machine:

```powershell
uv run python scripts/release_local.py 0.9.0 --dry-run   # build, hash, sign, print the plan
uv run python scripts/release_local.py 0.9.0             # publish
```

The script builds (`node scripts/build-desk.mjs`, `uv build`, `packaging\windows\build.ps1`,
then `uv sync --all-extras`), stages `release-out\v<version>\` (installer, portable, wheel,
sdist, `SHA256SUMS`, `latest.json`, `latest.json.sig`), signs the manifest with
`%USERPROFILE%\.netcodex-release\update-signing-key.pem` and checks the signature with the key
embedded in the app. Publishing uploads the assets to the GitLab generic package registry
(`netcodex/v<version>/…`) and creates the GitLab Release with `glab api` (glab must be logged in;
the commit must already be pushed), moves the pointer `netcodex-desktop/latest/latest.json` +
`.sig` last, runs `uv publish` with `UV_PUBLISH_TOKEN` from the environment (never printed),
and calls the Dokploy deploy webhook of the landing (`DOKPLOY_URL`, `DOKPLOY_DEPLOY_TOKEN`).
`--skip-build`, `--skip-gitlab`, `--skip-pypi` and `--skip-landing` leave steps out. Bump
`version` in `pyproject.toml` and `src/netcodex/__init__.py` first. Keep a backup of the signing
key: without it, installed apps cannot accept new updates.

The tag pipeline in `.gitlab-ci.yml` still describes the CI equivalent (builds, registry
uploads, release, PyPI, landing redeploy); its `latest.json` is not signed, so the landing does
not serve it as an update manifest. macOS binaries need a macOS runner; build them locally with
`uv run pyinstaller --onefile --name netcodex --collect-submodules netcodex --collect-submodules uvicorn --collect-data netcodex scripts/netcodex_entry.py`.

## Development

```powershell
uv run ruff check .
uv run pytest
uv build
npm run diagrams:check
```

## Local Web

Install dependencies once:

```powershell
uv sync
npm install
npm install --prefix web
```

Run the local API and web UI together from one terminal:

```powershell
npm run dev
```

This starts:

- API: `http://localhost:8000`
- Web: `http://127.0.0.1:3100`

You can still run each side separately when debugging:

```powershell
npm run api:dev
npm run web:dev
```

In development (`npm run dev`) the desk reads `NEXT_PUBLIC_API_URL` (default
`http://localhost:8000`) and the dev API also serves the local-sources endpoints. The MVP web flow accepts `.jsonl`, `.sqlite`, and
`.zip` uploads, analyzes detected Claude/Codex sessions, previews Markdown,
and downloads generated artifacts plus `netcodex-manifest.json` as a ZIP.

### Public landing deployment (landing-only mode)

The web app can be deployed publicly as a marketing site (e.g. Dokploy/Nixpacks
with build path `web`, `npm run build` then `npm run start`). Because the export
workspace needs the local API, a production build runs in **landing-only mode**
when `NEXT_PUBLIC_LANDING_ONLY=1` is set, or when `NEXT_PUBLIC_API_URL` is unset:
`/app` shows a "This tool runs locally" panel with install instructions instead
of the upload form, and every "Open app" call to action points to `/install`.
Set `NEXT_PUBLIC_LANDING_ONLY=0` to force the full workspace in a production
build. `next dev` always keeps the local workspace.

**Download for Windows.** The GitLab project is private, so visitors cannot download Release
assets. The landing serves the installer itself: `npm run build` runs `prebuild`
(`web/scripts/fetch-downloads.mjs`), which reads `latest.json` from the generic package registry
with a project deploy token that only has `read_package_registry`, downloads the installer and
the portable exe into `web/public/downloads/`, verifies size and SHA-256 and writes
`web/lib/downloads.json` (version, size, SHA-256 shown on the page). It also fetches
`latest.json.sig`, verifies it with the update public key and publishes the signed update
manifest at `/downloads/latest.json` (+ `.sig`) for the desktop app's automatic updates. Configure it as build-time
environment of the landing app (never commit it): `GITLAB_DEPLOY_TOKEN_USER`,
`GITLAB_DEPLOY_TOKEN` (optional `GITLAB_PROJECT_ID`, `GITLAB_URL`,
`NETCODEX_DOWNLOADS_REQUIRED=1` to fail the build when the download fails). Without a token the
page shows the pipx instructions only. The token is used only during the build; it never
reaches the browser.

See `docs/web/local-web-api.md` for the API contract and temporary file cleanup
policy.

## Architecture

The canonical architecture model lives in `docs/architecture/likec4/model.c4`
and is validated with LikeC4. GitLab-friendly Mermaid mirrors live in
`docs/architecture/c4.md`.

VS Code users should open the `.c4` file with the LikeC4 extension installed.
The expected extension id is `likec4.likec4-vscode`.

## GitLab Flow

NetCodex uses GitLab Flow, not Git Flow:

- `main` is protected and always releasable.
- Work starts from issue branches named `issue/<iid>-<short-slug>`.
- Every change goes through a merge request into `main`.
- Merge requires a green pipeline and resolved discussions.
- `release/*` branches and `v*` tags are reserved for release preparation.

See `docs/development/gitlab-flow.md` for the full policy.

## Privacy Rules

- Do not commit real exports, raw `.jsonl` files, SQLite databases or local
  attachments.
- Use sanitized fixtures only.
- Keep parsers read-only against source directories.
- Use `--include-paths` only when full local paths are intentionally needed in
  the generated metadata.
