time-machine
Time Machine
Per-task daily snapshots plus one-click restore. Every issue in your workspace that was modified in the last 24 hours gets a canonical field snapshot captured once a day. Any member can open the Time Machine on a task, browse snapshot dates, preview the field-by-field diff against the current state, and restore any snapshot back into the live task.
Requires the Enterprise plan.
When a snapshot is captured
A daily scheduler task (issue-daily-snapshots, 24h interval) walks
every issue where updated_at is within the last 48 hours. The 48-hour
grace window means the previous day stays covered even if the tick
slips by up to a day.
For each candidate, the worker builds the canonical field set:
name,description_html,prioritystate_id,start_date,target_date,estimate_pointassignee_ids,label_ids,module_ids,cycle_ids(each sorted lexicographically so the hash is stable across runs)
The worker sha256-hashes the canonical JSON and writes a row into
issue_daily_snapshots if:
- No row already exists for
(issue_id, today)(unique index). - The fresh hash differs from the most recent prior snapshot for the same issue (so a subscribe / unsubscribe or a comment does not accumulate an identical snapshot).
Idempotent: re-running the task on the same day produces zero writes.
Browse and preview
On any task, open the More actions menu (three-dot button in the detail toolbar) and pick Time Machine. The modal lists every stored snapshot for the task, most recent first, each flagged with whether it still differs from the current state.
Selecting a date loads the snapshot payload plus a computed diff against the current issue. The diff is field-by-field: base fields show their before / after values side by side; array fields (assignees, labels, modules, sprints) show a short summary of the set membership; the description shows a compact "differs" note (v1 does not render a rich HTML diff).
Restore
The Restore button applies the snapshot's field values back to the live issue in a single transaction:
name,description_html,priorityare overwritten.state_id,start_date,target_date,estimate_point_idare set (null values in the snapshot clear the live field).- Assignees, labels, modules, and sprints are replaced (delete-then- reinsert) to match the snapshot's set.
The restore surfaces on the audit log as
workspace.issue.time_machine.restored with metadata
{ issue_id, snapshot_date }, and appends an activity row to the
task's history so the change is auditable there too.
Requires member role or above on the project. A restore is not
destructive to the snapshot itself: the row stays in
issue_daily_snapshots, so the same snapshot can be restored again if
needed.
Endpoints
GET /workspaces/{slug}/projects/{projectID}/issues/{issueID}/time-machine/
GET /workspaces/{slug}/projects/{projectID}/issues/{issueID}/time-machine/{YYYY-MM-DD}/
POST /workspaces/{slug}/projects/{projectID}/issues/{issueID}/time-machine/{YYYY-MM-DD}/restore/
All three respond with 402 Payment Required when the workspace is on a plan below Enterprise.
What is not in v1
- Sub-daily granularity. A snapshot is captured at most once per day per issue. High-churn workflows (a spec that changes ten times in a morning) collapse into a single row for that day.
- Field-scoped restore. v1 restores every tracked field or none. A per-field restore ("only reset the assignees") is next.
- Rich description diff. The modal notes that the description differs but does not render an HTML diff view. v1 asks the user to restore and use the description version history for that field.
- Retention pruning. Snapshots accumulate indefinitely. A per- workspace retention policy (auto-purge after N days) is on the roadmap.
Related
- Audit CSV export: every restore
lands as
workspace.issue.time_machine.restored, so an admin can reconstruct who restored what and when. - Agent Dispatch Queue: the two features cover opposite ends of a task's timeline. Dispatch hands the task to a runner going forward; Time Machine puts a task back to any prior day.