CSV format
Verified against v0.21.0 · internal/poker/csv.go, internal/poker/state.go, internal/standup/csv.go, internal/plugin/csv.go, internal/session/csv.go
GET /api/sessions/{id}/export.csvMembers only. Served as an attachment named after the session title, sanitized.
| Column | Contents |
|---|---|
ticket |
The story’s reference, e.g. PLAT-412. Empty for an ad-hoc item |
story |
Title |
status |
Where the story is in the queue |
estimate |
The value saved onto the story, if one was |
votes |
How many people voted |
detail |
Name: value; Name: value. Only present for the current story, and only once revealed. A guest who voted is named here like a member, and stays named after their link is revoked or expires |
Flat rooms keep those six columns. A room with drafted children appends
story_id, parent_id, planning_role, content_revision, split_revision,
removed, is_remainder, scope_revision, accepted_scope_revision,
estimate_provenance, estimate_review, notes, and dependencies. These identify retained local rows, including
removed children. planning_role is proposed, planning, or context.
Only unremoved planning rows count toward planning progress.
estimate_review is unestimated, current, or needs-review. A stale accepted
value remains in estimate, with status and estimate_review both
needs-review; it is excluded from settled progress until deliberate acceptance.
Provenance distinguishes historical, facilitator-set, poker and
story-total (a split parent’s estimate recorded as the sum of its stories,
which need not be a card in the deck); none of
these fields contains vote values. A context
parent’s estimate is its Previous estimate, retained for history; it is
excluded from active points. For example, parent 13 and children 3, 5, and blank
export those four independent values without a rollup or converting blank to zero.
notes retains each row’s notes with the same spreadsheet escaping as its title.
dependencies is a JSON array sorted by edge ID. Parent rows contain their whole
graph; child rows contain incoming and outgoing edges. Each edge retains id,
parentId, blockerId, dependentId, reviewState, and retiredAt. Join endpoints
by story_id, including removed rows; do not infer identity from titles. Retired
and unavailable-blocker intent stays explicit. These are planning relationships,
with Completion not checked; they do not establish tracker or delivery state.
Consumers should read headers, tolerate these additive columns for split rooms,
and count only retained planning rows with current accepted estimates.
The export is a local handoff; it does not create tracker issues or confirm links.
Standup
Section titled “Standup”| Column | Contents |
|---|---|
name |
Display name |
yesterday |
Their entry |
today |
Their entry |
blockers |
Their entry |
skipped |
Whether they were marked absent |
Plugin-provided kinds
Section titled “Plugin-provided kinds”A plugin ceremony has no fixed columns. The file is id,kind,title,phase plus
one column per top-level field of the kind’s wire state document — the same
projection the room already broadcasts, never raw storage. Nested values are
JSON. The retrospective plugin’s document is revealed, columns, cards,
groups, actionItems; card authorId is omitted until reveal.
It exports only what you could already see
Section titled “It exports only what you could already see”Rows are rendered from the same redacted view the WebSocket sends, not from raw storage. Unrevealed votes are structurally absent, so the export cannot be used to read a round early.
Formula injection
Section titled “Formula injection”Every text cell that begins with =, +, -, @, a tab or a carriage return is
prefixed with a single quote.
A story titled =HYPERLINK("http://evil.example","Q3 planning") would otherwise
become a live formula the moment the file is opened in Excel, Sheets or
LibreOffice. With the prefix it is text.
This means a cell may have a leading ' that was not in the original title. That
is deliberate, and preferable to shipping executable spreadsheets.