Skip to main content
Refactoring restructures the knowledge base in one step. You describe the change in a manifest (moves, merges, splits, frontmatter edits, tag renames), KiwiFS builds a plan that shows every page that moves and every link it respells, and applying the plan writes everything as a single git commit. Every wiki link and markdown link that resolved before still resolves to the same page afterwards, and comments and personal state follow the pages they belong to. A commit can be reverted the same way. Use this instead of looping over rename calls: one plan, one review, one commit.
1

Plan

Send the manifest to POST /refactor/plan. Nothing is written. Review the moves, link edits, errors, and warnings, and keep the digest.
2

Approve (agents only)

If an agent’s plan exceeds the workspace’s size limits, a human reviews it in GET /refactor/pending and approves it by digest.
3

Apply

Send the same manifest and the digest to POST /refactor/apply. If any affected file changed since you reviewed, nothing is written and you get the fresh plan back.
4

Revert

Pass the returned commit to POST /refactor/revert to undo it as a new commit.

The manifest

A manifest is YAML or JSON. Unknown keys are an error, so a typo can’t silently drop part of a restructuring. It needs at least one of moves, merges, edits, rename_tags, relinks, or split.
manifest.yaml
Each entry has from (a file, a folder ending in /, or a glob) or from_regex, plus to. A to ending in / is a destination folder that keeps each file’s name.
from is deleted and everything that pointed at it now points at into. The body of into is left as it is, so write the combined page first, then merge.
select picks pages by paths, glob, and/or query (a DQL WHERE expression). At least one criterion is required; use glob: "**" for everything. Then, in order: when (an expression that filters the selection), set, compute (keys set from expressions such as slug(title)), unset, add_tags, remove_tags, replace (find, with, optional regex), and move_to (a destination template such as archive/{{year}}/{{slug}}.md). on_conflict is error (default) or suffix("-%d"). force lets the edit change frontmatter keys owned by another field manager. Selection always sees paths as they were before the manifest.
Renames a tag in frontmatter tags lists and inline #tags.
Breaks a page into one page per heading. Fields: from, level (default 2), into (default: a folder named after the page), and confirm. A split stays plan-only until confirm: true.
delete_empty_dirs: true removes folders the plan leaves empty. now pins the clock that when, compute, and move_to expressions see; pass back the plan’s now to apply exactly what you reviewed.
Workspace rules live in the [refactor] section of .kiwi/config.toml: approval_files and approval_links (agent plans above these sizes need approval; 0 means the defaults of 50 files and 200 links, -1 turns the check off), protect (globs no plan may touch), and scope (the only folder plans may touch). Plans also refuse to move pages another actor has claimed.

Preview a plan

Build the plan for a manifest without writing anything.
object
required
The request body is the manifest itself, as YAML or JSON (1 MB limit).
boolean
default:"false"
Add a diffs array with a unified diff for every written page.
string
workspace-edit returns the plan as an LSP WorkspaceEdit instead, for editors.
string
Who will apply the plan. Pages claimed by anyone else can’t be moved.
string
default:"rest"
Names the calling tool in the plan and the commit trailers. Values starting with mcp are treated as agents for approval.
Returns 400 if the manifest can’t be parsed or is empty. A plan with problems still returns 200; check errors. With format=workspace-edit, a plan with errors returns 422 with error and plan.
string
Identifies this exact plan. Pass it to apply.
object[]
Every path that moves, as from and to.
object[]
Every merged page, as from and to.
object[]
Pages whose links are rewritten.
object[]
Pages changed by edits or rename_tags: path, from, and a changes list.
object[]
Comment files migrated, as from and to.
object[]
Personal-state files updated: file, changes, conflicts.
string[]
Folders removed because they end up empty.
object[]
Each split page (from) and the pages it becomes.
string[]
Problems that block apply. A plan with errors can’t be applied.
object[]
The subset of errors that concern one page (path, error). Drop those pages and plan again to proceed.
object[]
Destinations that can’t be used, by code: exists, many_to_one, case_or_normalization, forbidden_chars, too_long, trailing_dot_or_space, empty_name, dir_cycle, parent_is_file, or is_folder. Each entry has path, detail, and optionally from and with.
string[]
Why a valid plan can’t be applied yet, such as an unconfirmed split.
string[]
Non-blocking issues worth reading before applying.
object
For agent callers: required and reason.
object
Link health after the plan: unresolved (links that already pointed nowhere), orphaned (pages that lose all inbound links), and complete (false when the plan didn’t read every page).
string
The clock the manifest’s expressions used, if any.
string
Git HEAD when the plan was built.
object
Counts: pages, links, rewritten, unresolved.

Apply a plan

Rebuild the plan for a manifest and apply it as one commit.
object
required
The same manifest you planned, as JSON.
string
Digest of the plan you reviewed. If set and the workspace changed since, nothing is written. Strongly recommended.
boolean
For agent clients: the user confirmed this plan (for example through MCP elicitation).
string
Commit author.
string
default:"rest"
Calling tool. Values starting with mcp must have approval for plans over the workspace’s limits.
object
What changed.
object
The plan that was applied.

Revert a commit

Undo a commit as a new commit. Every page the commit changed goes back to its previous bytes, and comment and personal-state files a restructuring rewrote go back too. It works on any commit, not only refactors.
string
required
Commit ID to revert.
boolean
default:"false"
Return the revert plan without applying it.
string
Digest of the revert plan you reviewed with dry_run.
string
Commit author.
With dry_run, the response is the revert plan (same shape as a plan, with reverts set to the commit). Otherwise it is applied and plan, as for apply. Returns 400 for a missing or invalid commit ID, 409 if the digest no longer matches or a file changed while applying, 422 if any affected file changed since the commit (a revert never discards later work), and 501 when git versioning is off.

Approve a plan for an agent

Record a human’s approval of a plan so an agent can apply it once within the next hour, even though it exceeds the workspace’s approval limits.
object
required
The manifest being approved.
string
required
Digest of the plan being approved.
The manifest is planned again. Returns 400 if either field is missing, and 409 with the fresh plan if the plan has errors or no longer produces that digest.

List plans waiting for approval

Return the plans agents tried to apply that exceed the workspace’s approval limits.
object[]

Compute a manifest with a script

Run a Starlark (Python-like) program that returns a manifest, for selection logic too irregular for globs, DQL, and expressions. Nothing is written; apply the result with apply.
string
required
Starlark source. Return the manifest from main() or set a global manifest. Available functions: query(dql), files(glob="**"), read(path), frontmatter(path), links(path), slug(text), json.encode, json.decode, and print (captured).
string
Who will apply the plan.
The script runs in a separate read-only process with no while loops or recursion, and is bounded by steps, memory (256 MB), and time (30 seconds). Returns 400 for an empty script and 422 if the script fails or returns an invalid manifest.
object
The manifest the script returned.
string
What the script printed.
object
The plan for that manifest.

Plan an editor’s file renames

Turn an LSP WorkspaceEdit (an editor’s rename refactoring) into a manifest and plan it. Only the file renames are kept; text edits are ignored and recomputed by the planner.
object[]
LSP document changes. rename entries (oldUri, newUri) become moves.
object
LSP text edits by URI. Ignored.
Returns 400 if a rename points outside the knowledge base or the edit renames no files.
object
The manifest built from the renames.
object
Its plan.
string[]
Parts of the edit that were not used, and why.

List moves that left references behind

Return moves made without relinking (WebDAV or NFS renames, renames with link updates turned off, or files moved on disk while the server was watching) whose old paths are still referenced, plus a relinks manifest that repairs them. Plan and apply that manifest like any other.
object[]
object
A manifest with relinks that repairs the references.
Return every wiki link that doesn’t resolve to an existing file, with the best fuzzy match when there is one.
object[]
integer
Number of broken links.

List orphan pages

Return pages that no other page links to.
Rewrite broken wiki links to their best fuzzy match: an exact path, then a path-suffix match (ignoring numeric folder prefixes such as 06-), then a matching file name. Links with no match are left alone.
boolean
default:"false"
Report the fixes without writing. Also accepted as a dry_run=true query parameter when there is no JSON body.
string
Commit author.
Unlike apply, each fixed page is written as its own commit.
object[]
Each fix: source, old_target, new_target.
integer
Number of fixes.
boolean
Whether anything was written.

MCP equivalents

kiwi_refactor_plan, kiwi_refactor_apply, kiwi_refactor_script, and kiwi_refactor_revert cover plan, apply, script, and revert. Over MCP, plans larger than the workspace’s limits ask the user to confirm, or wait for approval in the web UI if the client can’t ask. Approve, pending, raw moves, workspace edits, and the link-health endpoints are REST-only.

Wiki links

How links resolve, and why moves keep them working.

Files

Single-file rename and directory rename.

Claims

Claimed pages can’t be moved by other actors.

MCP tools

The refactor tools agents use.
Last modified on October 19, 2026