How collaboration actually works
What is shared, what stays yours, and where the boundary is enforced.
Understanding what's atomic, what's trust-based, and what to expect when two people touch the same thing.
Live push (SSE)
When you launch rememd in remote mode, it opens a long-lived GET /events connection. The backend publishes change notifications on an in-memory bus; every connected client gets them. The client filters by the workspaces the user can see, then invalidates its index cache and reloads that workspace's index.
Events currently emitted:
workspace_changed- the blob's version bumped (index PUT).task_claimed/task_released- a task's claim state flipped.agent_run_started/agent_run_released/agent_run_finished- an unattended run took, dropped or reported back on a task. Separate from thetask_*pair on purpose: a person picking work up and a machine writing against it are not the same event.agent_run_outcome- what became of the pull request a finished run left: merged, or closed unmerged. The oneagent_run_*event published while nothing is running.presence_changed- someone connected or disconnected; payload lists the currently-online user IDs.
When dev B logs a session, edits a PRD, or claims a task, your view updates without a refresh click.
Task claim/release (server-enforced)
Claim is atomic: the server locks the blob row, checks no one else holds the task, writes assigneeUserId + claimedAt + assignee, bumps the version. If another user already holds it → 409 Conflict. Only the holder (or an admin) can release → 403 Forbidden otherwise.
In the UI: right-click a task. The context menu shows Claim task, Release task, or "Claimed by <name>" depending on state. Admins get a Force release (admin) option on any claimed task.
PRD / session-body writes (optimistic lock)
Each content document has its own version counter. When you save a PRD, the client PUTs with the version it last saw. If the server's at a newer version (someone edited in between):
- The client fetches the server's current body.
- Throws a
DocumentConflictcarrying both bodies. - The app shows a three-button alert: Keep mine (overwrite), Discard mine (reload server), Cancel.
No silent overwrite, no silent last-write-wins. You always know when there's a conflict.
Workspace-index writes (optimistic lock + silent retry)
Index-level writes (creating a feature, adding a session metadata, claiming a task - anything that touches the blob) use the same optimistic-lock pattern but with a one-shot silent retry. For small metadata edits this is fine; for blob-level conflicts affecting content, the document-level conflict mechanism above catches the important cases.
Presence
A small green dot overlays the avatar when a teammate currently has rememd open and connected to this backend. Not full "they're viewing this feature right now" - just "they're online."
Author attribution
Notes and session events stamp authorUserId automatically when saved through RemoteStorage. In work-mode, the session timeline shows a colored avatar beside each event's timestamp, indicating who logged it. Hover to see the name.
Repo paths are per-user (important!)
rememd used to store absolute paths like /Users/dev-a/.../some-repo inside the workspace blob, which meant dev B's rememd would try to use your paths - and fail. As of the dockerlayer branch, paths live in each user's ~/.recall/repo-map.json, keyed by the shared focus-area / feature UUIDs.
Practically:
- Each teammate
git clones wherever they want on their disk. - Nothing about that path is shared with anyone.
rememd connectand the cwd-based commands (rememd note,rememd log) need the user to register their clone once:rememd link focus-area <name> <path>.- Pure CLI workflow (
rememd ls,task claim,watch,prd edit) needs no path setup at all.
Legacy blob-stored paths still decode as fallback, so pre-refactor data doesn't break. The migration into your local map happens automatically on first launch: any path in the blob that exists on your disk gets copied into your local map; paths that don't exist on your disk are ignored (they belong to someone else).