tackline

Where data lives

Everything is in a .tackline folder in the repository root, as readable JSON:

  • .tackline
    • state.jsonthe active session, last view and last open file
    • sessions
      • search-speedup.jsonone file per session
      • docs-pass.json
  • Saved as you go. Every change writes its file right away; there’s no save key. Writes go to a temporary file that then replaces the old one, so a crash never leaves half a file.
  • File names come from the session name. Two names that give the same file name get -2, -3, ….
  • Not in git. On first run tackline offers to add .tackline/ to .gitignore. Sessions are personal working notes; commit them only if you mean to share them.

A session file #

{
  "version": 1,
  "id": "01JBX3K9Q8F7Z2M4N6P0R5T8VW",
  "name": "Search speedup",
  "created_at": "2026-10-25T13:20:00Z",
  "notes": [
    {
      "id": "01JBX3M2W4Q8E6R1T7Y3V5K9P0",
      "file": "src/matcher.rs",
      "span": { "start_line": 3, "end_line": 7, "start_col": null, "end_col": null },
      "anchor": {
        "selected": "    for item in items {\n…\n    }",
        "before": "pub fn matches(query: &str, items: &[String]) -> Vec<String> {\n    let mut out = Vec::new();",
        "after": "    out\n}"
      },
      "text": "replace the loop with an iterator chain",
      "created_at": "2026-10-25T13:21:04Z"
    }
  ]
}
  • notes is in prompt order.
  • span lines are 1-based and inclusive; start_col / end_col are set for character selections.
  • anchor is how a note finds its code again after edits: the selected text and up to two lines before and after it.
  • version is there for future changes to the format.

Whether a note is stale isn’t stored: it’s worked out from the files each time.