This file provides guidance to AI agents when working with code in this repository.
Time Machine Inspector is a macOS desktop app built with Tauri v1. It inspects Apple Time Machine backups and shows what changed between snapshots. The frontend is Svelte 4 + TypeScript; the backend is Rust. macOS Full Disk Access is required at runtime.
deno task dev # Start dev mode (Tauri + Vite)
deno task dev:web # Frontend only (no Tauri, browser)
deno task build # Production build
deno task lint # svelte-check + eslint + prettier check
deno task format # eslint --fix + prettier --write
deno task test # cargo test (Rust only)Run a single Rust test:
cargo test --manifest-path ./src-tauri/Cargo.toml <test_name>Rust #[command] functions in src-tauri/src/ are exposed to the frontend via Tauri's invoke_handler. In dev mode, main.rs runs tauri_specta::ts::export(...) which regenerates bindings.ts at the project root — this file is the auto-generated TypeScript type layer for all IPC commands.
src/lib/commands.ts wraps the generated bindings in a Proxy that automatically calls errorPopup on any IPC error, so all frontend IPC calls go through commands.<methodName>(...).
| File | Responsibility |
|---|---|
main.rs |
Tauri setup, menu, error_popup command, specta export |
cmd.rs |
Core IPC commands: load_backup_list, get_backup, backups_info; shared state (DestinationsState, LoadedBackups) |
listbackups.rs |
Calls tmutil to enumerate destinations and backups |
destinationinfo.rs |
destinationinfo command — reads Time Machine plist for destination metadata |
compare.rs |
Diffs two backup snapshots (the heavy computation) |
dir_map.rs |
Tree structure holding per-directory size deltas |
Shared mutable state is stored in Tauri-managed Mutex structs (DestinationsState, LoadedBackups) and accessed via State<'_> in async commands.
src/page/page.ts holds Svelte stores for the currently viewed backup (page), loaded backup infos (backupInfos), the drill-down path (selectedPath), and the rendered directory map (pageMap). The backups store triggers a reload of backupInfos on every set.
bindings.ts is only regenerated when running deno task dev (debug builds). After adding or changing a #[command] signature in Rust, run deno task dev once to refresh the file before touching frontend code.
- Update
CHANGELOG.md - Bump version in
src-tauri/Cargo.toml - Run
cargo check --manifest-path src-tauri/Cargo.tomlto syncCargo.lock - Tag
v#.#.#— GitHub Actions builds and publishes the release
<CRITICAL_INSTRUCTION>
This project uses Backlog.md MCP for all task and project management.
CRITICAL RESOURCE: Read backlog://workflow/overview to understand when and how to use Backlog for this project.
- First time working here? Read the overview resource IMMEDIATELY to learn the workflow
- Already familiar? You should have the overview cached ("## Backlog.md Overview (MCP)")
- When to read it: BEFORE creating tasks, or when you're unsure whether to track work
| Command | Purpose |
|---|---|
task_create |
Create a new task (status defaults to "To Do") |
task_edit |
Edit metadata, check ACs, update notes, change status |
task_view |
View full task details |
task_search |
Find tasks by keyword |
task_list |
List tasks with optional filters |
task_complete |
Moves task to backlog/completed/ — only use for cleanup, not for marking done |
- Create:
task_create— new task inbacklog/tasks/ - Start:
task_edit(status: "In Progress")— mark as active - Done:
task_edit(status: "Done")— mark finished, stays inbacklog/tasks/(visible on kanban) - Archive:
task_complete— moves tobacklog/completed/(use only when explicitly cleaning up)
IMPORTANT: Use task_edit(status: "Done") to mark tasks as done. Do NOT use task_complete unless the user explicitly asks to archive/clean up — it removes the task from the kanban.
Backlog.md does NOT enforce ID uniqueness on the filesystem. If two task files declare the same id: in their frontmatter, task_view/task_search silently resolve to whichever has the newer updated_date, hiding the other from the kanban and MCP lookups. This is how TASK-341 ended up with two owners (iOS-sync vs. Plex umbrella) in commit 89ff249.
Before creating any task, ALWAYS:
- Run
task_list(orrg "^id: TASK-" backlog/tasks/ backlog/archive/tasks/ backlog/completed/) to find the highest existing ID. - Let
task_createauto-assign the next ID — never setid:manually in frontmatter or filenames. - For subtasks, pass
parentTaskIdtotask_createso Backlog.md generates the hierarchical ID (e.g.,TASK-342.1) for you.
Detecting a collision:
rg -N "^id: " backlog/tasks/ backlog/archive/tasks/ backlog/completed/ \
| awk -F': ' '{print $NF}' | sort | uniq -dResolving a collision: the MCP has no rename/change-id operation. Renumbering requires: (1) git mv the file to a new filename with the new ID; (2) edit the frontmatter id: field; (3) edit parent_task_id: if the task is a subtask whose parent was also renumbered (this field is NOT settable via task_edit); (4) edit dependencies: arrays in other tasks that reference the old ID; (5) verify with rg "^id: TASK-OLD$" backlog/tasks/ returning zero results.
check_active_branches and remote_operations are both disabled in backlog/config.yml. With worktrees, these features scan other branches and pull in tasks that were already completed/archived on main but still exist in backlog/tasks/ on older branches — bloating the kanban with ghost tasks. Do not re-enable without accounting for worktree branch divergence.
The finalSummary, description, implementationNotes, and planSet MCP parameters are single-line JSON strings. Literal \n sequences are NOT interpreted as newlines — they render as the two characters \ n in the markdown file. To write multiline content:
- Use
task_editwith the field for short single-paragraph content - For multiline content, edit the task markdown file directly with the file editing tool (the file path is shown in
task_viewoutput)
task_edit parameter names are different from task_create:
| Operation | task_create param |
task_edit param |
|---|---|---|
| Task ID | — (auto-assigned) | id (NOT taskId) |
| Title | title |
title |
| Description | description |
description |
| Acceptance Criteria | acceptanceCriteria |
acceptanceCriteriaSet (replaces all), acceptanceCriteriaAdd, acceptanceCriteriaRemove, acceptanceCriteriaCheck, acceptanceCriteriaUncheck |
| Dependencies | dependencies |
dependencies |
| Parent Task | parentTaskId |
not supported — edit parent_task_id: in the markdown frontmatter directly |
| Status | status |
status |
| Notes | — | notesAppend, notesSet, notesClear |
| Plan | — | planAppend, planSet, planClear |
| Final Summary | — | finalSummary, finalSummaryAppend |
| References | references |
references, addReferences, removeReferences |
| Documentation | documentation |
documentation, addDocumentation, removeDocumentation |
Common error: Using taskId instead of id, or acceptanceCriteria instead of acceptanceCriteriaSet in task_edit calls. Always use id and the acceptanceCriteria* variant names, and task_edit cannot re-parent — edit the file's parent_task_id: frontmatter directly when a parent ID changes.
The overview resource contains additional detail on decision frameworks, search-first workflow, and guides for task creation, execution, and completion.
</CRITICAL_INSTRUCTION>