Collaborating
Pulls, issues, comments and reviews are records in each participant’s own account. Writes to someone else’s repository go through a gateway they trust. Pulls, issues and moderation and Gateway explain how this works.
The examples use alice.test as the owner and bob.test as a
collaborator.
The appview
Section titled “The appview”Pulls and issues on a public repository are records in many accounts, so
listing them takes an appview: a knotless-serve with an index. knotless
uses https://knotless.dev unless KNOTLESS_APPVIEW names another:
export KNOTLESS_APPVIEW=https://appview.exampleSet it empty (KNOTLESS_APPVIEW=) for no appview at all: commands that
list pulls and issues on public repositories then fail.
Private repositories need no appview: their pulls and issues are read from the members’ repos in the space.
Give someone write access
Section titled “Give someone write access”Only an account can write to its own repo, so collaborators push through a
gateway: a knotless-serve that the owner has delegated to. Delegate once,
then share the repository for writing:
knotless account delegate alice.test did:web:git.example.com # as aliceknotless repo share knotless://alice.test/proj bob.test --writeaccount delegate opens a browser for you to approve the gateway at your PDS. The
gateway then holds a session for your account, so run your own or use one
you trust. Share for writing before you have delegated, and repo share
delegates to the appview’s gateway first, in the same way.
The collaborator pushes with plain git:
git push knotless://alice.test/proj feature # as bobTheir remote helper signs each request with a service token from their own
PDS. The gateway checks the token against the repository’s collaborators
before it writes as the owner. Commits sent to one branch at the same time,
with knotless repo commit or the MCP repo_commit tool, are queued and land
together as one push, rebuilt on the new tip if the branch moved
underneath them.
To see who has access, or take it away:
knotless repo members knotless://alice.test/projknotless repo share knotless://alice.test/proj bob.test --undoProtect a branch
Section titled “Protect a branch”knotless branch protect knotless://alice.test/proj main # forward only, no merge commitsknotless branch protect knotless://alice.test/proj main --merges # forward only, merge commits allowedknotless branch protect knotless://alice.test/proj main --reviews 1 --code-owners # and reviewedknotless branch rules knotless://alice.test/projknotless branch protect knotless://alice.test/proj main --undoThrough the gateway, a collaborator can only move a protected branch forward and can never delete it. Unless the rule allows merges, they cannot put merge commits on it either, and pulls merge into it squashed, one commit each.
With --reviews <n>, a pull merges into the branch only once <n> of
you and your collaborators, other than its author, approve it (knotless comment add <url> <pull> <text> --approve), and none of you has asked for
changes. With --code-owners too, each path it changes that the branch’s
CODEOWNERS file gives owners needs one of them to approve it:
# .knotless/CODEOWNERS, CODEOWNERS or .github/CODEOWNERS* @alice.testweb/ @bob.test @carol.testdocs/ did:plc:abc123The last line that matches a path names its owners. --dismiss-stale
counts only approvals of the pull’s head as it is now. knotless pull merge <url> <pull> --check lists what a pull still lacks, and the owner’s
--force merges past it.
The owner writes to their own account without the gateway, so the rules hold the owner only as far as their own client keeps to them.
Fork, pull, review and merge
Section titled “Fork, pull, review and merge”Anyone can fork a repository and offer changes back:
knotless repo fork knotless://alice.test/proj # as bobgit push knotless://bob.test/proj topicknotless pull create knotless://alice.test/proj main knotless://bob.test/proj topic "Fix the parser" -m "Details."pull prints the pull’s at:// URI. -m - reads the body from stdin,
where Markdown’s backticks and $ are safe from the shell:
knotless pull create knotless://alice.test/proj main knotless://bob.test/proj topic "Fix the parser" -m - < body.mdList the pulls, or show one with its comments:
knotless pull list knotless://alice.test/projknotless pull show knotless://alice.test/proj <pull at-uri>The MCP pull_show tool, on a pull, also says what it brings in and
whether it merges cleanly.
To review someone else’s pull, comment with --approve or --changes:
knotless comment add knotless://alice.test/proj <pull at-uri> "Looks right" --approveYour latest verdict is the one that stands. An approval is of the head you looked at: push to the pull and it shows as an approval of an earlier version until you review again.
To say something of particular lines, add --line with the file and the
lines, :old for lines the pull removes. Each starts a thread:
knotless comment add knotless://alice.test/proj <pull at-uri> "A few things" --changes \ --line src/main.rs:12 "This can panic" \ --line src/main.rs:20-24:old "Why remove this?"comment add prints each comment’s URI. Answer one with its URI as the
subject, and once it is dealt with, knotless comment resolve knotless://alice.test/proj <comment at-uri>. On the pages, the + beside
a line of the pull’s Files tab does the same.
The owner or a collaborator merges it:
knotless pull merge knotless://alice.test/proj <pull at-uri>pull merge stops on a conflict first, naming the paths (merging conflicts in <paths>). Otherwise it fast-forwards when it can, and makes a merge
commit, Merge <title>, a blank line and the pull’s URI, by you. Into a
protected branch without --merges, it squashes the pull into one commit
even when it could fast-forward: the head’s author and date, you as
committer, and the pull’s title, body and URI as the message. A commit
whose message ends with a pull’s URI links to that pull on the web pages.
As a collaborator, the merge goes through the gateway, which takes or
refuses each ref on its own: the branch update and the head branch’s
deletion. pull merge fails on the first ref refused.
When a pull comes from a branch of the repository itself, merging it
deletes that branch in the same push. --keep-branch keeps it, and so does
another open pull that names it.
In a repository that names runners, pull merge refuses until
the pull’s checks pass. --wait <secs> waits for them, and --force, the
owner’s alone, merges past them. The refusal names what failed, what is
still running, or the older head or base the checks are of, and ends with
what to do, where to read why among it: read their logs with `knotless run list <url> --pull <pull> --log`. On a pull’s page, the same refusal
names the page’s controls instead, and the failed checks are linked
beside it. The merge gate lists
each wording.
To point a pull at other branches:
knotless pull retarget knotless://alice.test/proj <pull at-uri> --base releaseOnly the pull’s author can change its head branch, with --head.
Revert a merged pull
Section titled “Revert a merged pull”The owner or a collaborator undoes a merged pull with a pull of its own:
knotless pull revert knotless://alice.test/proj <pull at-uri> -m "It broke the build"It prints the new pull’s URI. The pull brings in one commit, on a new
branch revert/<rkey> cut from the target branch as it is now, that undoes
everything the merge brought in. Its title is Revert "<title>", and its
body links the merged pull and says why. Check and merge it, or queue it,
as any pull. When the target branch has since changed what the pull
changed, pull revert stops, naming the paths (reverting conflicts in <paths>). On the web, a merged pull’s page has a Revert button that does
the same and opens the new pull.
Use the merge queue
Section titled “Use the merge queue”When many pulls are ready at once, queue them. The queue is off until you
turn it on for a branch, and then every pull into that branch lands through
it. A runner started with --queue checks queued pulls together, in
batches, and lands each batch that passes:
knotless branch protect knotless://alice.test/proj main --queueknotless pull merge knotless://alice.test/proj <pull at-uri> --queueknotless queue list knotless://alice.test/projknotless queue leave knotless://alice.test/proj <pull at-uri>pull merge --queue returns at once. queue list lists each queue in order, and the
pulls ejected from it with the reason. The merge
queue explains how batches are built and
bisected.
Open and close issues
Section titled “Open and close issues”knotless issue create knotless://alice.test/proj "Crashes on empty input" -m "Steps…"knotless issue list knotless://alice.test/projknotless issue close knotless://alice.test/proj <issue at-uri>knotless issue reopen knotless://alice.test/proj <issue at-uri>A pull whose title or body says Fixes <issue> (or Closes, Resolves),
naming the issue by its page URL or its at:// URI, closes that issue when
it merges into the default branch, directly or through the merge queue.
See closing issues.
The keyword must come right before the issue, in any case, and may carry
punctuation before it and one : after ((fixes:). A word that merely
holds a keyword, such as prefixes, does not count. The issue may be
wrapped in <> or (), or followed by ., ,, ;, :, ! or ?. A
page URL may be https:// or http://, on any host, with %3A in the DID
and a trailing /, query or #fragment; a Markdown link counts by its
target. #12, a pull’s URI, or an issue on another repository closes
nothing. Each issue counts once, however often it is named, and only an
open one the merger may close is closed.
Write from the repository’s templates
Section titled “Write from the repository’s templates”A repository can say what its pulls and issues should hold, in
.knotless/pull.md and .knotless/issue.md. They are Markdown: a pull’s
is read from its base branch, an issue’s from the default branch. Their
<!-- --> notes say what the title should be, and anything else that
belongs to the writer rather than the body.
knotless pull template knotless://alice.test/proj # into the default branchknotless pull template knotless://alice.test/proj release # into releaseknotless issue template knotless://alice.test/projWith a template, a pull or issue is refused if it has no body, a blank
one, one of only the template’s notes, or one with none of the
template’s headings (## Why, at any level, in any case). The error
names what is missing and carries the template, so whoever opens it, a
person or an agent, writes the title and body from it. A body that keeps
even one of the headings goes in as written, less any of the template’s
notes copied into it, so a section with nothing to say can be left out.
The MCP pull_template and issue_template tools give the same, and pull_create and issue_create
say to read it first.
A template can ask for a short opener and fold its sections below it in
<details>, which the pages and the iOS app draw closed under what its
<summary> says, as GitHub does. The headings count inside a fold too.
knotless’s own .knotless/pull.md does this, so the full write-up an
agent gives sits under its model’s name, below what a person chose to
say.
Label pulls and issues
Section titled “Label pulls and issues”The owner defines the labels; then the owner and collaborators put them on.
Of a scope’s exclusive labels, such as priority/high and
priority/low, only one stands at a time.
knotless label define knotless://alice.test/proj kind/bug --color '#d73a4a' --description "Something broken"knotless label define knotless://alice.test/proj priority/high --exclusiveknotless label define knotless://alice.test/proj priority/low --exclusiveknotless issue label knotless://alice.test/proj <issue at-uri> kind/bug priority/highknotless issue label knotless://alice.test/proj <issue at-uri> priority/high --undoknotless label delete knotless://alice.test/proj kind/bugpull show and issue show print an item’s labels under its title. See
labels.
Edit what you wrote
Section titled “Edit what you wrote”The author of a pull or issue can edit its title and body. The author of a
comment can edit it or take it back. -m '' drops a pull’s or issue’s
body.
knotless pull edit knotless://alice.test/proj <pull at-uri> --title "Fix the parser" -m "Updated details."knotless comment delete knotless://alice.test/proj <comment at-uri>Pulls and issues are closed, not deleted, so what was said about them stays.
Moderate
Section titled “Moderate”An owner can hide a pull, issue or comment on their repository, and block an account from one repository or from all of theirs:
knotless mod hide knotless://alice.test/proj <issue at-uri>knotless mod block troll.test knotless://alice.test/projknotless mod block troll.test knotless://alice.test/proj --undoAnyone can report an account, a repository or a record to the appview’s
moderation service. The reason is one of spam, violation,
misleading, sexual, rude or other:
knotless mod report <issue at-uri> spam -m "the same link in every issue"The service’s operators, the accounts its KNOTLESS_ADMIN_DIDS names,
read reports and take accounts and records down, signed in as
themselves. Other appviews can follow those takedowns as labels.
knotless admin reportsknotless admin takedown troll.testRename, transfer or delete a repository
Section titled “Rename, transfer or delete a repository”knotless repo rename knotless://alice.test/proj parser # the old name redirectsknotless repo transfer knotless://alice.test/parser carol.test # offer it to carolknotless repo accept knotless://alice.test/parser # as carolknotless repo delete knotless://alice.test/parser --yesknotless repo transfer <url> --undo withdraws an offer. A transfer moves the
pulls and issues too. Naming and identity
explains how renames and transfers keep links working.