Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Effectful-Tech/clanka/llms.txt

Use this file to discover all available pages before exploring further.

The ApplyPatch module provides the applyPatch tool that Clanka agents call to modify files. It accepts two patch formats — standard git/unified diffs and the wrapped apply_patch format — and validates every hunk against the current file contents before writing anything to disk.

applyPatch(patchText)

Agents call this function from within their JavaScript sandbox:
await applyPatch(patchText: string): Promise<string>
patchText
string
required
A patch string in one of the two supported formats (git/unified diff or wrapped apply_patch). Heredoc syntax (cat <<'EOF' … EOF) is automatically stripped before parsing.
return
string
A success message listing every file that was modified, for example:
Success. Updated the following files:
M src/foo.ts
A src/bar.ts
Status letters follow git conventions: M for modified, A for added, D for deleted, R for renamed/moved.
applyPatch is atomic. All hunks are matched against the existing file contents before any file is written. If any hunk fails to locate its context lines the entire patch is rejected and no files are changed.

Supported patch formats

Git / unified diff

The standard format produced by git diff or diff -u. Each file section starts with diff --git, ---, and +++ headers.
diff --git a/src/foo.ts b/src/foo.ts
--- a/src/foo.ts
+++ b/src/foo.ts
@@ -10,7 +10,7 @@ export function greet(name: string) {
-  return `Hello, ${name}`
+  return `Hello, ${name}!`
 }
A single patch string may contain hunks for multiple files. Rename/move operations are expressed with rename from / rename to headers or by supplying different --- and +++ paths.

Wrapped apply_patch format

A custom envelope used by agents that prefer explicit file directives:
*** Begin Patch
*** Add File: src/bar.ts
+export const bar = 42
*** Update File: src/foo.ts
@@ -10,7 +10,7 @@
-  return `Hello, ${name}`
+  return `Hello, ${name}!`
*** End Patch
Supported directives inside the envelope:
DirectiveEffect
*** Add File: <path>Create a new file with the lines that follow (prefixed +).
*** Delete File: <path>Remove the file entirely.
*** Update File: <path>Apply hunks to an existing file.
*** Move to: <newpath>Rename the file after applying hunks (placed after *** Update File:).
The wrapped format supports multiple file sections in one patch block, unlike the single-file parseWrapped helper used internally.

Rename and move support

Files can be moved or renamed as part of a patch. In git diff format use rename from / rename to headers or different ---/+++ paths. In the wrapped format add *** Move to: <newpath> immediately after *** Update File: <path>. The parsed result carries the destination in the movePath field of a FilePatch:
export type FilePatch =
  | { readonly type: "add";    readonly path: string; readonly content: string }
  | { readonly type: "delete"; readonly path: string }
  | {
      readonly type: "update"
      readonly path: string
      readonly chunks: ReadonlyArray<Chunk>
      readonly movePath?: string   // set when the file is also renamed/moved
    }

Low-level API

These exports are available for tooling or testing outside of an agent context.

parsePatch(input)

Parse a patch string into an array of FilePatch objects without touching the filesystem.
export const parsePatch = (input: string): ReadonlyArray<FilePatch>
input
string
required
A patch string in either supported format. Whitespace normalisation and heredoc stripping are applied automatically.
return
ReadonlyArray<FilePatch>
An ordered list of file operations to apply. Throws Error if the patch is empty, malformed, or contains no hunks.

patchChunks(file, input, chunks)

Apply a pre-parsed list of Chunk objects to a file’s string content and return the updated content. Used internally by parsePatch and exposed for testing.
export const patchChunks = (
  file: string,
  input: string,
  chunks: ReadonlyArray<Chunk>,
): string
file
string
required
The file path, used only in error messages when a hunk cannot be located.
input
string
required
The current file content as a string.
chunks
ReadonlyArray<Chunk>
required
The parsed hunks to apply.
return
string
The updated file content. Line endings are preserved (CRLF files remain CRLF).

Chunk type

export type Chunk = {
  readonly old: ReadonlyArray<string>   // lines to find in the file
  readonly next: ReadonlyArray<string>  // lines to replace them with
  readonly ctx?: string                 // optional anchor context line
  readonly eof?: boolean                // hint: match at end of file
}
Hunk matching falls back through four strategies in order: exact, trailing-whitespace-stripped, fully-trimmed, and Unicode-normalised-trimmed. This makes patches tolerant of minor whitespace drift.

Example patches

Modify an existing file (git diff)

diff --git a/src/utils.ts b/src/utils.ts
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -1,5 +1,6 @@
 export function add(a: number, b: number) {
-  return a + b
+  const result = a + b
+  return result
 }

Add and update files (wrapped format)

*** Begin Patch
*** Add File: src/logger.ts
+export const log = (msg: string) => console.log(`[clanka] ${msg}`)
*** Update File: src/index.ts
@@ -1,3 +1,4 @@
+import { log } from "./logger"
 import { run } from "./runner"
 
 run()
*** End Patch

Move a file while patching it (wrapped format)

*** Begin Patch
*** Update File: src/old-name.ts
*** Move to: src/new-name.ts
@@ -2,4 +2,4 @@
-export const VERSION = "1.0.0"
+export const VERSION = "1.1.0"
*** End Patch

Build docs developers (and LLMs) love