Commands#
Command |
Purpose |
|---|---|
|
Add an issue; |
|
Rows of issues; one issue’s metadata and file range |
|
Change state, priority, or blockers; take an issue; move it |
|
Add a dated logbook entry; state and claim untouched |
|
Every live claim, oldest first: who holds what, for how long |
|
Turn an inbox file’s unstamped
|
|
The identity a claim would record |
|
Query the corpus; bounded dependency and related traversal |
|
Deadlines and scheduled starts inside a horizon, overdue first |
|
JSONL, one object per issue |
|
Relationships |
|
Markdown roadmap; read-only Org or markdown projection |
|
Corpus digest; whether a mirror is still current |
|
Validation |
|
Change stream for pollers |
|
Layout introspection |
|
Shell completion scripts and the manual page |
States and priorities#
States are TODO, STARTED, BLOCKED, DONE, and CANCELLED. An issue is
ready when it is TODO or STARTED and no id in its :BLOCKED_BY: is
still open. Priorities are the Org cookies [#A], [#B], and [#C],
defaulting to C.
Properties#
:ID: is required and generated. :CREATED: is set on create. :PARENT:,
:BLOCKED_BY:, :VISSUE_TAGS:, :TYPE:, :CLAIMED_BY:, :CLAIMED_AT:,
and :DISCOVERED_FROM: are read by the query verbs. Any other property is
preserved untouched, in the order it appears on disk.
:BLOCKED_BY: accepts commas, whitespace, or both. :PARENT: may name
another issue or any Org heading with an :ID: under the tracker prefix, so a
design document can head a work hierarchy. Parent chains must terminate;
check reports a loop.
What Org owns#
Three fields live where Org keeps them rather than in the drawer, because Org reads them from there and nowhere else.
Field |
Written as |
What it buys |
|---|---|---|
Deadline, scheduled, closed |
The planning line under the heading |
|
Tags Org can hold |
The heading’s own
|
Org tag search and
|
Identity |
|
|
Project |
|
The agenda labels rows by project |
A tag Org will not accept in a heading, needs-review say, stays in
:VISSUE_TAGS: and still answers search and related. create --tags
splits a list between the two on Org’s own tag character class.
Both shapes are read, so a tracker written before this and one edited in Emacs
parse the same; the next rewrite settles on the Org shape. :TAGS:,
:DEADLINE:, and :SCHEDULED: in a drawer are names Org reserves, which
org-lint reports, so they are migrated rather than kept.
JSONL export schema#
Each line is an object with id, project, title, state, priority,
properties, org_tags, tags, logbook, body, line_start, and
line_end.
org_tags is the heading’s Org tag run; tags is the union with
:VISSUE_TAGS:, and is the field to filter on. Logbook entries carry
timestamp, from, to, and note. CLOCK and other opaque drawer lines
also carry raw, the verbatim Org line, so time recorded by another tool
survives a rewrite.
Configuration#
<root>/vissue.toml, then <root>/<prefix>/issues.config.toml, each
overriding the compiled defaults key by key.
Key |
Default |
Meaning |
|---|---|---|
|
|
Directory under the root holding projects |
|
unset |
Identity a claim records |
|
|
Cookie applied when
|
|
|
Base36 characters in a generated id suffix |
|
|
When |
A short id_length is a small space: 2 characters is 1296 ids, and create
reports an exhausted space rather than failing obscurely.
Environment#
Variable |
Meaning |
|---|---|
|
Tracker root; |
|
Directory under the root holding one directory per project |
|
Identity a claim records, ahead of the config file |
|
|
Exit statuses#
Status |
Meaning |
|---|---|
0 |
Success, including a reader that closed the pipe |
1 |
Failure, or a stale |
2 |
|
MCP server#
vissue-mcp speaks the Model Context Protocol over stdio and calls the
library in process. It resolves its root from VISSUE_ROOT and
VISSUE_PREFIX. Tools mirror the CLI verbs: vissue_list, vissue_ready,
vissue_show, vissue_create, vissue_update, vissue_claim,
vissue_count, vissue_search, vissue_children, vissue_backlinks,
vissue_related, vissue_waiting_on, vissue_body_excerpt, vissue_tree,
vissue_graph, vissue_ancestors, vissue_impact, vissue_cycles,
vissue_refile, vissue_wait, vissue_whoami, vissue_roadmap,
vissue_export, vissue_check, vissue_hygiene, vissue_mirror,
vissue_projects, and vissue_identity.
The server grants write access to every project under its root. Point it at a tracker root you are willing to let the caller edit, not at a home directory.
Concurrency#
Every read-modify-write cycle takes a process-local mutex and an advisory lock
on issues.org.lock, then writes through a temporary that is flushed to the
device, uniquely named, and renamed into place. Concurrent creates from
several processes therefore neither lose headings nor collide on the
temporary, and a crash mid-write leaves the previous file rather than a
truncated one. Any other tool writing the same file is expected to take that
lock too.
The lock covers one project file. Adding a blocker reads the whole corpus for
the acyclicity check inside that lock, so it sees every write that has landed;
two blockers added at the same moment in different project files can still
close a cycle between them. check and cycles report one if it happens.