# Show HN: Slivingdoc, conflict-resolving notebook for agents w. S3 backend

> Source: <https://www.slivingdoc.dev/>
> Published: 2026-08-17 13:21:33+00:00

## Pull the notebook into a directory

`pull`

mcp:
notes_pull(path)
→ OK
cli:
`slivingdoc pull`

→ OK
reads the accepted state from the bucket — one small manifest
called `current`

, plus the immutable packs it
references — and writes the notebook into your directory as
ordinary UTF-8 text files.

The path picks a *checkout*, not a place inside the
notebook: any directory under the workspace root works, each one
mirrors the full notebook, and each remembers its own baseline —
what it last saw. Unpublished local edits are merged with the
accepted state, never overwritten.

The caller never sees Git object IDs, pack names, or S3 keys. The directory is the whole interface.

## Edit with ordinary file tools

Between calls there is no protocol at all. Agents — as many as you
like — read and write the files with the tools they already have:
a text editor, `sed`

, an LLM's file tools.

The notebook is directories and UTF-8 text files — binary files are rejected, never mangled. Bytes and line endings are preserved. slivingdoc does nothing until the next call.

As such, humans can work in the same directory: open the notebook in your editor and write alongside your agents. Its perfectly possible to use slivingdoc as a agent-free distributed notebook as well.

## Commit publishes your changes

`commit`

mcp:
notes_commit(path, message)
→ OK
cli:
`slivingdoc commit -m "note"`

→ OK
merges your files with the latest accepted state, packs the
result, and uploads the pack. Packs are immutable: uploading one
publishes nothing.

Your change is the delta since the checkout's baseline — so a path
that was never pulled is refused with
`INVALID_REQUEST`

before any network work. Pull once
first: commit publishes intent, not a guess.

Publication is a single conditional replace of the small
`current`

manifest — `If-Match`

on the ETag
the writer observed. The bucket is the durability boundary;
everything local is a rebuildable cache.

## Concurrent writers cannot clobber each other

Two agents commit at once. Both observed `current`

at
ETag `e1`

; S3 accepts exactly one replacement for it.
The loser gets a precondition failure — expected contention, not
an error.

The losing writer downloads what it missed, merges against the new head, and retries with a fresh proposal. No lock object, no lease, no clock. Accepted state is never silently overwritten.

## Conflicts are just text

When your change and an accepted remote change touch the same
lines, the call returns `CONTENT_CONFLICT`

and writes
standard conflict markers into the affected files. The structured
error names every file and marker line range.

Resolve with the same file tools you edit with: keep the text you
want, delete the marker lines, call
`notes_commit`

again. A complete marker block is never
accepted into the notebook.

## Checkpoints keep cold starts fast

Every commit uploads one small incremental pack. Left alone, that chain would make a fresh server download thousands of objects. So after a configurable count (1,024 by default), slivingdoc compacts the stable prefix into one complete-state checkpoint.

A new reader needs one checkpoint plus the short tail after it. Checkpoints never block writers, and a failed checkpoint never touches accepted state.
