Skip to content

Local issues

The local tracker keeps each issue in a Markdown file in your repository, in .itervox/issues/. It needs no Linear or GitHub account, no API key and no labels, so it suits solo projects, demos and trying Itervox out. Files are the source of truth: edit one in your editor and the board follows on the next poll.

Terminal window
itervox init --tracker local

or let itervox quickstart choose it: quickstart picks the local tracker when LINEAR_API_KEY is not set and origin is not on github.com (pass --tracker local to choose it anyway).

Both write a WORKFLOW.md with:

tracker:
kind: local
# project_slug: ITX # Optional — identifier prefix for new issues (default ITX).
active_states: ["Todo", "In Progress"]
terminal_states: ["Done", "Cancelled"]
working_state: "In Progress"
completion_state: "In Review"
backlog_states: ["Backlog"]

and an example issue, .itervox/issues/ITX-1.md, in Backlog so nothing runs until you say so. No .itervox/.env credentials are needed.

To try the board without touching a project, itervox demo --tracker local runs the demo over issue files in its scratch directory.

The file name, without .md, is the issue’s identifier (ITX-12.md is ITX-12). Identifiers are a prefix, a dash and a number.

---
title: Add a --json flag to `report`
state: Todo
priority: 2
labels: [cli]
blocked_by: [ITX-3]
branch: itervox/itx-4
created: 2026-10-09T12:00:00Z
updated: 2026-10-09T12:30:00Z
---
Print the report as JSON when `--json` is passed. Keep the table output
as the default.
## Comments
### 2026-10-09T12:05:00Z — alex
The schema is in docs/report.md.
Front matterRequiredMeaning
titleyesThe issue title.
stateyesAny state name. It is matched against active_states, terminal_states and backlog_states ignoring case.
prioritynoA number; lower is more urgent, as with Linear (1 urgent … 4 low).
labelsnoA list. Read in lower case, like the other trackers.
blocked_bynoIdentifiers of issues that block this one. A blocker that is not terminal keeps this issue from being dispatched; a blocker with no file also keeps it blocked.
branchnoThe issue’s branch. Itervox records it when an agent starts; stacked work builds on a blocker’s branch.
created, updatednoRFC 3339 times. Itervox sets updated on every write.

Other keys are kept when Itervox rewrites the file, but the front matter is rewritten in a standard layout: YAML comments in it are dropped and spacing may change. Put notes in the description instead.

Everything after the front matter is the description, up to the last ## Comments heading that has a comment under it. Each comment starts with ### <RFC 3339 time> — <author>; text between the heading and the first comment is kept. A ## Comments heading with no comment after it is part of the description. Code blocks are not special, so a fence never hides the comments. When text Itervox writes (a comment, or a new issue’s description) contains a line that would read as that heading or a comment header, the line is written with a leading \ (Markdown shows it unchanged) and read back without it, so no text can rewrite the file’s structure. Two consequences: a backslash you type before such a line yourself is removed the next time Itervox writes the file, and if a description quotes this format (a ## Comments line followed by a comment header) and you then delete every comment by hand, the quoted example is read as the comments. Comments Itervox writes (the pull request link, the session summary, input-required questions) are signed Itervox.

  • By hand. Create ITX-2.md, change state: Backlog to state: Todo, add a comment: the change appears on the next poll (polling.interval_ms), without a restart. Itervox re-reads the files whose size or modification time changed, and any file changed within two seconds of its last read (for filesystems with coarse timestamps). Before writing a file it always reads it again, so a change is applied to what is on disk.
  • From the dashboard. Moving a card or posting a comment writes the file.
  • By agents. The agent actions that create issues, comment and move state work the same as with Linear or GitHub. A new issue takes the next free number for the prefix.

Itervox writes a file atomically (a temporary file, then a rename), so an editor never sees half a file.

A missing title or state, front matter that is not closed, a priority that is not a number or a time that is not RFC 3339 is reported, never fatal:

  • the daemon logs a warning once per change, and keeps using the last version it could read. A file that does not parse when the daemon starts, or a new one, is left out until it is fixed: the board and dispatch do not see that issue;
  • Itervox will not write to the file until it parses again, so your edit is never overwritten;
  • itervox doctor lists it as a warning.

Issue files are meant to be committed with the code: itervox init adds !.itervox/issues/ and !.itervox/issues/** to a root .gitignore that ignores .itervox/. To keep them private, add this line after those:

.itervox/issues/

Runtime files under .itervox/ (.env, HEARTBEAT.md, logs, queue files) stay ignored either way.

  • There is no sync with Linear or GitHub; that is planned with the local store design.
  • One daemon per issues directory: two daemons writing the same files can overwrite each other’s change.
  • Comment commands (/itervox run) are GitHub only.