Guarantees and limits

What slivingdoc guarantees, what stays the operator's job, how it behaves at each failure point, the notebook content rules, path security, and the credentials boundary.

slivingdoc promises current-state durability under concurrency. It does not promise historical recovery, and it is not a backup product. This page is the line between the two, and the rules your content has to obey to stay inside it.

What slivingdoc guarantees

  • Accepted state is durably indexed by one authoritative manifest.
  • A failed concurrent publication cannot silently overwrite accepted state.
  • Accepted packs are immutable.
  • A successful commit is durably referenced by current.
  • Merge conflicts do not advance remote state.
  • Checkpoint and cleanup failures do not corrupt current state.

notes_commit returns OK only after the server has proved that current accepted the proposal, or that a later manifest records its publication ID. It never reports success while acceptance is uncertain.

What the deployment owns

These are recovery policies, not hidden prerequisites of the synchronisation algorithm. Choose them according to your own recovery requirements:

  • bucket versioning
  • noncurrent-version retention
  • replication
  • object lock
  • backup export
  • recovery procedures
  • storage lifecycle policy

The bucket must already exist: slivingdoc does not create or configure it. See Set up a bucket and S3 requirements.

Failure guarantees

The publication order is load-bearing — local state, then the immutable pack, then the conditional replacement of current — and each interruption point has a defined outcome:

Failure point Guaranteed result
Before pack upload Remote state is unchanged.
During pack upload Remote state is unchanged.
After pack upload, before CAS The pack is an unreferenced proposal.
Pack upload response lost Read the unique key and validate SHA-256 and size.
CAS precondition failure Another writer won. Merge and retry.
CAS response lost Read current and search for the publication ID.
Merge conflict Remote state is unchanged. The visible directory is rewritten with the merge and markers.
Retry exhaustion The remote result is not reported as success. Caller files remain available.
Checkpoint failure Accepted notebook state is unchanged.
Cleanup failure Accepted notebook state is unchanged. Obsolete storage remains.
Corrupt pack or checksum Refuse the import and report a storage-integrity error.

There is one more case that no table of interruption points can cover: an unexpected failure after local mutation has already started. There is no bespoke recovery algorithm per interruption. Instead the operation stops its normal work, reports RECOVERY_FAILURE, and tries to reconstruct the private state and the visible directory from the authoritative current. The error names the failed stage, whether remote acceptance is known (yes, no, or unknown), and whether resynchronisation succeeded. A successful repair does not turn the anomalous call into OK.

Warning: Recovery can replace the visible directory, because that directory is not a durability boundary. The error says so candidly. If immediate repair is impossible, the private state records that recovery is required, and the next call must resynchronise from current before it does any new work.

Concurrency and scaling

One notebook has one ordered accepted state, so the current object is the final serialisation point. Merge work, pack creation, uploads, and downloads all happen concurrently; the conditional write is the only serialised publication action.

The planning workload V1 is designed around is:

100 agents
one commit per agent per minute
approximately 1 kB of new note content per commit

That is roughly 1.67 accepted commits per second. V1 does not promise a fixed throughput before benchmarks run against the intended S3 service; what the architecture does promise is the absence of quadratic full-history uploads and long writer critical sections.

Throughput past that depends on your note layout, not on the storage:

  • Changes to separate files usually merge with no caller action.
  • Frequent overlapping changes to one file create semantic conflicts that no storage layer can remove.
  • Prefer many focused files over one global append file. slivingdoc does not enforce agent namespaces; a convention such as one directory per agent is yours to set, and path policies can enforce it.

Notebook rules

The notebook holds directories and regular UTF-8 text files, and nothing else:

  • Files must be valid UTF-8 text without the NUL character (U+0000). Empty files are valid. Bytes and line endings are preserved, and text is not normalised.
  • Symbolic links, devices, sockets, and named pipes are rejected, as are hard-link semantics. A hard-linked regular file is read as an independent path, and a rewrite does not preserve the link.
  • Executable bits and other platform-specific modes are not notebook state; slivingdoc writes one normal file mode.
  • Empty directories are not notebook state, because Git does not store them. Materialisation creates the parent directories it needs and removes obsolete empty ones.
  • Binary files, and anything else that fails the text rule, are not notebook state.

Path names are portable by construction, so one accepted notebook works on every supported host. Each internal path is valid UTF-8 in Unicode NFC form, uses / separators, and is at most 4,096 UTF-8 bytes. Each segment is 1 to 255 UTF-8 bytes, contains no control character and none of /\:*?"<>|, and does not end in a space or a dot. The names ., .., .git, Windows device names, and names that collide under Unicode case folding are all rejected.

The request and message bounds are:

Input Rule
MCP request path Optional. Omitted or empty means the server’s notebook directory, which every result reports. May begin with ~/, which expands to the current user’s home directory. The resulting absolute host path is 1 to 4,096 bytes and must be at or below the workspace root.
Subcommand path Optional, and may be relative: it resolves against the working directory before the same root rule applies.
Commit message Non-blank UTF-8 without U+0000, at most 16,384 bytes. A message of only Unicode white space is rejected; every other message is preserved byte for byte. Retained in recent internal history only.

Finally, one content rule exists purely to protect you from yourself: a complete conflict-marker block — the exact lines <<<<<<< local, =======, and >>>>>>> remote at column zero, in that order — is never accepted into the notebook, even when you wrote it by hand. The rule survives a process restart and will reject a literal marker example in a document; change one character of one signature line and the block is ordinary text again. See Resolve conflicts.

Path security

Every request path goes through the same rules:

  • canonicalise the requested path
  • require it to stay below the configured workspace root
  • reject symlink traversal in every existing path component
  • reject special files during scans
  • avoid following links during replacement and cleanup
  • use private directories that callers cannot select

Filesystem access uses root-relative operations rather than a check-then-open sequence, so an existing or newly substituted symlink component cannot escape the root. A configured read-only or writable entry obeys the same path rules as any other notebook path and is validated at startup, so a malformed entry refuses startup instead of silently protecting nothing.

The visible directory keeps its identity for the lifetime of the workspace: slivingdoc creates it when missing and thereafter only changes its contents — it never renames it aside, replaces it, or removes it, so a working directory, an open editor, and a file watcher all stay valid. Individual files are replaced through a temporary file renamed over the target, so each file changes atomically.

Note: A path policy is a guardrail at the MCP tool boundary, not a security boundary against the agent. The serve process holds the S3 credentials, so an agent that can read that environment or start its own slivingdoc process bypasses the setting — the same model as an operator’s sftp configuration, where the policy lives in the server configuration and never in the data.

The credentials boundary

slivingdoc has no authentication layer of its own. Credentials come from the AWS SDK default credential chain, resolved at startup, and the tool’s own flags shape only where the client points — --bucket, --prefix, --region, --endpoint — never who it is. No flag carries a credential, and an --endpoint URL containing user information is refused outright, so a secret cannot echo into a diagnostic.

Credentials stay inside the process. They never cross the MCP protocol: the client sees only notes_pull, notes_commit, and their result envelopes. A redaction layer keeps key material, S3 keys, private paths, and Git object IDs out of every error and log line as defence in depth. Connect an MCP host covers the three ways to deliver credentials to the process.

Outside V1

Some things are deliberately not here, and are not planned for this version:

  • byte-based checkpoint thresholds
  • multi-level pack compaction
  • multiple independently ordered notebook partitions
  • permanent or configurable logical history
  • a public backup and restore API
  • an administrative status API
  • remote file-editing tools
  • Windows arm64 artifacts
  • a public Go SDK

There is also no Git executable dependency, no public Git remote, no writer lock or lease object in S3, and no branch, tag, ref, revision, checkout, or rollback API. The supported programmatic interface is MCP; the CLI mirrors the same two operations for humans.

Next

  • Storage model — the manifest, packs, checkpoints, and cleanup.
  • Errors — every code and reason, and what to do about each one.
  • S3 requirements — the permissions and guarantees a store must provide.

Last updated September 21, 2026

Type to search the documentation.