#+title: gitbay changelog Versioning follows semver from v0.1.0. Database migrations run automatically on daemon start; upgrade notes appear per release when anything beyond "replace the binary and restart" is needed. * v1.10.0 — 2026-09-04 Every command parses its arguments the same way, the web answers by exit code, and a restart no longer waits on idle connections. - One flag parser for every command: an unknown flag, a missing value or too many arguments is exit 2 with the command's usage, everywhere. =mr review --approve --bogus= used to report repository =--bogus= as not found. #96 - =--json= is honoured by the dispatcher's own refusals, so a script told no gets the envelope. #109 - A store failure is exit 1 and not-found is exit 3; both used to be usage errors. #107 - Web form actions answer by exit code: the 404 page for a thing that does not exist, the page with the message for anything else. #106 - Inside a clone, =gitbay mr create= takes the checked-out branch as =--source=; =gitbay --help= is the server's reference for the noun, flags included. #101 #130 - Shutdown closes idle SSH connections at once and drains only sessions mid-command; a store failure during key lookup no longer counts as a bad key against the auth limiter; the CLI says on ssh's exit 255 that a burst may have tripped it. #141 - A merge request head the target already contains is recorded as merged instead of refused; a fork is created with its parent in one insert; a failed transfer revert is reported; the repository quota is checked under a lock. #108 - Issues and merge requests share their comment, reference and author-or-write code. #110 - The payloads the web and clients decode are named types: =Created=, =MRCreated=, =IssueShow=, =MRShow=. JSON unchanged. #126 - Tests: parse failures per command, non-ASCII paths (which found =ls-tree= returning octal escapes, fixed with =core.quotepath=off= for every git the server runs), concurrent pushes. #129 Replace the binary and restart, and reinstall the CLI. No migration. * v1.9.0 — 2026-09-03 The runner is no longer an admin, the web no longer reaches around the registry, and the CLI stops paying a handshake per command. - =keys add --scope runner= confines a key to =runner next/log/done= and read-only git; the runner commands accept that scope or an admin. The systemd drop-in sandboxes the runner process. gitbay.org's runner now polls as a non-admin =ci= account scoped to one repository. #92 - The web's repo create, issue create and edit, MR edit and both comment forms dispatch the command the CLI runs, so the repository quota, the archived-repository refusal, notifications, the body format and the audit entry hold from a browser. #93 - The CLI shares one SSH connection per instance (=ControlMaster=, five minutes idle): a command costs a round trip instead of a handshake, 0.4 s instead of 4 s from a distant laptop. =no_multiplex = true= on an instance opts out. #94 - A disabled account is refused on every surface, and disabling revokes its API tokens along with its sessions. #95 - CODEOWNERS gates whenever the file exists on the target branch, not only under =require-approvals=. #99 - The HTTP listeners have header and idle timeouts, and SIGTERM drains in-flight requests and SSH sessions before exit. #104 #105 - =git archive= runs under a two-minute deadline and a 512 MiB cap. #124 - Every git invocation ends option parsing before the ref, so a ref shaped like an option is a bad revision and never a flag. #135 - The admin noun is gated in the dispatcher as well as in each handler; registry tests cover that and =ReadsStdin=. #127 - An e2e test runs every =ReadOnly= command against a populated instance and fails on any row it changes. #97 - =http.trusted_proxies= attributes proxied API requests to the last untrusted =X-Forwarded-For= hop for rate limiting; =email add= is capped at five codes an hour per account. #136 - A merge request head is built in the target repository, at =refs/merge-requests//head=, so a fork's merge request has =ci/= statuses for =require-checks= to gate on. A head from another repository is built without the target's secrets. #98 - Triggers refuse deleting a user or organization that still owns repositories, whatever path the delete takes. #136 - The stylesheet's fonts are served again, and directory crumbs on blob and blame pages link to the tree. #102 #103 - The Threat-Model wiki page covers the runner. #138 Replace the binary and restart, reinstall the CLI, and =make deploy-runner=: the runner fetches merge request refs before checkout. Migrations 0032 and 0033 run on start. The daemon host needs git 2.24 or newer for =--end-of-options=. Operators running =gitbay-runner=: give it a non-admin account with a key added by =keys add --scope runner=, remove the admin key it held, and =make deploy-runner= to install the sandboxed unit drop-in; an admin key keeps working meanwhile. * v1.8.1 — 2026-09-03 Markdown and org files render when opened. - A =.md=, =.markdown= or =.org= file renders on its page the way a README does on the directory page, through the same renderer with relative links resolved against the file's directory. =source= in the action bar, or =?view=source=, shows the text as before. Every other file is unchanged. #88 - The e2e harness waits for the HTTP and git listeners as well as SSH before a test starts; a test whose first act was an HTTP request could be refused, which failed two otherwise green runs. #91 Replace the binary and restart. No migration. * v1.8.0 — 2026-09-03 The tracker's lists narrow, labels have colours you set, and the CLI's help is the server's. - =issue list= takes =--label=, =--assignee=, =--author= and =--milestone= (a title, or =none= for issues with no milestone); =mr list= takes =--author= and =--milestone=. The store narrows in SQL, and the web lists take the same names as query parameters and show each active filter with a link that drops it and keeps the rest. Both lists had taken =--state= and nothing else, so the web's filtering could never match the CLI's. #84 - =label list= shows a repository's labels with their colour and how many issues carry each; =label set