Use the `formpatch` CLI for top-level Clojure object edits when the user explicitly wants Formpatch, when `formpatch` is already installed in the target environment, or when developing this repository itself. Prefer the installed `formpatch` command for other repositories; use `./bin/formpatch` only while working inside the Formpatch repo. Use it to list top-level objects, fetch full objects, insert new top-level forms, replace existing top-level forms, delete top-level forms, or explain the `oid` + optional `rev` + optional `file_rev` workflow used by Formpatch.
Use formpatch when Formpatch is the requested or available editing path for top-level Clojure edits. It is a fast Babashka CLI that treats a file as an ordered list of top-level objects. It supports:
list: inspect top-level objects with truncated text previewsget: fetch one or more full top-level objectsinsert: add one or more top-level objects before or after an anchor, or at the head/tail of the filereplace: replace one or more contiguous top-level objects with zero or more new top-level objectsUse whole-object rewrites. Do not try to patch inside a form with this skill.
./bin/formpatch.formpatch command and do not assume ./bin/formpatch exists.Each top-level object has:
oid: stable file-local object identity encoded as a 6-character base62 tokenrev: short hash of the current full object textfile_rev: short hash of the whole fileDefault behavior:
oid to target an object@rev when you want object-level optimistic locking--file-rev only when you need strict whole-file optimistic lockingThis means one list can often support multiple follow-up edits without re-listing, as long as the target object itself has not changed.
formpatch list --file <path> and inspect the returned JSON.oid; keep rev when you want a write guard.get for the target objects.--dry-run --diff before mutating.insert or replace.file_rev, touched, before, and after handles instead of re-listing immediately.list only when you need fresh discovery context, more full objects, or the mutation result does not give enough anchors.List top-level objects:
formpatch list --file src/foo/core.clj
Interpret the response as:
file_rev: current file versionoid: stable file-local 6-character base62 identityrev: optimistic lock for that objectindex: current position in the filetext: truncated preview texttext_truncated: whether the preview was truncatedhead / name: best-effort metadata for display and selectionFetch one or more full objects:
formpatch get \
--file src/foo/core.clj \
--objects <oid>,<oid>@<rev>
Insert new top-level forms with raw stdin.
Insert after an anchor object:
formpatch insert \
--file src/foo/core.clj \
--after <oid>@<rev> \
--dry-run \
--diff <<'EOF'
(defn helper-a
[]
:a)
(defn helper-b
[]
:b)
EOF
Remove --dry-run --diff to apply the edit.
Use --before instead of --after when needed.
Insert at the head of the file (no anchor needed):
formpatch insert \
--file src/foo/core.clj \
--head <<'EOF'
(ns foo.core)
EOF
Use --tail to append at the end of the file. Both --head and --tail work on empty files.
Successful insert returns minimal delta JSON including:
file_revtoucheddeletedbeforeafterdiffReplace one object by rewriting the full form:
formpatch replace \
--file src/foo/core.clj \
--targets <oid>@<rev> \
--dry-run \
--diff <<'EOF'
(defn updated
[x]
(inc x))
EOF
Replace one object with multiple objects by passing multiple top-level forms on stdin.
Replace multiple objects only when the target objects are contiguous in the current file.
If you need strict whole-file CAS, add --file-rev <file_rev>.
Delete with replace --empty:
formpatch replace \
--file src/foo/core.clj \
--targets <oid>@<rev> \
--empty
Delete multiple objects only when the target objects are contiguous.
Deletion returns the removed oids in deleted.
oid@rev for writes. Bare oid is convenient, but it will not protect you from overwriting a changed target object.oid as file-local. Do not assume it is globally unique across files or repositories.--file-rev only when you truly need strict whole-file locking; otherwise it reduces handle longevity.rewrite-clj work or another general editor when whole-object replacement is not sufficient or Formpatch is unavailable.--dry-run --diff before writing unless the change is trivial.stdin. Do not wrap replacement code in JSON strings.stdout for success and machine-readable JSON on stderr for failure.touched / before / after handles over an immediate extra list../bin/formpatch. Outside repo development, prefer the installed formpatch command and do not probe ./bin/formpatch first.