Wiki: Parity
Parity
- Rule
- Merge requests
- Issues
- Repositories
- Discovery
- Accounts
- Organizations
- Pagination
- SSH only, by design
Which surface can do what. The CLI is meant to be the complete interface: every capability exists over SSH, and the other surfaces dispatch the same control commands rather than reimplementing them, so they cannot drift. This page is updated in the merge request that changes a row.
Three surfaces now: the CLI over SSH, the web, and the iOS client
(krz/gitbay-ios). A no in the cli column is a defect, not a
preference — it means some surface reached around the registry and
stranded a capability where only it can reach.
Rule
A capability lands over SSH first. If it belongs to the
triage/review/respond loop, it lands on the web in the same merge
request. Anything whose input is a credential — secrets, mirror
tokens, API tokens, session minting — stays SSH-only by design: the
web dispatcher refuses SSHOnly commands outright.
Rows are one page or one action each. Grouped rows hide gaps, twice now: "browse, log, blame, search" read as covered while blame had no command at all, and "build list, log" read as covered while the job list a trigger can name had none (krz/gitbay#50), leaving the picker browser-only and the iOS build screen unable to say more than the log.
Merge requests
| capability | cli | web | ios |
|---|---|---|---|
| read, diff, commits | yes | yes | yes |
| comment | yes | yes | yes |
| edit title and body | yes | yes | yes |
| review (approve etc.) | yes | yes | yes |
| resolve a thread | yes | yes | yes |
| comment on a diff line | yes | yes | yes |
| merge (all strategies) | yes | yes | yes |
| close | yes | yes | yes |
| create | yes | yes | yes |
| create from a fork | yes | no | yes |
| retarget | yes | yes | no |
| milestone | yes | yes | yes |
| choose body markup | yes | no | no |
Creating from a fork works anywhere the source can be typed as
owner/name:branch; only the web lacks it. Retargeting moves an open
merge request onto another branch of the same repository and stales the
reviews, since an approval was of the diff against the old branch.
Issues
| capability | cli | web | ios |
|---|---|---|---|
| read, list, filter | yes | yes | yes |
| create | yes | yes | yes |
| comment | yes | yes | yes |
| edit title and body | yes | yes | yes |
| close and reopen | yes | yes | yes |
| labels, assignees | yes | yes | yes |
| milestone | yes | yes | yes |
| milestone list | yes | yes | yes |
| choose body markup | yes | no | no |
Issue, MR and release bodies, and their comments, carry the markup they
were written in — --format md|org on create, comment and edit, stored
alongside the text so changing a preference later cannot reinterpret
prose that already exists. Every surface renders the stored format;
the no above is the absence of a picker on the web form and in the iOS
composer, both of which write markdown. Diff-line comments have no
format column and are always markdown.
Repositories
| capability | cli | web | ios |
|---|---|---|---|
| browse files | yes | yes | yes |
| read a file | yes | yes | yes |
| commit log | yes | yes | yes |
| commit log at a ref | yes | yes | yes |
| one commit with its patch | yes | yes | yes |
| blame | yes | yes | yes |
| search file contents | yes | yes | yes |
| branches and tags | yes | yes | yes |
| wiki (read) | yes | yes | yes |
| download an archive | yes | yes | n/a |
| edit a file | yes | yes | yes |
| create | yes | yes | yes |
| pin | yes | yes | yes |
| settings, protection | yes | yes | yes |
| topics, website | yes | yes | yes |
| visibility | yes | yes | yes |
| archive (read-only flag) | yes | yes | yes |
| release list, show | yes | yes | yes |
| release create, edit | yes | yes | yes |
| build list | yes | yes | yes |
| build show (one build) | yes | yes | yes |
| build log | yes | yes | yes |
| build jobs | yes | yes | yes |
| build trigger | yes | yes | yes |
| delete, transfer | yes | no | no |
| release delete | yes | no | no |
No row is web-only any more. Blame, file editing, log at a ref, archive, the public listing and the wiki were all in that state — a handler reading git or the store directly instead of dispatching a command — until krz/gitbay!99, !101 and !102 gave them commands.
The wiki row covers reading. Editing a wiki is a push to
<repo>.wiki.git on every surface, including the web, so there is no
edit row to have parity on.
n/a marks a capability deliberately absent from a surface rather than
missing from it. Archive download is n/a on iOS: the read API carries
a command's stdout as a JSON string, so a gzip stream cannot survive it,
and the app has nowhere useful to put a tarball — the brief rules out
local git, so there is no clone, checkout or build to feed. The web's
route stays the way to get one.
A README or wiki page's org renders per surface: the web through
go-org, the iOS client through the shared OrgSwift package
(krz/org-swift). OrgSwift is held to orgo's output by the
krz/org-conformance corpus — golden renderings from orgo, itself
diffed against Emacs ox-html — so constructs the iOS client used to
approximate (tables, footnotes, timestamps, heading tags, nested lists)
now render the way the reference does. go-org is not yet on the corpus.
Discovery
| capability | cli | web | ios |
|---|---|---|---|
| search repositories | yes | yes | yes |
| browse all public repositories | yes | yes | yes |
| profile page | yes | yes | yes |
| profile about and links | yes | yes | no |
| activity feed | yes | yes | yes |
explore is the listing without a query; repo search is the one with.
About text renders as markdown or org-mode per the about_format it
was stored with. The iOS Profile decoder lists its keys explicitly,
so it ignores about and links rather than breaking on them.
Accounts
| capability | cli | web | ios |
|---|---|---|---|
| SSH keys: list, add, remove | yes | yes | yes |
| PGP keys: list, add, remove | yes | yes | yes |
| email add and verify | yes | yes | yes |
| dashboard aggregate | yes | yes | yes |
| API token mint | yes | no | no |
| account export bundle | yes | no | no |
| profile set | yes | no | no |
profile set carries description, website, about and links. It is not
SSHOnly — nothing about a bio is a credential, and the JSON API runs
it — but no surface has ever offered a form, so the no above is
missing UI rather than a rule.
Organizations
| capability | cli | web | ios |
|---|---|---|---|
| read members and teams | yes | yes | yes |
| members add, remove, role | yes | yes | yes |
| teams create, delete | yes | yes | yes |
| team members | yes | yes | yes |
| team repo grants | yes | yes | yes |
| create, rename, delete | yes | no | no |
Pagination
issue list, mr list, repo list, and feed take --limit <n>
and --cursor <c>. Cursors are opaque; each page carries the next
one. Without the flags a list stays complete, so existing scripts are
unchanged. The web renders server-side and does not paginate; iOS
pages with the cursors.
SSH only, by design
Build secrets, mirror configuration and tokens, custom domain claims, API token minting, web session minting, deploy keys, account and instance administration. Deleting or transferring a repository is also CLI-only: both want a typed confirmation, not a button.
These are the only rows where a no is intended. Everywhere else a
no is work outstanding, and n/a means a surface cannot usefully
carry the capability at all — see the archive note above.