~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

7

Releases of knotless

knotless 0.5.0 Latest ea74a57

Features

A workflow step can use a step another repository shares

A step with uses: <owner>/<repo>/<step>@<version> runs the steps of .knotless/steps/<step>.yml in that repository, at the commit .knotless/uses.lock pins it to, with the inputs with gives, only the secrets the step passes it, and its own repository checked out beside the checkout as KNOTLESS_STEP_DIR. A step file can use shared steps of its own. Release a step with knotless publish <url> @step/<step> <version> .knotless/steps/<step>.yml --commit <sha>, and pin the ones a checkout uses with knotless uses update. Each step is now given its secrets as it starts, rather than the container holding them all.

show lists the pulls that mention an issue

knotless show on an issue prints mentioned in <pull> for each pull on the repository whose title or body names it, oldest first, ending , to close it where the pull names it after a closing keyword. MCP's show_item gives the same as mentionedBy.

A login and a gateway's grant name knotless's own space types

knotless login asks for space:dev.knotless.space and space:dev.knotless.orgSpace, each with the collections knotless writes there, in place of every space of every app (space:*); knotless delegate asks the same of a gateway's grant. A login or grant from before still works, and is asked for again as any older one is.

A workflow step can run only at some refs

A step with on: {refs: [refs/heads/main, refs/tags/*]} runs only at a push to, or a run asked for at, a ref those patterns match, as on.push.refs are matched; anywhere else it passes unrun, listed skipped, its log saying why. A pull's run and a merge-queue batch's run are at no ref, so such a step runs in neither. On a step with uses, its on holds for every step the shared step comes to, beside their own.

Themes of your own

The pages' Appearance settings make a theme of your own colours, checked as you choose them for text that reads on what it is drawn on, and publish it as a dev.knotless.theme record for anyone to choose from Appearance. Choosing one copies its colours into your preferences, so its author changing or deleting it later leaves your pages as they are. Logging in again asks to write dev.knotless.theme records.

The command line does the same: knotless theme check, publish, use and delete, and knotless themes to find them; and over MCP, the theme and list_themes tools. A palette is held to the same contrast wherever it is made.

Fixes

knotless show names the command that reads an ejected pull's logs

A pull the merge queue ejected as its checks failed shows logs: knotless checks <url> --pull <pull> --log, or --queue <branch> for a batch, after where it stands. The runner no longer writes that command into the reason it records, which the web pages show beside links to the checks that failed.

An organization's space has a type of its own, dev.knotless.orgSpace

An organization keeps its invitations and hidden members in a space of the type dev.knotless.orgSpace, which has its own lexicon, so that a login can name it. Its gateway moves an organization out of its old space, of the type dev.knotless.org, as it starts and as the organization next changes, keeping each member where they stood. A hidden member's record of joining stays in the old space, and counts, until they join again: knotless org join <org> --hidden moves it.

knotless status shows the server's disk

knotless status adds a disk line: how much room is left on the disk a knotless-serve keeps its mirrors on. Under 15% free the disk shows as low among the problems, and under 5% the server counts as unhealthy.

knotless 0.4.0 fa4f93f

Features

Say an account is a bot

knotless profile --bot says your account is a bot, such as a runner, a triager or a reviewer, and --no-bot takes that back. The MCP server's set_profile takes bot, and the profile settings page has a box for it. A bot's profile shows a "Bot" tag, and the front page's feed leaves out what it says and pushes.

Fixes

The feed leaves out bots

The front page's feed no longer shows what a repository's runners and triagers say or push on it, which repeated what people did and crowded them out. A runner that is the repository's owner or a collaborator still shows. A pull the merge queue landed shows as merged by whoever queued it. A bot's own profile still shows everything it did.

The appview's gateway is the one its DID document names

knotless share --write, knotless delegate with no gateway named, and a runner landing a merge queue through the gateway now ask the appview for its DID instead of making one from KNOTLESS_APPVIEW's address. A runner that reaches its appview at an internal address, as one beside it does, lands its queue again rather than failing to reach a gateway that does not exist.

Private repositories work on the October 29 spaces alpha

The spaces alpha of October 29 moved spaces from com.atproto.simplespace to a policy on com.atproto.space, and creating a private repository or sharing one failed against a PDS running it. knotless now creates each private repository's space under the memberspace policy and manages its members with com.atproto.memberspace. A PDS on an older alpha can't create private repositories with this version.

knotless 0.3.0 9ecd068

Features

Archive a repository

knotless archive <url> makes a repository you own read only, and knotless archive <url> --undo makes it writable again. While it is archived, pushes and commits are refused, nobody can open pulls or issues or comment on it, and its workflows stop running. Its pages show it as archived. You can also archive and unarchive it from its settings, in the Danger zone, or with the MCP server's archive_repo tool.

Hear of your pulls' failed checks and merge queue ejections

knotless notifications, the MCP notifications tool and the pages now say when checks fail at your pull's latest run (checks-failed) and when the merge queue takes your pull out (ejected), each naming the checks that failed. Either can be turned off with knotless notifications settings --off <reason>. The pages' notification settings can also show new notifications on your screen while knotless is open in a tab.

Change part of a long file without sending all of it

knotless commit --edit <path> <old> <new> and the MCP commit tool's edits replace text in a file as the branch holds it, so an agent changing one line of a long file sends that line, not the file. On a branch that moved meanwhile, edits are made in the file as it is there. knotless search and the search tool take --path/path to look only under a directory or glob, and --context/context to show the lines around each match, enough to write an edit from. The read_file tool takes start and end to read only some lines, and blame (--lines <first>-<last> on the command line) blames only some.

Notifications of one kind

knotless notifications --kind <kind> lists only mentions, reviews, comments, pulls-and-issues, checks or stars-and-follows, and the MCP server's notifications tool takes the same kind. A listing of one kind marks nothing seen, so the others stay new.

Owners give their runners secrets

knotless secret <url> set <name> [--ref <pattern>]... gives a repository's runners a secret, read from stdin, sealed to the key each runner publishes so only it can read it, and left at the appview. knotless secret <url> ls lists them, never a value, and rm takes one back. The MCP server has a secret tool to match. A runner reads them for each run whose workflow lists a name its secrets file does not grant. knotless runners <url> remove deletes the secrets sealed to that runner, and add says which secrets must be set again to reach it.

A read-only knotless-mcp, and reviews of private repositories

knotless-mcp --read-only offers only the tools that read, and runs no other, whatever account it is logged in as. The review agent reads through it with its own login, so it reviews the private repositories shared with it, and a repository says what it wants of its reviews in .knotless/review.md on its base branch.

Topics and collaborators on a repository

knotless describe <url> --topic rust --topic cli names what a repository is about, and --topic '' drops its topics. They show under its description, each linked to the other repositories about it, and the MCP server's update_repo tool and the repository's settings change them too. A repository's page also shows who may push to it besides its owner.

Review agents

knotless-agent review runs an account of your own that reviews the pulls asking it for a review, as GitHub's Claude review bot does. Ask it with knotless pull --reviewer <its handle> or knotless edit --reviewer; it reads the pull with Claude Code, through knotless-mcp's read tools, and writes a review with a verdict and comments on lines, then reviews again as you push, up to --rounds times. It uses your Claude subscription (claude setup-token) or an API key, and --command takes any other reviewer that reads and writes its JSON. The guide is docs/guide/reviews.md.

The reviewer can watch every repository an account holds

knotless-agent review --owner <handle> reviews the pulls of every public repository that account holds, listed again at each read, so a repository made later is reviewed without restarting the agent. Repeat --owner for more accounts, and name repositories besides as before.

knotless-run keeps a key for secrets

knotless-run now makes a P-256 key on its first start, kept in --secrets-key <file> (secrets-key.json beside its state file by default), and publishes its public half as its dev.knotless.runnerKey record. Owners will seal the secrets they give a runner to it, so only the runner can read them.

The appview keeps secrets sealed to a runner

knotless-serve answers dev.knotless.putSecret, deleteSecret and listSecrets: an owner leaves a repository's runners secrets, each sealed to one runner's key, and the appview holds only ciphertext. knotless's login asks for these methods, so a session from before asks again at its next login.

Owners manage secrets on the repository's settings

The repository's Settings, under Actions, list its secrets by name and add, replace and remove them, signed in as its owner. Each value is sealed in the browser to the keys the runners publish, as knotless secret seals it, so the appview still holds only ciphertext.

Hear of new versions, and upgrade

Once a day, knotless asks its appview for the newest release. When one is out, a command ends by saying so on stderr. knotless upgrade installs it over the copy you run. When the appview asks for a newer version than yours, because yours is known to harm repositories, knotless and knotless-mcp refuse to run until you upgrade. KNOTLESS_NO_UPDATE_CHECK turns the check off, and KNOTLESS_IGNORE_MINIMUM runs anyway.

A workflow can name the runners that run it

A workflow's runners key names, by handle or DID, which of the repository's runners run it; the others leave it be and file no check of it. knotless secret <url> set <name> --runner <handle> gives a secret to those runners alone and takes back the copy any other had, as the MCP secret tool's runners does. Together they keep a deploy and its secrets on a runner of your own while the hosted runner checks everything else.

Fixes

Clones no longer break after a branch is deleted and compacted

A clone or fetch could fail with "the remote has no pack holding" a commit of a deleted branch, such as a landed pull's. A newer pack still named that commit as a base, and compaction had dropped it. Compaction now keeps every base that the packs it leaves name.

Compaction stops rather than lose a commit

If compaction can't fetch a commit that a newer push still needs, it now stops and deletes nothing. Before, it left that commit out and deleted the packs anyway, which broke clones with "the remote has no pack holding" that commit.

A conflict is named a conflict

A 409 from knotless-serve, such as a gateway commit whose edit no longer finds its text, now says Conflict (409) rather than InternalServerError (409), so it no longer reads as the server failing.

A pull the merge queue landed shows the checks it landed on

A merged pull's page now shows the checks of the batch the merge queue landed it in, not older runs of its own heads. Over MCP, list_items and show_item name that batch's tip as merged_batch.

Joining an organization reads both places at once

knotless org join reads whether you joined publicly and in the organization's space at the same time. Switching between them no longer reads again after the organization takes you in.

Pages left open catch up when you come back

A page left in a background tab for a minute or more loads fresh data when you look at it again, and any page does the same when your connection comes back. A repository's page that loses its live connection now catches up on what it missed once it reconnects.

Pictures show at the size they were taken

A picture attached with --image, or images over MCP, keeps the size it is drawn at: a PNG saying it was made at 2x, as a Mac's screenshot does, shows at half its pixels, so a phone's screenshot is phone-sized on a pull or issue.

A run says which secrets it was not granted

A run whose workflow lists a secret the runner does not grant it now says so at the top of its log, ==> NAME is not granted to <repo> at <ref>, rather than leaving the secret silently absent. A pull's or merge-queue batch's run says the same of each, as it gets none.

An edit or reply in progress survives the page updating

A comment you are editing, or a line comment you are replying to, on a pull's or issue's page no longer loses what you typed when the page refreshes and an earlier event shows up.

knotless 0.2.0 37e09fc

Features

Blame a file without a clone

knotless blame <url> <path> [--rev <rev>] prints who last changed each run of a file's lines, as git blame finds it, read from the cache mirror: the lines, the commit, its author, when it was written and its subject, tab-separated. The MCP server's blame tool answers the same as JSON, with the commit's parent and the file's path there, to blame again before it.

Reviews and merges say what they mean

merge --check lists each approval that does not count, and why, as an uncounted line (the MCP merge check as reviewsUncounted), and a merge refused for its reviews says so too. It says when the asker may not merge the pull, and counts a review written a moment ago. Over MCP, a refusal for reviews names the comment tool and merge with force rather than CLI commands; merge answers how it merged (method) and why it kept the head branch (kept); show_item gives handles beside reviewers' DIDs, marks reviews outdated, maintainer and uncounted, gives comments' mention facets, marks every comment of a resolved thread resolved, has a review's own comment name itself as review, and says draft: false; comment notes an approval that will not count; notifications says markedSeen.

Comment on a pull's lines, in threads you can resolve

knotless comment takes --line <path>:<n>[-<m>][:old] <text>, as many as you like, to comment on lines of a pull's diff, alone or as one review with --approve, --changes or a body, and prints the URI of each comment it wrote. Given a comment's URI, it answers that comment in its thread. knotless resolve and unresolve resolve a thread or open it again, and knotless show says which lines each comment is on and which answer which. Over MCP, comment takes lines and answers written too, set_state resolves a thread, and show_item gives each comment's line, reply, review and resolved. On the pages, the + beside a line of a pull's diff comments on it, or starts a review sent from the "Review changes" menu.

Delete all your knotless data

knotless delete-data <handle> lists what knotless keeps in your atproto account (your repositories, those others push to or read named, and the records of each kind), then, once you type your handle again (or pass --yes), deletes all of it: your private repositories' spaces, each public repository as knotless delete deletes one, then your pulls, issues, comments, stars, follows and the rest. knotless.dev then forgets you and logs you out. A run cut short carries on where it stopped when run again. Your atproto account, and other apps' records in it, stay. The delete_account_data MCP tool does the same, and the pages' account settings have a "Delete your knotless data" section. Logging in again asks to call dev.knotless.deleteAccountData.

Draft pulls and requested reviewers

knotless pull --draft opens a pull that neither merges nor queues until you mark it ready with knotless edit <url> <at-uri> --ready (--draft makes it one again); merge --check says draft and why. --reviewer <handle>, on pull and edit, asks someone to review your pull, and edit --no-reviewer stops asking: they hear of it as a review-requested notification once the pull is not a draft. knotless show lists both, and list -q takes is:draft, -is:draft and review-requested:<handle or @me>. MCP's open_pull and edit_item take draft and reviewers too. The pages mark drafts in the pulls list, show requested reviewers in the merge box, and let the author mark a draft ready there.

The gateway holds collaborators to required reviews and checks

Through the gateway, a collaborator moves a branch whose rule asks for reviews only by merging a pull reviewed as it asks, with its checks passed: a plain push or knotless commit to it is refused, saying to open a pull. In a repository that names runners, a collaborator's merge of a pull, pushed by any client, is refused until the pull's checks pass, as knotless merge refuses it.

Mentions

@handle in a pull's or an issue's title or body, or in a comment, now mentions that account: a full handle, with a dot, not in code or a link. Writing the record, from the command line, MCP or the pages, resolves each handle and keeps the account's DID in it as facets, so the mention still names the account after its handle changes. The pages link each mention to the account's profile, and the account hears of it with a new notification reason, mention, on unless turned off with knotless notifications settings --off mention, MCP's notification_settings or the settings page. On a private repository only those who can read it hear of a mention.

Organizations

Any account can be an organization. As that account, after delegating to a gateway (knotless delegate), knotless org add <handle> invites another account, and knotless org join <org> --public or --hidden accepts: from then on they push to each of the organization's repositories, made before or after, and read the private ones, until knotless org leave or knotless org remove. A public membership shows to anyone; a hidden one only to the organization's members, and on its public repositories a hidden member pushes and opens pulls while merging, closing and labelling take a public membership. Invitations lapse after 7 days. --admin makes an admin, who invites, removes and makes repositories as the organization from their own login (--org <org>, or knotless create knotless://<org>/<name>). knotless org members lists who is in (--public as anyone outside sees it), knotless org list which organizations an account is in, and knotless org delete --yes ends it. knotless members names an organization's members on each repository. The org MCP tool does the same, and so do the pages: Start an organization in your account menu, then a Members tab to invite, change roles, join, hide, leave and remove, and Delete organization in settings. An invitation shows in knotless notifications, MCP's notifications and the pages' notifications until it is answered or lapses, and the pages answer it there. Logging in again, and delegating again, asks to write dev.knotless.org, dev.knotless.orgMember and dev.knotless.orgAcceptance records and to call the organization methods.

knotless merge --check, and MCP's merge with check, tell a hidden member why they may not merge on an organization's public repositories: that it takes a public membership.

Pictures in pulls, issues and comments

Paste or drop a picture into a pull's, an issue's or a comment's box on the pages and it is uploaded to your account and linked where you put it, as GitHub does. From the command line, --image <file> on pull, issue, comment and edit does the same, and over MCP images on open_pull, open_issue, comment and edit_item. The record attaches each picture its body shows, so your PDS keeps it, and lets it go when an edit takes it out. A picture over 1 MB is made smaller rather than refused, and so is a profile picture, which may now be a WebP or GIF too.

A pull's diff over MCP numbers its lines

The MCP server's pull_diff tool now leads each line of a hunk with its line number in the old file and in the new, as comment's lines takes them: a + line is side: new at its new number, a - line side: old at its old number. An agent no longer counts lines from the @@ headers to comment on one.

Branches that take pulls only through the merge queue

knotless protect <url> <branch> --queue makes a branch take pulls only through the merge queue, as GitHub's "Require merge queue" does: knotless merge (and MCP merge) queues a pull into it instead of merging, saying so, and only the owner's --force merges at once. The gateway moves such a branch for no collaborator but the runner that lands the queue. knotless rules shows queue, MCP protect_branch takes it, and the repository settings' Branches page has a "Require the merge queue" checkbox for each protected branch, whose pulls' pages then offer only the queue.

Repositories show their releases

A repository's pages show what it publishes: its latest release and its packages under its name, and a Releases tab listing every version, with its notes, files and, for an image, the docker pull command. knotless-serve indexes dev.knotless.release records and answers dev.knotless.listReleases.

Repositories show their links

A repository can name up to five links, its website first, as a profile names its links: knotless create <url> --link <url> [--title <text>], and knotless describe <url> --link … to replace them, or --link '' to drop them. The MCP create_repo and update_repo tools take links, and its settings page has a Links field. Its pages show the first link under the description, before its latest release, with a count of any others that opens the list of them all. knotless describe prints a link: line for each.

Protected branches can require reviews, from code owners too

knotless protect <url> <branch> --reviews <n> makes a pull merge into the branch only once <n> of the owner and collaborators, other than its author, approve it, and while none of them has asked for changes. --code-owners also asks, for each path it changes that the branch's CODEOWNERS file (.knotless/CODEOWNERS, CODEOWNERS or .github/CODEOWNERS) gives owners, for one of them to approve it; --dismiss-stale counts only approvals of the pull's head as it is now. merge, merge --check (which lists what is missing, and CODEOWNERS lines it skipped), the merge queue, MCP protect_branch and merge, and the pages' branch settings and merge box all follow it. The owner's --force merges past it.

Revert a merged pull

knotless revert <url> <pull at-uri> [-m <reason>] undoes a merged pull as GitHub's Revert button does: one commit that undoes everything its merge brought in, on a new branch revert/<rkey> cut from its target branch, and a pull of that branch into it, titled Revert "<title>", its body linking the merged pull and saying why. It prints the new pull's URI; check and merge it, or queue it, like any pull. It stops on a conflict, naming the paths. The owner and collaborators may. The revert MCP tool does the same, and a merged pull's page has a Revert button.

Reviews stand as GitHub's do

Each reviewer's latest verdict is where they stand: a later --approve or --changes replaces an earlier one, and a comment without a verdict changes nothing. knotless show lists each reviewer as a review: line with the head they looked at, and the MCP list_items and show_item give an item's reviews in place of approvals. You can no longer review your own pull, or an issue. The pages show reviewers in a pull's merge box, and a review of a head the pull has since moved past as one of an earlier version.

Sharing for writing delegates first, and reviews say more

knotless share --write and MCP's share delegate your writes to the appview's gateway first when you have not, approved in the browser as delegate is, and say they did. Notifications name what each is about (the pull or issue, or for a star the repository) and its repository as handle/name; a review says how many line comments it holds and whether it mentions you. show_item gives each line comment its side and startLine, resolved only on threads, superseded on a review a later one replaced, and whether each requested review is still pending; list_items says draft: false too. A pull whose only code owner is its author says why it can never have that approval, and protect_branch and list_rules warn when you alone own a path.

Tag a commit without a clone

knotless tag <url> <name> [<from>] tags a commit, the default branch's or that of a branch, tag or commit, and prints it; --delete deletes a tag. The MCP server's create_tag and delete_tag tools do the same. Each release of knotless is now tagged v<version> at the commit it was built from.

The branch menu switches to tags too

On a repository's code, commits, file and blame pages, the menu that switches branches has a Tags tab beside Branches, as GitHub's does, to see the same page at a tag. Viewing a tag, the menu's button shows the tag icon and opens on Tags.

Fixes

Buttons show their action under way

On the pages, the button you pressed shows a spinner and says what it is doing, such as "Inviting…" or "Joining…", until the server answers. The rest wait, dimmed. This covers organizations and their invitations, notifications, merging, settings, labels, reactions and the rest.

Commands and MCP tools say when your login is out of date

While your login is older than what knotless asks for now, every command ends by saying so and naming the knotless login to run. An MCP tool a PDS refuses for want of scope tells the agent to have you sign in again, by reconnecting knotless in your assistant or running knotless login.

Deleting a repository leaves nothing of it

knotless delete, the delete_repo tool and the pages' Delete now also delete the repository's releases and reruns, and what you wrote about it yourself: your pulls, issues, comments, states, labels, hides, queue entries and blocks naming it, your star of it, and your reactions to those. The repository's own record goes last, so a delete cut short carries on when run again. knotless.dev drops what it kept of a deleted repository, its mirror included, and a runner drops its checks, caches and secrets grants. Logging in again asks to write dev.knotless.release records, which knotless publish needs with OAuth.

Organization changes take fewer round trips

Inviting, removing and leaving wait on fewer calls to a PDS. The gateway reads what it needs at once rather than one after another, and no longer tries to make the organization's space each time. On the pages, a change this server's gateway made is no longer indexed a second time.

Handle suggestions when inviting and sharing

On the pages, the fields that take someone else's handle suggest accounts as you type, as the login dialog does: inviting to an organization, adding a collaborator or a reader, and offering a repository to another account.

Say how to grant what a login lacks

A command a PDS refuses because your login is older than what knotless asks for now says so, and to run knotless login again. Logins now keep the scope they asked for, and the pages offer to log in again, or to delegate again, when knotless asks for more.

Collaborators and organization members hear of new pulls and issues

A pull or an issue opened on a repository is now a notification for its collaborators, and for the members of the organization that owns it, hidden members too, as it was for its owner.

Suggestions for @ while writing

Typing @ in a comment, a review, an edit or a new pull or issue on the pages suggests whom to mention: those in the thread, then whom you follow, then accounts whose handles match. Arrows choose, Enter or Tab picks, Escape closes. A mention an edit adds is heard of as of the edit, not as of when the record was first written.

A new repository never replaces one of the same name

create, fork, accept and rename refuse a name a repository of yours already has, public or private, with <url> already exists, before writing anything. On a PDS that took a create over an existing record as an update, creating a repository under a taken name replaced the old one's record and orphaned its history. The record is now written with a compare and swap that the PDS refuses when any record is there. On the web, the new repository form, the fork menu and the rename setting say as you type whether the name is free, and hold their button while it is taken.

Organization changes read at once

Joining, inviting, removing and ending an organization read what they need at the same time instead of one after another. They also read the organization's space once instead of two or three times.

Pasted pictures show in the preview

A picture pasted or dropped into a pull's, an issue's or a comment's box shows in its preview, and a profile picture picked shows before it is saved: the pages let a picture be drawn from what was pasted or picked.

Notification settings live with your other preferences

knotless notifications settings and the notification_settings MCP tool read and change which notifications you hear of through the appview's preferences (dev.knotless.getPreferences and putPreferences), which also keep the theme you choose on the pages. They behave as before, but need an appview at this version or later. Notification settings made before this were not carried over: everyone starts from hearing every reason, from anyone.

Say why a private repository can't be made yet

knotless create --private, and the create_repo MCP tool with private, on a PDS without spaces now say that your PDS can't hold private repositories yet, rather than passing on its UpstreamFailure or MethodNotImplemented. Nothing is made.

Notifications from private repositories reach members who never logged in to the appview

Members of a private repository who use only the command line or MCP now hear of what is said there: a mention, a comment on their issue, a reply. Writing a pull, an issue, a comment, a review or a state to a private repository, or sharing one, now shows the appview the repository with a delegation token, so its index has what was written. Sharing a private repository to read now names the account in the record's new readers, which the appview takes as the owner's word that they may hear of it. Someone mentioned there who is not a member still hears nothing.

A merged pull's diff once its branch is gone

The MCP pull_diff tool on a merged pull answers what its merge brought in, from the commits its merge recorded, rather than failing once merging deleted its branch.

Pushes through a gateway are credited to whoever made them

A push or commit a collaborator or runner makes through a gateway names them as pusher on the claims and refs it writes, and the feed and activity pages credit it to them rather than to the repository's owner, while the repository lists them as a collaborator or runner.

A reverted pull names its revert

Once a revert pull merges, the pull it undid names it: knotless show says reverted by, as do the MCP show_item (item.revertedBy) and the pull's page. A merged pull's compare in show_item is what its merge brought in, even once its branch is deleted, and the MCP diff tool says when there are no differences rather than answering nothing.

Usage keeps who did what for 30 days

knotless-serve's usage counts (--usage) delete the accounts they noted for MCP, the gateway and the pages' logins once 30 days have passed, keeping only counts. In knotless admin stats, an event's accounts are of the days asked, at most the last 30, and a funnel starts with an account that had not done its first step in the 30 days before.

knotless 0.1.1 5092cd2

Features

Container images as releases

knotless publish --oci <dir> publishes an OCI image layout as a release, each blob named for its digest, and knotless-serve answers docker pull <host>/<owner>/<repo>/<package>:<version> from those releases at /v2/.

Agents publish and read releases

The MCP tools publish, releases and read_release publish a version of a package, list a repository's releases, and read one file of a release, as knotless publish, releases and download do.

Images can be pushed to knotless-serve's registry, which lists their tags

docker login with the owner's handle and an app password, then docker push to a version's tag, publishes the image as that version's release; tags/list lists an image's versions.

Releases as records

knotless publish publishes a version of a package from a repository, as dev.knotless.release records in its owner's account, never changed once made; knotless releases lists them and knotless download fetches and checks a version's files.

knotless-serve installs from a repository's releases

--releases knotless://<owner>/<name> serves /install.sh and /releases/ from that repository's releases of the knotless package, each file checked against its record and kept, rather than from a directory.

Fixes

Releases stream

knotless publish reads each file a part at a time as it uploads it, and knotless download writes each part as it reads it, beside the file until it is whole and checked, so a file of any size takes only a few parts' memory.

A runner's pass that runs long says where it is

knotless-run logs each pass over a repository as pass ended, with how long it took, and one still going after 5 minutes as pass running long, with the stage it is at, every 5 minutes. A git command slower than KNOTLESS_SLOW_MS is logged at warn, as git. The same failure of a repository is logged once a minute while it goes on, with a count, rather than every time.

knotless-serve's image is published as a release

Each new version's image is the release of the knotless-serve package: docker pull knotless.dev/chadtmiller.com/knotless/knotless-serve.