What feature would you like to see?
Export the entire session conversation from the web UI as a single file download.
User flow
- Session header overflow menu (⋯) → Export conversation
- Small dialog: choose format JSON (default) or Markdown, then Download
- Remember last format in
localStorage (hapi.sessionExportFormat)
- Show loading / error toasts; support
AbortController if the user leaves mid-export
- Trigger browser download via
Blob + <a download> (desktop + mobile PWA)
Why JSON is the default
- Lossless: preserves hub
DecryptedMessage + session metadata (tools, codex, attachments meta, etc.)
- Markdown is a human-readable derived view from the same payload, not a second source of truth
Hub: single export endpoint
GET /api/sessions/:id/export
Returns HapiSessionExport v1 (format-agnostic):
{
"schemaVersion": 1,
"exportedAt": 1730000000000,
"session": { },
"messages": []
}
- Same auth as existing session routes (
requireSessionFromParam)
- Server-side
getAllMessagesForExport(sessionId) — do not paginate via repeated public /messages calls from the browser
- Apply visible-message filtering consistent with the chat UI where applicable
- Hard cap (e.g. 20_000 messages) →
413 with a clear message; no silent truncation
Web serialization
- JSON:
JSON.stringify(payload, null, 2) → .json
- Markdown:
serializeSessionMarkdown(payload) using normalizeDecryptedMessage; skip nulls; ## User / ## Assistant sections; concise tool summaries; optional YAML front matter → .md
- Filename example:
{title-slug}-{sessionId-8chars}-{YYYY-MM-DD}.{json|md}
Suggested files
shared/src/sessionExport.ts — schema/types
hub/src/store/messages.ts — export query helper
hub/src/web/routes/sessions.ts — route
web/src/lib/sessionExport/* — fetch, download helper, markdown serializer + tests
web/src/components/SessionHeader.tsx — menu + dialog
web/src/lib/locales/en.ts, zh-CN.ts
Additional information
Motivation
Acceptance criteria
Out of scope
Prior art
Open WebUI, LibreChat, LobeChat: JSON as canonical export + optional Markdown for reading.
Manual test plan
- Short session → JSON → verify count/order
- Same session → Markdown → readable structure
- Reload → format preference retained
- Very long session → 413 or success with clear UX
- iPhone PWA / Android Chrome → file downloads
What feature would you like to see?
Export the entire session conversation from the web UI as a single file download.
User flow
localStorage(hapi.sessionExportFormat)AbortControllerif the user leaves mid-exportBlob+<a download>(desktop + mobile PWA)Why JSON is the default
DecryptedMessage+ session metadata (tools, codex, attachments meta, etc.)Hub: single export endpoint
Returns
HapiSessionExportv1 (format-agnostic):{ "schemaVersion": 1, "exportedAt": 1730000000000, "session": { }, "messages": [] }requireSessionFromParam)getAllMessagesForExport(sessionId)— do not paginate via repeated public/messagescalls from the browser413with a clear message; no silent truncationWeb serialization
JSON.stringify(payload, null, 2)→.jsonserializeSessionMarkdown(payload)usingnormalizeDecryptedMessage; skip nulls;## User/## Assistantsections; concise tool summaries; optional YAML front matter →.md{title-slug}-{sessionId-8chars}-{YYYY-MM-DD}.{json|md}Suggested files
shared/src/sessionExport.ts— schema/typeshub/src/store/messages.ts— export query helperhub/src/web/routes/sessions.ts— routeweb/src/lib/sessionExport/*— fetch, download helper, markdown serializer + testsweb/src/components/SessionHeader.tsx— menu + dialogweb/src/lib/locales/en.ts,zh-CN.tsAdditional information
Motivation
GET /api/sessions/:id/messages(200/page)Acceptance criteria
GET /api/sessions/:id/exportreturnsHapiSessionExportv1 (session + chronological visible messages)413, explicit errorserializeMarkdownunit testsOut of scope
Prior art
Open WebUI, LibreChat, LobeChat: JSON as canonical export + optional Markdown for reading.
Manual test plan