Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

Blame · docs/issues.md

Line attribution on main · 189 line(s)

520470e1
Keenan Nemetz
16d ago
1 # Issues
2
3 Your issues belong to the repository, not to a vendor. They clone with the code,
4 keep working when a hosting service has an outage, and stay readable in any text
5 editor.
6
7 An issue is a Markdown file stored on a special branch called `vole`. Every clone
8 of the repository carries the issues and their history, so there is no separate
9 issue database to back up.
10
11 ## Where issues live
12
13 ```text
14 issues/<ulid>/issue.md # the issue
15 issues/<ulid>/comments/<ulid>.md # a comment
16 ```
17
18 Here is a complete issue:
19
20 ```markdown
21 ---
22 title: "Nothing renders on the docs page"
23 state: open
24 author: you
25 created: 2026-10-22T21:30:00Z
26 labels:
27 - bug
28 ---
29 Steps to reproduce...
30 ```
31
32 The top section, between the `---` lines, is YAML metadata. The rest is the
33 Markdown body. Titles and other free text are always quoted, so characters like
34 `#` or a leading `-` cannot change the meaning of the file.
35
36 An issue id is a 26-character ULID. It uses uppercase letters and digits, but not
37 `I`, `L`, `O`, or `U`. A UUID will not work.
38
e05f1c48
Keenan Nemetz
13d ago
39 ## Numbers
40
41 Nobody types 26 characters, so every issue and change request also has a small
42 number: `#1`, `#42`. Issues and change requests share one sequence, oldest first,
43 the way one forge counts both in a single run.
44
45 The number is **derived, not stored**. It is the position of the commit that
46 created the entity in the metadata branch's history. Nothing is added to the file,
47 no counter is kept, and there is nothing to migrate: an existing repository gets
48 its numbers the first time anyone asks. Two clones of the same history produce the
49 same numbers, and `vole admin index rebuild` reproduces them from git.
50
51 The ULID is still the identity — it is the path, the front matter's neighbour in
52 `closes:`, the thing in the commit messages — so a number is a convenience, not a
53 reference you should quote in a script. The one way to make one wrong is to rewrite
54 the branch history: an admin redaction force-push renumbers everything after the
55 commit it rewrote.
56
57 Every command that takes an id takes a number instead, with or without the `#`:
58
59 ```sh
60 vole issue show 42
61 vole issue close '#42'
62 vole change show 1
63 ```
64
520470e1
Keenan Nemetz
16d ago
65 ## Writing an issue without the CLI
66
67 ```sh
68 git switch --orphan vole
69 ID=01M5JR2JK29KKMAA1T9MDNTPBP
70 mkdir -p issues/$ID
71 cat > issues/$ID/issue.md <<'MD'
72 ---
73 title: "Nothing renders on the docs page"
74 state: open
75 author: you
76 created: 2026-10-22T21:30:00Z
77 labels:
78 - bug
79 ---
80 Steps to reproduce...
81 MD
82 git add -A
83 git commit -m "issue: docs page blank"
84 git push origin vole
85 ```
86
7e0b5950
Keenan Nemetz
6d ago
87 Vole checks the file when you push. The `author` field must be the account you push
88 as unless you hold `maintain`, which is the one place the browser is stricter than a
89 push: a contributor writes as itself. If someone else pushed first, the CLI puts your
90 change on top of theirs and tries again.
520470e1
Keenan Nemetz
16d ago
91
6c84d387
Keenan Nemetz
15d ago
92 ## From the browser
93
ab326d3a
Keenan Nemetz
14d ago
94 When browser sign-in is enabled (see [Accounts and access](accounts-and-access.md#browser-sign-in)),
6c84d387
Keenan Nemetz
15d ago
95 a signed-in contributor or maintainer can open an issue or comment from the
96 repository's issue page. The author is the account whose passkey opened the
97 session; the form cannot choose a different name. The change is written with the
7e0b5950
Keenan Nemetz
6d ago
98 same metadata writer the CLI uses, so it is the same file on the same branch. A
99 contributor can use this form or the CLI; pre-receive asks the same capabilities the
100 form does, so neither offers more than the other.
6c84d387
Keenan Nemetz
15d ago
101
802e0e52
Keenan Nemetz
4d ago
102 The issue's author or a maintainer can correct its title with the pencil beside
103 the heading, or its description from the card's menu. Each opens its own field in
104 place, so saving does not leave the page or replace the discussion. The discussion,
105 labels, and assignees are left alone, and the edit is an ordinary metadata commit
106 like the one the CLI writes.
a4e7a99a
Keenan Nemetz
5d ago
107
520470e1
Keenan Nemetz
16d ago
108 ## Using the CLI
109
110 ```sh
111 vole issue new --title "Nothing renders on the docs page" -m "Steps..." -l bug -a wilbur
112 vole issue comment -m "Also affects search" 01M5JR2JK29KKMAA1T9MDNTPBP
113 vole issue edit-comment 01M5JR2JK29KKMAA1T9MDNTPBP 01M5N1PRC4GJPZNEEG8PR8J4D6 -m "Corrected."
114 vole issue rm-comment 01M5JR2JK29KKMAA1T9MDNTPBP 01M5N1PRC4GJPZNEEG8PR8J4D6
115 vole issue edit 01M5JR2JK29KKMAA1T9MDNTPBP --title "A better title" -l bug -l docs
116 vole issue assign 01M5JR2JK29KKMAA1T9MDNTPBP wilbur
117 vole issue unassign 01M5JR2JK29KKMAA1T9MDNTPBP wilbur
118 vole issue close 01M5JR2JK29KKMAA1T9MDNTPBP
119 vole issue reopen 01M5JR2JK29KKMAA1T9MDNTPBP
e05f1c48
Keenan Nemetz
13d ago
120 vole issue list --state open -l bug --assignee wilbur --format '%(number) %(title)'
520470e1
Keenan Nemetz
16d ago
121 vole issue show 01M5JR2JK29KKMAA1T9MDNTPBP # a prefix is enough
e05f1c48
Keenan Nemetz
13d ago
122 vole issue show 42 # the number is enough
520470e1
Keenan Nemetz
16d ago
123 ```
124
e05f1c48
Keenan Nemetz
13d ago
125 `--format` understands `%(number)`, `%(id)`, `%(shortid)`, `%(state)`, `%(author)`,
126 `%(title)`, `%(labels)`, `%(assignees)`, and `%(created)`. `%(shortid)` is a
127 prefix of the ULID, which is mostly timestamp; `%(number)` is the alias people
128 read and quote.
520470e1
Keenan Nemetz
16d ago
129
130 The CLI commits and pushes for you. It uses the account your SSH key belongs to,
131 not the name in `git config`. If you want to commit without pushing, add
132 `--no-push`.
133
134 You can also create an issue in a new directory with no remote configured:
135
136 ```sh
137 git init bug-report
138 cd bug-report
139 vole issue new --title "the docs page is blank" \
140 --remote ssh://git@forge.example.com/demo.git
141 ```
142
143 ## Rules
144
b492b557
Keenan Nemetz
3d ago
145 - Issues and comments live under `issues/` and `changes/` on the `vole` branch.
b312e166
Keenan Nemetz
10d ago
146 Other paths are rejected. Releases have their own paths, written by Vole. CI
147 records are not stored on the branch; they live in `data/runs.db`.
520470e1
Keenan Nemetz
16d ago
148 - History on the `vole` branch must be linear. Merge commits are not allowed.
149 - Force-pushing `vole` requires repository admin and is recorded in
150 `data/audit.log`. It is meant for redaction, not normal work.
e05f1c48
Keenan Nemetz
13d ago
151 - Writing `#42` in a body links to that entity. Because one sequence holds both
152 kinds, the link goes through `/n/42`, and the server resolves it to the issue or
153 the change request that holds the number. `#<ulid>` links by id and is the form
154 that keeps working if history is ever rewritten. Commits that mention an id are
520470e1
Keenan Nemetz
16d ago
155 shown as backlinks on the issue page.
a6b42433
Keenan Nemetz
7d ago
156 - Writing `@name` links to that account's profile. It is the same syntax a
157 workflow's `mentioned` filter matches, so the page and a job agree about who was
158 addressed. Code samples are skipped, and a name that is not an account stays
159 text.
520470e1
Keenan Nemetz
16d ago
160 - An assignee must be a valid account name: lowercase letters, digits, `-`, and
474a812d
Keenan Nemetz
15d ago
161 `_`. The name is stored as written because account names are never reused. A
62576fa8
Keenan Nemetz
14d ago
162 value that is not an account name cannot be an assignee.
520470e1
Keenan Nemetz
16d ago
163 - The web page can filter by state, label, and assignee, and search titles and
164 bodies.
165
166 ## Comments
167
f6f4b1db
Keenan Nemetz
15d ago
168 A comment is a file at `issues/<id>/comments/<ulid>.md` with `author`,
169 `created`, and optionally `reply_to` metadata. `reply_to` names any comment in
170 the same thread. The web renders one level of nesting by collecting a root's
171 descendants beneath it.
520470e1
Keenan Nemetz
16d ago
172
173 Only the author of a comment can edit or delete it. Vole compares the author on
174 the old version of the file with the account behind the SSH key. An admin can
175 override this, for example to repair a thread after someone leaves, and the
176 override is recorded in `data/audit.log`.
177
f6f4b1db
Keenan Nemetz
15d ago
178 Deleting a comment replaces it with a tombstone ("Comment deleted") so replies
179 keep the thread they answer. The text remains in Git history, and a deleted
180 comment cannot be edited. Editing a comment does not add an "edited" field; the
181 commit carries the time. Deleting is not redaction. Redaction means an admin
182 force-push.
183
184 The web comment menu offers Reply, Copy, Edit and Delete. Editing and deleting
185 are limited to the author or an admin, and deletion leaves a tombstone so replies
186 keep their thread.
520470e1
Keenan Nemetz
16d ago
187
188 The issue itself works differently. Closing, relabeling, or assigning someone
189 else's issue is normal triage, not a claim of authorship.