Skip to content

feat: add --append-only flag to protect files from overwrite - #175

Open
ErycM wants to merge 2 commits into
bitbonsai:mainfrom
ErycM:feat/append-only-flag
Open

feat: add --append-only flag to protect files from overwrite#175
ErycM wants to merge 2 commits into
bitbonsai:mainfrom
ErycM:feat/append-only-flag

Conversation

@ErycM

@ErycM ErycM commented Aug 5, 2026

Copy link
Copy Markdown

Split out of #162 as requested — the append-only piece only, rebased on current main (9748d7e). Reviewable and mergeable on its own (see the note on file overlap with #173 at the bottom).

Why

Some vault files are appended by more than one client — an operations log, a journal, a running changelog. write_note defaults to mode: "overwrite", so a client that read the file a minute ago, or an LLM that simply forgot to pass a mode, silently wipes everything appended since that read. There is currently no way to tell the server "this file is never overwritten wholesale".

What

  • Opt-in --append-only=log.md,journal.md. For those basenames, mode: "overwrite" is refused with a message pointing at append / prepend, which re-read the file server-side.
  • Threaded CLI → createServerFileSystemService (new optional 4th constructor arg).
  • Off by default. No flag, no behavior change — covered by a regression test.
  • Matches on basename, so both log.md and wiki/log.md are protected by one entry. That is deliberate for the log/journal use case; happy to switch it to path-relative matching (or support both) if you would rather it be explicit.

Tests

src/append-only.test.ts — refuses overwrite of a configured file (and the previous content survives), matches in nested folders, still allows append and prepend, leaves unconfigured files alone, no protection by default.
src/cli.test.ts — flag absent, trimming and empty entries, empty value, positional vault path preserved.

Full suite on this branch: 253 passed, 1 failed. The failure is src/shutdown.test.ts > stdio server exits on SIGTERM, which also fails on pristine main on this machine — a 500 ms boot race on a slow box, not introduced here. Same note as in #173 and #174.

End-to-end against the built dist/server.js, driven over real MCP stdio with --append-only=log.md:

write_note log.md   (append)    -> Successfully wrote note: log.md (mode: append)
write_note log.md   (overwrite) -> Error: Append-only file: log.md. Whole-file overwrite is
                                   disabled for this file (--append-only); use mode "append"
                                   or "prepend" instead.
write_note notes.md (overwrite) -> Successfully wrote note: notes.md (mode: overwrite)
log.md on disk                  -> "entry 1\n"

Commits

  1. feat: add --append-only flag to protect files from overwrite
  2. chore: rebuild dist — kept as its own commit, matching 5a293c6.

No website/ content changed (root README.md only).

One overlap worth flagging

Both this PR and #173 add src/cli.ts, because each needs a testable parser and neither should depend on the other landing first. They are independent in behavior, but whichever merges second will need a trivial rebase there — one flag constant, one parser function, one extra predicate in stripKnownFlags. Tell me which you want first and I'll rebase the other immediately.

ErycM added 2 commits August 5, 2026 11:36
Some vault files are appended by multiple clients (e.g. an operations log). A
client that reads such a file and then calls write_note with mode:overwrite
silently clobbers entries another client appended after that read - and
write_note defaults to overwrite, so an LLM that forgets the mode can wipe the
file wholesale.

Add an opt-in --append-only=<name,...> flag, threaded CLI -> createServer ->
FileSystemService. For the listed basenames, mode:overwrite is refused with a
message pointing to append/prepend, which re-read the file server-side. Off by
default, so existing behavior is unchanged. Parsing lives in a new src/cli.ts
so it is unit-testable without importing server.ts; adds src/cli.test.ts,
src/append-only.test.ts, and a README entry.

@bitbonsai bitbonsai left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ErycM, thanks again for splitting this out. I pulled the branch and ran it locally: all 254 tests pass, the build and audit are clean, and the configured overwrite guard works as intended.

I have three asks before merge:

  1. --append-only sounds like the file can only be appended to, but the implementation also allows prepend, patch, delete, move, and metadata changes. Could you please rename it to something that matches the actual guarantee, such as --no-overwrite, and make the README and paired website install docs clear that it blocks only write_note with mode: "overwrite"?
  2. Please make configured basenames case-insensitive, so protecting log.md cannot be bypassed as LOG.md on macOS or Windows.
  3. This should land after #174, since the protected append workflow relies on its serialization fix. Once #174 is merged, please rebase this branch, bump to the next available minor version, update the lockfile, and rebuild dist.

The core guard is useful. These changes would make the name and guarantee line up cleanly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants