Data format
Board layout
The default file backend stores the board below .pinto/ in the repository
where pinto is run. The directory contains the configuration, individual PBI
Markdown files, Sprint data, templates, and the issued_ids history. Each PBI is a separate file so
that a Git diff shows the change to one item clearly.
The board is local-first: no account, server, or database service is required. File and Git backends are the plain-text compatibility boundary: their PBI and Sprint records remain human-readable and a Git diff can show each operation. SQLite is the explicit persistence exception. It exposes the same pinto operations through an opt-in, normalized database, but its versioned schema and migration rules replace the per-record text diff.
PBI files
A PBI file combines TOML frontmatter with a Markdown body:
+++
id = "T-1"
title = "Implement the parser"
status = "todo"
rank = "i"
created = "2026-01-01T00:00:00Z"
updated = "2026-01-01T00:00:00Z"
+++
Acceptance criteria and planning notes belong here.
The frontmatter carries structured fields such as the ID, title, status, rank, labels, relations, timestamps, and optional Sprint information. The body is user-authored Markdown and is preserved when the display locale changes.
An action PBI promoted from a Sprint Retro or Review has one additional machine-readable source link:
[source]
kind = "review"
sprint_id = "S-1"
kind is retro or review, and sprint_id identifies the parent Sprint
and the corresponding child record. The link does not introduce another PBI
or child-record state; the PBI’s normal status remains authoritative.
The filename stem is part of the record identity: tasks/T-1.md and
archive/T-1.md must both contain id = "T-1". File reads validate active and
archived items, as well as Sprint filenames, and stop on filename mismatches or
duplicate logical IDs before a write or migration can overwrite existing data.
Statuses must be columns in the configured workflow. The rank is a fractional index used to keep ordering changes small. Completion and start timestamps are recorded when a PBI crosses the configured workflow boundaries.
Sprint files
A Sprint uses the same TOML-frontmatter/Markdown-body shape under .pinto/sprints/. Its title,
state, planned dates, capacity settings, and timestamps are structured fields; its goal is the
Markdown body. goal_achieved = true or goal_achieved = false records the explicit boolean
retrospective result in frontmatter; a recorded result always accompanies a non-blank Goal, and
writing a blank Goal clears the result. When the field is omitted, the Goal is unevaluated. Closing
a Sprint writes closed_at plus spillover_points, spillover_items, and
unestimated_spillover_items. Zero spillover values and an unset close time are omitted before
close. These fields preserve retrospective context after unfinished PBIs are rolled over or
released, while velocity continues to count completed work only.
Sprint Retro files
A Sprint Retro is stored separately under .pinto/retro/ as
.pinto/retro/<SPRINT-ID>.md. Its ID is the parent Sprint ID, so the file name
and the id frontmatter field must match. The body is free-form Markdown and
the frontmatter records id, created, and updated:
+++
id = "S-1"
created = "2026-07-29T00:00:00Z"
updated = "2026-07-29T00:00:00Z"
+++
## What went well
The file and Git backends keep this record as plain text. The optional SQLite backend also keeps Retro files in this dedicated directory so the format stays visible and compatible with the Sprint CLI.
Sprint Review files
A Sprint Review is stored separately under .pinto/review/ as
.pinto/review/<SPRINT-ID>.md. Its ID is the parent Sprint ID, so the file name
and the id frontmatter field must match. The body is free-form Markdown and
the frontmatter records id, created, and updated:
+++
id = "S-1"
created = "2026-07-29T00:00:00Z"
updated = "2026-07-29T00:00:00Z"
+++
## Demonstrated
The file, Git, and optional SQLite backends keep Review data separate from both the Sprint goal and Sprint Retro records.
The machine-readable show and list representations expose sprint_id as
the explicit parent-Sprint reference for both child-record types. It currently
matches the stable id, which is also the Sprint ID and filename stem. Complete
export --json snapshots place these records in their retros and reviews
collections; importing a snapshot restores the same IDs, parent links, times,
and Markdown bodies.
Retro and Review show views generate parent-Sprint context at read time. The
context is not written into either Markdown body: it includes the parent goal,
state, schedule, close-time spillover, and any available capacity, velocity,
burndown, or Cycle/Lead Time reports. Missing context is displayed as
unavailable and represented as null in --json; a closed Sprint’s stored
spillover remains available after unfinished PBIs are rolled over or released.
The generated detail view also lists active PBIs whose [source] link points to
that child record; their normal PBI statuses are read from the PBI files.
Removing a Sprint protects these one-to-one child records by default. The
--delete-records option is required to remove the matching Retro and Review
files with the Sprint; records for other Sprints are unaffected.
Configuration
.pinto/config.toml controls the shared workflow and presentation settings. The
default workflow is:
columns = ["todo", "in-progress", "review", "done"]
done_column = "done"
It is the one file under .pinto/ intended for hand-editing. Beyond the
workflow columns, it selects the storage backend, project identity, WIP limits,
and display/timezone options. Personal interactive Kanban keybindings belong
in $XDG_CONFIG_HOME/pinto/config.toml; they are not board data and are not
included in board exports. See Configuration for every
setting. Keep machine-readable JSON timestamps in UTC; the display timezone
does not rewrite stored data.
Compatibility boundaries
Board configuration is a strict TOML schema and may gain keys between releases;
an older binary can reject a newer .pinto/config.toml. Markdown PBI and Sprint
records are the file-backed board data. File and Git backends are the plain-text
compatibility boundary, while SQLite is the explicit persistence exception with
its own versioned schema and migration rules. JSON is a machine-readable CLI
output contract, not another persistence backend and not a configuration file.
Personal keybindings are independent of all four board data formats.
Safe operations
Use pinto commands to add, transition, rank, edit, archive, and relate PBIs.
The generated .pinto/issued_ids file preserves every issued item number so a
permanently deleted ID is never assigned to a different PBI; do not remove it
when changing storage backends.
Do not maintain a second hand-edited backlog or edit task files as part of the
normal workflow. Direct recovery is an exception for damaged data; validate the
board with pinto list afterward.
For the full JSON contract and migration rationale, see JSON output and storage migration.