Git-native issue tracker
OCaml 81%
Perl 15%
Python 3%
Raku <1%
<1%
Shell <1%
Dune <1%

README.md

tracker #

tracker is the pure state model for a Git-native issue tracker. A row carries its acceptance checks and, while owned, the holder and instant of its claim. The durable store is a dedicated tracker Git repository, independent of the code repositories it describes. Creating a code branch does not fork issue state or claims; only the designated tracker store ref accepts them. Tracker.Core.claim and Tracker.Core.release return a new row or a refusal; the caller persists the result only after checking that the store still has the row it read. No claim expires with time.

A claim's holder is a name the writer gives; tracker keeps no roster of writers and no rule about who may release whose claim. Who wrote a change is Git's answer, the commit's author, and who may write the store is whoever may push to its remote. Tracker.Core.release ~holder removes a claim only if holder still holds it, a compare-and-swap on the holder.

The core is independent of Git and IO. Row.v creates an open row with an explicit filing instant, priority, triage state, acceptance checks, labels and typed edges. A caller that needs to inspect a claim can use Row.claim, which returns the holder and timestamp when one exists. Row.claim_holder is for a row known to be claimed and raises on an unclaimed row.

Schema.snapshot checks row kinds, statuses, label families, check kinds and unique row IDs before admitting a set of rows. Schema.rewrite validates every row against a replacement vocabulary while preserving row identity. Row.merge ~ancestor left right combines independent label, check and edge changes with the vendored mrdt three-way set merge. Competing scalar changes are conflicts; a claim or status change must go through the authority.

Row_json.of_string ~schema ~id reads a stored row.json against the schema from its Git tree. The id comes from the row directory. Row_json.to_string ~schema writes validated rows with a fixed member order and final newline, so a Git diff shows the field that changed. Unknown fields are refused.

Schema_toml.of_string reads the store's schema.toml; the writer is Schema_toml.to_string. Its arrays list the admitted statuses and check kinds, and kinds the admitted row kinds; without it a store admits Beads' built-in types, bug, feature, task, epic and chore. Each [[label_families]] entry gives a name and values; ["*"] admits any value in that family. Each [[fields]] entry declares a structured field of one kind: its kind, name and type, one of text, integer (with optional min and max), texts or records, whose own fields are declared inline, one level deep; any field may be optional. A row's fields live in its row.json under "fields", and are checked against its kind's declarations: a missing, unknown, mistyped or out-of-bounds field is refused, named by its path.

An optional [rules] table states what a write must not leave a row breaking: title_limit and heading_markers for the title, leads_at_most for the priorities that need a reason and a label from queues, [[rules.requires]] for a label that needs a label of another family, and decided and waits for a decision still to be taken. Schema.admit judges a row against the row it replaces, so a write is refused only for a rule it introduces; every store write passes it before its ref moves. Schema.owed lists what a stored row already breaks, and Store_tree.audit names every row of a commit that its schema does not admit, as tk check prints them.

Schema_candidate.v validates a schema and all its rows together. Schema_candidate.rewrite applies replacements to both in memory and returns a candidate only if every result is valid and each row keeps its id. The store writes that candidate as one Git tree.

Store_tree.load ~repo ~commit reads schema.toml and the row files from that commit's tree with nox-git-eio. It checks the SHA-256 shard of each row id and returns the source tree id with the validated candidate, so an index can be tied to the exact tree it describes.

Distributed coordination defines the shared machine-local authority, cross-machine convergence and ref decision model.

The package's current test gate is:

dune build @ocaml-tracker/runtest