gitroll 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SPEC.md CHANGED
@@ -1,146 +1,192 @@
1
- # GitRoll Format, version 1
1
+ # GitRoll format, template version 1
2
2
 
3
- A Roll is an ordinary Git repository. It must stay readable and useful without GitRoll: every file is Markdown, YAML, or an unmodified original attachment.
3
+ A log lives in an ordinary Git repository, in a folder called `.gitroll/`. It must stay readable and useful without GitRoll: every file is Markdown, YAML, or an unmodified original attachment, and the format is small enough to hold in your head.
4
+
5
+ The only thing you must do to log an event is create a Markdown file in `.gitroll/events/`.
4
6
 
5
7
  ## Layout
6
8
 
7
9
  ```
8
- .gitroll/config.yaml required
9
- .gitroll/types/<type>.yaml optional custom event types
10
- entries/YYYY/MM/<id>.md one event per file
11
- projects/<slug>.yaml optional project metadata
12
- attachments/<sha256><.ext> attachment bytes, named by content hash
10
+ .gitroll/config.yaml required: template_version
11
+ .gitroll/README.md optional: how to log, for whoever opens the folder
12
+ .gitroll/events/2026-09-15-ac-serviced.md one event per file
13
+ .gitroll/files/ac-receipt.pdf files kept with events, created when first needed
13
14
  ```
14
15
 
15
- Entries never live inside project folders. An event references projects, so one event can belong to several.
16
+ `.gitroll/` sits at the root of the repository, whether the repository exists only for the log or already holds a project. It is committed like any other source file.
16
17
 
17
- `YYYY/MM` is taken from the event's `created` timestamp and never changes when the event is edited. Readers must not depend on that folder structure: any `.md` file under `entries/` is an event.
18
+ **`.gitroll/` is a namespace, not a privacy boundary.** A log is exactly as visible as the repository it lives in: in a public repository, every event and every attachment in it is public.
18
19
 
19
- ## Dates and time zones
20
+ Anything else in the repository belongs to whoever put it there. GitRoll reads and writes only `.gitroll/`, and commits only the files it wrote.
20
21
 
21
- - **Format.** Timestamps are ISO 8601. Writers record local time with its offset, for example `2026-09-15T14:30:00-07:00`, so both the author's wall-clock time and the exact instant are kept. Readers must accept:
22
- - `2026-09-15T14:30:00-07:00` or `2026-09-15T21:30:00Z`: an exact instant.
23
- - `2026-09-15T14:30` or `2026-09-15T14:30:00`: no offset, so the reader's local time.
24
- - `2026-09-15`: a date typed by hand, meaning noon local time, so it falls on that day in every time zone. Writers expand it to `2026-09-15T12:00:00` when they next save the event.
25
- - Anything else (such as `Sept 15`) is invalid, and `gitroll check` reports it.
26
- - **Ordering** uses the instant, so events logged in different time zones sort correctly.
27
- - **Display and filters** use the viewer's time zone. An event logged at 9:00 in New York shows as 6:00 to someone in Los Angeles, and "this month", `after:` and `before:` use the viewer's local days.
28
- - **Folders** (`entries/YYYY/MM`) use the year and month as written in `created`, the author's local date, and never move.
29
- - **Fields** of kind `date` in custom types hold a date (`2026-09-15`) and are shown as that calendar day, without time zone conversion.
22
+ ### Events
30
23
 
31
- ## `.gitroll/config.yaml`
24
+ Any `.md` file anywhere under `.gitroll/events/` is an event. Subfolders are allowed and mean nothing to GitRoll: they are for people who like to organize.
32
25
 
33
- ```yaml
34
- version: 1
35
- name: My Roll
36
- attachments:
37
- max_mb: 25 # optional per-file limit for new attachments
38
- remove_location: true # optional; remove GPS data from photos (default true)
39
- ai: true # optional; false turns off "Ask your Roll" for everyone
26
+ An event's **identity is its path**. There is no id field, and nothing is required inside the file. Renaming an event is an ordinary `git mv`; Git history follows the rename.
27
+
28
+ ### Files
29
+
30
+ Files kept with an event are ordinary files with readable names, linked from the event's Markdown with ordinary relative links:
31
+
32
+ ```markdown
33
+ [Receipt](../files/ac-receipt.pdf)
34
+
35
+ ![The leak](../files/leak.jpg)
40
36
  ```
41
37
 
42
- `.gitroll/theme.css` (optional) overrides the app's style variables. See docs/TEMPLATES.md.
38
+ There are no content hashes, no manifest, and no list of attachments in the front matter: what an event links to is what it has. A link is resolved relative to the event's own file, and only inside the repository — a link that climbs out of the root (`../../../etc/passwd`) or starts at `/` is not an attachment, and `gitroll check` reports it.
43
39
 
44
- The author name on new events comes from each person's own GitRoll settings or `git config user.name`, never from the shared config.
40
+ Writers must not overwrite a file that is already there: an app storing a second `ac-receipt.pdf` writes `ac-receipt-2.pdf`.
45
41
 
46
- ## Events
42
+ ## The minimum event
47
43
 
48
- An event is a Markdown file with YAML front matter. The body is free Markdown text.
44
+ `.gitroll/events/2026-09-15-ac-serviced.md`:
49
45
 
50
- | Field | Required | Meaning |
51
- | --- | --- | --- |
52
- | `version` | yes | Format version, currently `1` |
53
- | `id` | yes | Globally unique id. Writers use UUIDv7 (time-sortable). Must match the file name. |
54
- | `type` | no | Event type id, default `log`. Lowercase letters, digits and `-`. |
55
- | `created` | yes | ISO 8601 timestamp with offset: when the event was recorded |
56
- | `occurred` | no | When it happened. Defaults to `created`. Same format as `created`; see [Dates and time zones](#dates-and-time-zones). |
57
- | `author` | no | Who logged it |
58
- | `projects` | no | List of project slugs |
59
- | `tags` | no | List of lowercase tags |
60
- | `attachments` | no | List of `{ hash, name, type, size }`, where `hash` is `sha256:<hex>` |
61
- | `amount` | no | `{ value, currency }`, where currency is an ISO 4217 code |
62
- | `data` | no | Type-specific structured fields (a mapping) |
63
- | `source` | no | `{ adapter, id, url? }` for events created by an import. `adapter` + `id` is unique within a Roll. |
46
+ ```markdown
47
+ # AC serviced
64
48
 
65
- Unknown front matter keys must be preserved by writers. Unknown `data` keys must be preserved too.
49
+ Replaced the capacitor. Paid $325.
50
+ One-year warranty on the repair.
66
51
 
67
- ### Edits and deletion
52
+ [Receipt](../files/ac-receipt.pdf)
53
+ ```
68
54
 
69
- Edits rewrite the file in place (same path, same `id`), and each edit is its own commit. Deleting an event removes its file in a commit. Git history is the audit trail: previous versions are never rewritten or force-pushed away by GitRoll.
55
+ That is a complete, valid event. No front matter, no id, no author, no timestamps.
70
56
 
71
- ## Event types
57
+ - **Title**: the first heading; failing that, the first line of text; failing that, the file name.
58
+ - **Date**: the `YYYY-MM-DD` at the start of the file name.
59
+ - **Tags**: any `#hashtag` in the text (not in code spans or fences).
60
+ - **Attachments**: the files it links to.
72
61
 
73
- A type is a template: a label, an icon, and optional fields stored under `data`. It never changes how an event is stored. An event whose type isn't known is still a valid event and renders as a general log.
62
+ ## Optional metadata
74
63
 
75
- Built-in starter types: `log`, `expense`, `decision`, `issue`, `milestone`.
64
+ Front matter is optional. When it is there, it is YAML, and it may hold anything; these keys have meaning:
76
65
 
77
- The starter set is deliberately small. A type id that no definition covers is still a valid event and renders as a general log, so a Roll may use any id it likes; anything more specific belongs in `.gitroll/types/<id>.yaml`.
66
+ | Key | Meaning |
67
+ | --- | --- |
68
+ | `date` | When it happened. Overrides the date in the file name. |
69
+ | `projects` | List of project slugs (`projects: [house]`). Nothing declares a project: naming it is all there is to it. |
70
+ | `tags` | List of tags. Merged with any `#hashtags` in the text. |
71
+ | `amount` | A number. What totals add up. |
72
+ | `currency` | ISO 4217 code for `amount`, default `USD`. |
73
+ | `title` | Overrides the heading as the event's title. Rarely needed. |
74
+ | `source` | Where the event came from. An importer writes `{ adapter, id, url? }`, and `adapter` + `id` is unique within a log, so importing the same thing twice creates one event. An event about code writes `{ repo, branch, commit }`; see below. |
78
75
 
79
- A custom type lives in the Roll, so its data never depends on a plugin being installed:
76
+ ```markdown
77
+ ---
78
+ date: 2026-09-15
79
+ projects: [house]
80
+ tags: [maintenance, warranty]
81
+ amount: 325
82
+ currency: USD
83
+ ---
80
84
 
81
- ```yaml
82
- # .gitroll/types/vehicle-service.yaml
83
- label: Vehicle service
84
- icon: 🚗
85
- amount: expected # none | optional | expected (whether to show the amount field)
86
- fields:
87
- - key: odometer # lowercase letters, digits, underscore
88
- label: Odometer
89
- kind: number # text | longtext | number | date | select | boolean | url
90
- - key: shop
91
- label: Shop
92
- kind: text
85
+ # AC serviced
86
+
87
+ Replaced the capacitor.
88
+
89
+ [Receipt](../files/ac-receipt.pdf)
93
90
  ```
94
91
 
95
- Optional `defaults` prefill the form when someone picks the type. They're plain values; GitRoll never runs anything from a Roll:
92
+ Every other key is yours. **Writers must preserve keys they don't know**, along with the comments and formatting of the YAML they didn't change.
96
93
 
97
- ```yaml
98
- defaults:
99
- text: Changed the oil.
100
- tags: [car]
101
- projects: [truck]
102
- amount: { value: 60, currency: USD }
103
- data: { shop: Jiffy Lube }
94
+ An amount written only in prose ("Paid $325") stays prose: GitRoll never extracts it, and no total counts it. If you want it counted, put it in `amount`.
95
+
96
+ ## Code references
97
+
98
+ An event may say which repository, branch and commit it is about:
99
+
100
+ ```markdown
101
+ ---
102
+ source:
103
+ repo: acme/app
104
+ branch: fix/checkout
105
+ commit: 9f1c2d3e4a5b6c7d8e9f0a1b2c3d4e5f60718293
106
+ ---
107
+
108
+ # Checkout times out
109
+
110
+ Caused by the index dropped in 9f1c2d3, fixed in #412. Related: other/lib#88.
104
111
  ```
105
112
 
106
- A custom file with the same id as a built-in type overrides it.
113
+ `repo` is `owner/repo` or any address Git understands (`git@github.com:acme/app.git`, `https://github.com/acme/app`). **This is the source repository where the work happened.** It is not the repository the log lives in, and it is not the branch the log is on, even when they happen to be the same.
114
+
115
+ References in the text are ordinary text, and readers recognize them:
116
+
117
+ | Written | Means |
118
+ | --- | --- |
119
+ | `#412` | Pull request or issue 412 **in the event's own `source.repo`**. With no `source.repo`, it is shown as text and never linked to a guess. |
120
+ | `owner/repo#412` | 412 in that repository |
121
+ | `9f1c2d3` … `9f1c2d3e4a5b…` | A commit, 7 to 40 hex characters |
122
+ | `https://github.com/owner/repo/pull/412` | Whatever the URL says |
107
123
 
108
- ## Attachments
124
+ Code spans, fenced code and HTML comments are not prose, so a `#412` inside one is an example, not a reference.
109
125
 
110
- Attachments are content-addressed. An event refers to an attachment only by `hash`; the file name in the event is the original, human-readable name.
126
+ ## Links between events
111
127
 
112
- In format version 1 the bytes are stored in the repository at `attachments/<sha256hex><.ext>`. Identical files are stored once. Validators check that each file's SHA-256 matches its name.
128
+ An event links to another with an ordinary relative Markdown link:
113
129
 
114
- GitRoll removes GPS location data from JPEG photos before hashing and storing them (unless `remove_location` is false), so a stored photo may differ from the camera original only in that metadata.
130
+ ```markdown
131
+ Follows [the incident on the 14th](2026-09-14-checkout-timeouts.md).
132
+ ```
133
+
134
+ That link is the relationship, and the backlink is the same link read the other way round — worked out when it is needed, never stored. Nothing declares a relationship, and the link still resolves on GitHub and in a text editor.
115
135
 
116
- Rolls must not contain symbolic links. Readers must not follow them, and validators report them.
136
+ ## Dates
117
137
 
118
- Because events reference only hashes, other storage (such as Git LFS or object storage) can be added later without changing existing events. A future store would be declared in `.gitroll/config.yaml`; readers resolve a hash by looking in the repository first.
138
+ - A date is `2026-09-15`, or a full ISO 8601 timestamp when the time of day matters (`2026-09-15T14:30:00-07:00`).
139
+ - The date comes from the front matter if it has one, else from the `YYYY-MM-DD` prefix of the file name.
140
+ - **If neither supplies one, the event is undated.** That is a normal state, not an error: it shows as undated and is left out of date searches.
141
+ - Filters and grouping compare **calendar days as written**, so an event stays on the day its author put it on wherever the log is opened.
142
+ - Anything a reader can't parse as a date (`Sept 15`, `15/09/2026`) is reported by `gitroll check` rather than guessed at.
119
143
 
120
- ## Projects
144
+ ## `.gitroll/config.yaml`
121
145
 
122
146
  ```yaml
123
- # projects/bathroom-remodel.yaml
124
- name: Bathroom Remodel
125
- description: Main bathroom, 2026
126
- created: 2026-09-01T10:00:00-05:00
147
+ template_version: 1 # required: which template revision this repository follows
148
+ name: My Roll # optional: the name shown in GitRoll
149
+ attachments:
150
+ max_mb: 25 # optional per-file limit for new attachments
151
+ remove_location: true # optional; remove GPS data from photos (default true)
152
+ ai: true # optional; false turns off "Ask your Roll" for everyone
127
153
  ```
128
154
 
129
- An event may reference a slug that has no project file; readers show the slug as the name.
155
+ `.gitroll/theme.css` (optional) overrides the app's style variables. See docs/TEMPLATES.md.
156
+
157
+ ### Template versions
158
+
159
+ `template_version` says which revision of the template a repository follows. It describes the repository, not the app, so a new GitRoll release never changes it.
160
+
161
+ - **Version 1** is this document.
162
+ - It is **incremented only for published changes to the template's structure or conventions.** New *optional* keys (`source`, and anything else a writer preserves rather than requires) don't change it: a reader of version 1 still reads every file correctly, and bumping the version would stop older versions of GitRoll writing to a repository they understand perfectly well.
163
+ - Readers read it when they open a repository, and **preserve it** during ordinary logging and editing.
164
+ - **A missing marker means the version is unknown, not current.** Tools say so, explain how to record one (`gitroll template --set 1`), and must not write one on their own: a version an app only guessed at is not a fact about the repository.
165
+ - **A version newer than the reader understands blocks writes.** Nothing is changed, and the reader says the app needs updating.
166
+ - **Future upgrades are explicit and reviewable**, and the marker is updated only after the upgrade succeeds.
167
+
168
+ There is no per-event version field. An event is Markdown; it does not need one.
169
+
170
+ ## Identity, history and simultaneous edits
171
+
172
+ - **Identity** is the file's path. It is readable, typeable, and needs nothing generated.
173
+ - **Renames and moves** are ordinary Git renames. A writer that moves an event rewrites the relative links in its body so they still resolve, and Git history follows the file.
174
+ - **Filename collisions**: a writer appends `-2`, `-3`, … before the extension. Two events logged the same day about the same thing become `2026-09-15-ac-serviced.md` and `2026-09-15-ac-serviced-2.md`. Nothing is overwritten, ever.
175
+ - **Edits** rewrite the file in place, each in its own commit. Git history is the audit trail: previous versions are never rewritten or force-pushed away by GitRoll.
176
+ - **Simultaneous edits** are merged as Markdown, line by line, the way Git merges any text file. That succeeds whenever two people touched different parts of the file. When the same lines changed on both sides, this device's version is kept as it is and the other version is appended in a note tagged `#conflict`, so nothing is lost and the conflict is easy to find.
177
+ - **Authors** come from Git: `git log` and `git blame` know who wrote what. Events carry no author field, so nobody can sign as someone else by editing a file.
130
178
 
131
- ## Validation
179
+ ## Reading a log
132
180
 
133
- `gitroll check` reports:
181
+ A reader:
134
182
 
135
- - a missing or invalid `.gitroll/config.yaml`
136
- - event files that don't parse, lack required fields, or whose file name doesn't match their `id`
137
- - duplicate ids or duplicate `source` identities
138
- - attachment references with no matching file, and attachment files whose content doesn't match their hash
139
- - invalid project or type definition files
140
- - `data` values that don't match a known type's field kinds
183
+ 1. Looks for `.gitroll/config.yaml` at the root of the Git repository (searching upwards from the current folder, so it works from a subfolder).
184
+ 2. Checks `template_version` before writing anything.
185
+ 3. Reads every `*.md` under `.gitroll/events/`, recursively.
186
+ 4. Resolves each event's links relative to the event's own path.
141
187
 
142
- Validation runs locally. A Roll requires no CI.
188
+ Files it cannot parse are reported, not skipped silently, and never stop the rest of the log from loading.
143
189
 
144
- ## Reserved for later versions
190
+ ## What is deliberately absent
145
191
 
146
- These names are reserved and currently ignored, so they're preserved like any unknown key: `pinned`, `related`, `resolves`, `entities`, `status`, `encryption`.
192
+ No ids, no per-event version, no required timestamps, no author fields, no attachment manifests, no content-hash file names, no project definition files, no event type definitions, no mandatory folder structure. Every one of those was something a person would have had to produce before they could write down what happened.