Skip to content

feat: folder operations (change 0012)#6

Open
fx wants to merge 3 commits into
mainfrom
feat/folder-operations
Open

feat: folder operations (change 0012)#6
fx wants to merge 3 commits into
mainfrom
feat/folder-operations

Conversation

@fx

@fx fx commented May 25, 2026

Copy link
Copy Markdown
Owner

Summary

Plans the folder-operations surface that the file API is missing today. Spec + change doc only in this commit — implementation will land on the same branch after docs review.

  • New tools/routes: list_folders, create_folder, delete_folder on both REST (/v1/vaults/:slug/folders[*path]) and MCP, sharing a new src/vault/folders.ts service-core module.
  • Motivated by the live vault: 20 of 34 first-level folders under social-graphs/people/ (e.g. peter-thiel/) are empty leaves preserved by Obsidian Sync but invisible to list_files (which only emits Dirent.isFile()). No upstream sync setting purges them — confirmed against Obsidian's sync settings docs.
  • Adds one new error code, folder_not_empty (409), surfaced when DELETE /folders/*path is called without ?recursive=true against a non-empty folder.

What's in this commit

  • docs/changes/0012-folder-operations.md — full change doc (requirements, scenarios, tasks, decisions).
  • docs/specs/rest-api/index.md — new ### Folder CRUD section + closed-set error code extension + changelog row.
  • docs/specs/mcp-server/index.md — three new tool rows + description guidance + changelog row.
  • docs/index.{yml,md} — index entries for change 0012.

Decisions worth flagging

  • Folders are a separate surface, not a includeFolders: true flag on list_files. Keeps types clean and tool descriptions actionable.
  • create_folder is idempotent (mkdir -p semantics); creating a folder where a file already lives returns invalid_path.
  • delete_folder refuses non-empty folders by default; recursive: true is required to opt in. Recursive delete walks the subtree, calls indexer.drop (best-effort, chokidar reconciles) for every Markdown descendant, then fs.rm.
  • Move/rename, bulk ops, and MCP resource URIs for folders are out of scope for this change.

Test plan

  • Spec review: confirm Folder CRUD section reads as the canonical surface
  • Confirm folder ops being a separate surface (not a flag on list_files) is the right shape
  • Confirm folder_not_empty (409) is the right code/status for the non-recursive refusal
  • Once docs are approved, implement per the task list in 0012; same branch, follow-up commits

Add list_folders / create_folder / delete_folder on REST and MCP so empty
folders (invisible to list_files today) are reachable. Motivated by ~20/34
empty leaves under social-graphs/people/ on prod that ob sync preserves
but the API hides. Introduces a new folder_not_empty error code (409).

- Adds docs/changes/0012-folder-operations.md
- Extends docs/specs/rest-api/index.md with the Folder CRUD section and
  the new error code in the closed set
- Extends docs/specs/mcp-server/index.md tool surface with the three
  new tools
- Updates docs/index.{yml,md}

Implementation follows on this same branch.
Copilot AI review requested due to automatic review settings May 25, 2026 01:30
@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2d6133d6-1085-4d2f-b2d4-9ef8736f7638

📥 Commits

Reviewing files that changed from the base of the PR and between 3856260 and 1c91350.

📒 Files selected for processing (1)
  • docs/changes/0012-folder-operations.md

📝 Walkthrough

Folder Operations Specification (RFC/Change Doc)

Adds spec and change docs for folder CRUD across REST and MCP; implementation to follow on the same branch.

Key Additions

  • REST endpoints under /v1/vaults/:slug/folders:
    • GET — list folders (cursor/prefix/limit, deterministic pre-order, no vault-root, symlinks/dotfolders/.obsidian/.trash omitted)
    • PUT — create folder (idempotent, mkdir -p semantics; creating where a file exists → invalid_path)
    • DELETE — remove folder (204 on success; defaults to refusing non-empty folders with 409 folder_not_empty; ?recursive=true walks subtree, best-effort indexer.drop for Markdown descendants, then fs.rm with force:false)
  • MCP tools: list_folders, create_folder, delete_folder (mirror REST shapes; delete_folder parity { deleted: boolean })
  • Service-core surface: src/vault/folders.ts exposing listFolders, createFolder, deleteFolder (folder-only semantics)

Errors

  • New closed-set error: folder_not_empty → HTTP 409
  • invalid_path for file-vs-folder conflicts; not_found / vault_not_found preserved

Decisions & Constraints

  • Folders are a separate surface (not a list_files flag)
  • Path validation: safeJoin + symlink-escape checks; trailing-slash canonicalization; empty-path routing rejected; hidden/reserved segments rejected
  • create_folder is idempotent; creating where a file exists errors
  • delete_folder refuses non-empty folders by default; recursive delete best-effort drops Markdown descendants from indexer then removes tree; indexer.drop failures are non-fatal; fs.rm uses force:false
  • Out of scope: move/rename, bulk ops, per-folder metadata/permissions, MCP folder resource URIs

Files Changed (docs/spec-only)

  • docs/changes/0012-folder-operations.md — full change doc (+334/-0)
  • docs/specs/rest-api/index.md — Folder CRUD section, error code, changelog (+62/-2)
  • docs/specs/mcp-server/index.md — added tool specs (+6/-0)
  • docs/index.md — change table entry (+1/-0)
  • docs/index.yml — change registry entry (+7/-0)

Tests & Implementation Notes

  • Spec lists tests: spec review, design confirmations, then implementation tests (service-core and adapter tests, tmpdir-based integration, path-traversal/race assertions). Indexer.drop is best-effort and non-blocking during recursive delete.

Walkthrough

Adds a draft "Folder Operations" change document and updates REST and MCP specs and documentation indexes to define list/create/delete folder semantics, error codes (including folder_not_empty), path validation, and an implementation checklist.

Changes

Folder Operations Specification and Integration

Layer / File(s) Summary
Folder Operations specification document
docs/changes/0012-folder-operations.md
Comprehensive specification defining service-core folder APIs, pre-order traversal with cursor/prefix/limit parity, idempotent mkdir -p-style creation with file-vs-folder conflict handling, non-recursive folder_not_empty refusal, recursive deletion that enumerates Markdown descendants and performs best-effort indexer drops, path validation rules, design decisions, non-goals, and an implementation checklist.
REST API specification integration
docs/specs/rest-api/index.md
Adds GET /v1/vaults/:slug/folders (cursor pagination, deterministic pre-order traversal, omission rules), PUT create (idempotent, 400 if path is a file), and DELETE (non-recursive 409 folder_not_empty vs recursive=true with Markdown index cleanup). Expands file-list omission rules to exclude symlinks and adds folder_not_empty to the closed-set error codes; updates changelog.
MCP server specification integration
docs/specs/mcp-server/index.md
Adds list_folders, create_folder, and delete_folder tools with input/output contracts matching REST, documents empty-folder visibility, mkdir -p idempotency, invalid_path when a file exists at the path, folder_not_empty behavior unless recursive: true, and updates changelog.
Documentation index updates
docs/index.md, docs/index.yml
Inserts change 0012 folder-operations into the docs index, linking the new change doc and marking the rest-api spec entry as draft with dependencies on 0004 and 0005.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I nibble at specs in moonlit hops,
Where empty folders hide like crops.
REST and MCP now share a tune,
So folders wake beneath the moon. 🐇📂

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: folder operations (change 0012)' accurately summarizes the main change—adding a new Folder CRUD surface with documentation and specifications.
Description check ✅ Passed The description is well-related to the changeset, explaining the motivation for folder operations, listing all modified files, and documenting key design decisions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds the design/spec documentation for Change 0012 (“folder operations”), defining a new folder CRUD surface on both REST and MCP so empty folders (which are currently invisible via file listing) are discoverable and manageable.

Changes:

  • Added a REST API “Folder CRUD” section including semantics for listing/creating/deleting folders and a new folder_not_empty (409) error.
  • Extended the MCP tool surface with list_folders, create_folder, and delete_folder entries mirroring the REST folder routes.
  • Registered Change 0012 in the docs indexes and introduced the new change doc with requirements, scenarios, and an implementation task list.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
docs/specs/rest-api/index.md Adds Folder CRUD spec + new error code + changelog entry.
docs/specs/mcp-server/index.md Adds the three new folder tools + description requirements + changelog entry.
docs/index.yml Adds change 0012 metadata entry (draft).
docs/index.md Adds change 0012 row to the changes table (draft).
docs/changes/0012-folder-operations.md New change doc describing motivation, requirements, scenarios, and task checklist for implementation.

Comment thread docs/specs/rest-api/index.md Outdated
Comment thread docs/specs/rest-api/index.md Outdated
Comment thread docs/specs/rest-api/index.md Outdated
Comment thread docs/specs/mcp-server/index.md Outdated
Comment thread docs/changes/0012-folder-operations.md Outdated
- Replace `list_files` references in the REST spec with the REST endpoint
  name (`GET /v1/vaults/:slug/files`) since `list_files` is the MCP tool.
- State symlink omission explicitly in `GET /v1/vaults/:slug/files` so the
  spec is internally consistent with the folder-listing rule that points to it.
- Spell out both folder routes in the rest-api changelog row instead of
  the ambiguous `[*path]` bracket notation.
- Align `delete_folder` output with `delete_file`: `{ deleted: boolean }`
  in both mcp-server spec and 0012.
- Tick the "Spec changelog rows" and "Docs index updates" task boxes
  since those landed in the same PR.
@fx

fx commented May 25, 2026

Copy link
Copy Markdown
Owner Author

@CodeRabbit full review

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/changes/0012-folder-operations.md`:
- Around line 17-23: The fenced code block containing the two kubectl shell
commands (the block that begins with "$ kubectl -n ob exec deploy/ob -- sh -c
'find /data/vaults/...") is missing a language tag; update the opening fence to
include "bash" so the block reads ```bash to satisfy MD040 and markdown linting
(no other content changes).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 476193fe-10d4-491b-8b7e-657dd6f55f80

📥 Commits

Reviewing files that changed from the base of the PR and between 5210644 and 3856260.

📒 Files selected for processing (5)
  • docs/changes/0012-folder-operations.md
  • docs/index.md
  • docs/index.yml
  • docs/specs/mcp-server/index.md
  • docs/specs/rest-api/index.md

Comment thread docs/changes/0012-folder-operations.md Outdated
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