Reference

Command behavior, addressing rules, workflow flags, and examples for day-to-day use.

$ etch help

Common Commands

etch mutates structured files and commits each successful mutating invocation.

The table shows common invocation forms, not every accepted flag placement or advanced format-explicit command. Follow the linked topics for behavior details, or use etch help --all for the full command index.

Core structured edits

Common formsClassDescription
idempotentSet JSON/YAML/frontmatter or Markdown inline fields.
idempotentDelete a file or selected JSON/YAML/frontmatter/inline-field value.
non-idempotentAppend a value to an array, or a JSONL record to .jsonl/.ndjson.
idempotentEnsure an array contains a value.
idempotentEnsure an array does not contain a value.

Markdown sections and lists

Common formsClassDescription
idempotentReplace the body under one Markdown heading.
non-idempotentAppend a block fragment under one Markdown heading.
non-idempotentPrepend a block fragment under one Markdown heading.
idempotentEnsure one Markdown task is closed.
idempotentEnsure one Markdown task is open, creating it when a destination is addressed.
non-idempotentAdd one open Markdown task.
non-idempotentAdd one Markdown list item.

Tables

Common formsClassDescription
idempotentSet CSV or Markdown table cells.
non-idempotentAppend a CSV or Markdown table row.
non-idempotentInsert a CSV or Markdown table row.
idempotentDelete table rows.
idempotentEnsure a table column exists.
idempotentRename a table column.
idempotentEnsure a table column is absent.

Files

Common formsClassDescription
idempotentCreate a new file; omitted content uses an extension-aware default.
idempotentReplace an existing file's entire content.
idempotentMove a file path.
idempotentCopy a file path.

Guards

Common formsClassDescription
guardGuard that a path exists in the admitted input view.
guardGuard that a path is missing in the admitted input view.
guardGuard that admitted file bytes contain a literal.

Agent setup

Common formsClassDescription
introspectionPrint agent setup or durable context prompts.
$ etch help model

Model

Mutating invocations plan from HEAD and commit as one transaction.

For tracked paths, etch reads base-tree bytes from HEAD, not from the live index or working tree. Dirty checkout edits are treated as concurrent local state and reconciled after the commit lands.
All operations in one invocation are planned together. If any operation fails, no commit is created. If every mutating operation is an idempotent no-op, etch exits 0 without creating a commit unless --allow-empty is supplied.
After a successful commit, etch materializes touched paths into the index and working tree unless --no-checkout is used.
$ etch help invocation

Invocation

Global flags appear before the command path; CWD is the path and capability boundary.

Shapes

  etch [flags] <command> [args...]
  etch run [script]
  etch --plan <command> [args...]
  etch --dry-run <command> [args...]
Path operands are relative to process CWD, not the repository root. Absolute paths, .. segments, .git path segments, and symlink escapes are rejected. Mutating invocations require CWD to be inside a git worktree.
Existing source paths must be tracked by default. --untracked admits untracked source paths under the same CWD boundary; those paths become tracked if the invocation commits.
--plan emits canonical JSON and --dry-run emits a git-am-compatible patch preview without side effects. --no-checkout skips post-commit checkout synchronization. --retries controls optimistic ref-CAS retry attempts.
--message replaces the generated commit message. --subject-prefix, --subject-suffix, --body-prefix, and --body-suffix modify generated messages and are mutually exclusive with --message.

Examples

--untracked

Admit untracked source paths under the current working directory; touched paths become tracked if the command commits.

Command
$ etch --untracked set scratch.json status open
$ etch help prompts

Prompts

etch prompt prints agent-facing Markdown. By default it prints a one-shot bootstrap prompt; --context prints durable instructions for future agent context.

Commands

  etch prompt
  etch prompt --bootstrap
  etch prompt --context
etch prompt has no side effects. The default bootstrap prompt is meant to start an agent, such as codex "$(etch prompt)" or claude "$(etch prompt)", so the agent can install durable etch guidance into this repository's agent instructions.
etch prompt --context prints the durable guidance directly. Add that text to AGENTS.md, CLAUDE.md, or another project instruction file when you want future agents to know when and how to use etch.
$ etch help scripts

Scripts

etch run [script] executes a batch script as one transaction.

The script path is optional. Omit it or pass "-" to read the script from stdin. Every statement is planned together against one base tree, so later statements see earlier statements. If parsing, guards, or mutations fail, the batch produces no commit. On success, the whole batch produces one commit unless every mutating statement is a no-op.
Script lines use shell-style quoting, but no shell expansion. Quote values with spaces. Quote JSON values as one token, usually with single quotes:
  set posts/hello.md title "Hello, world"
  append events.jsonl '{"kind":"prompt","name":"first"}'
  set state.json payload --json '{"name":"first"}'
Multi-line values use heredocs. Heredoc bodies are literal text, and the terminator line contains only the delimiter:
section replace posts/hello.md "## Summary" <<EOF
$FOO is not expanded.
EOF

Examples

run

Execute a batch of commands as one atomic commit. All-or-nothing — if any operation fails, no commit. Quote JSON as one token; no shell expansions.

Command
$ etch run - <<'SCRIPT'
contains state.json open
set state.json status complete
SCRIPT
Commit
etch set state.json $.status "complete"
state.json 2 lines (+1 -1) +-
1-{"status":"open"}
1+{"status":"complete"}
$ etch help selectors

Selectors

Selectors are singular JSONPath-style paths.

Accepted

  $.agents.assistant.last_run
  agents.assistant.last_run
  $.items[0].title
  $["key.with.dots"]
Rejected: wildcards, recursive descent, slices, filters, unions, functions, negative indexes.
set may create missing object containers and final object members. append and add may create a missing final array under object-container rules. Syntax that can produce multiple matches is rejected before evaluation.
$ etch help values

Values

Structured values are strings by default. Use --json for a strict JSON value. For structured commands, --json may appear immediately before or after the value.

Examples

  etch set state.json status complete          # string "complete"
  etch set state.json count --json 12          # number 12
  etch set state.json count 12 --json          # number 12
  etch append state.json events --json '{"kind":"prompt"}'
  etch append events.jsonl '{"kind":"prompt"}'
  etch set state.json status=complete count:=12
Assignment items are accepted by set only. NAME=value writes a string; NAME:=json writes JSON. JSONL and NDJSON append values are always strict JSON and do not use --json.
For add and remove, array membership uses semantic structural equality within the edited format, not byte-spelling equality.

Examples

set

Set one or more structured values. Strings by default; use --json or := for typed values.

Command
$ etch set state.json status=complete priority:=1
Commit
etch: 2 changes in state.json
state.json 4 lines (+2 -2) ++--
11{
2-"status": "open",
3-"priority": 0,
2+"status": "complete",
3+"priority": 1,
44"labels": ["agent"]
55}

delete

Delete a key from structured data, or delete an entire file.

Command
$ etch delete config.yaml old_key
Commit
etch delete config.yaml $.old_key
config.yaml 1 line (-1) -
11db_host: localhost
2-old_key: unused
32timeout: 30

append

Append a value to an array. Not idempotent — always adds.

Command
$ etch append log.json entries --json '{"event":"sync"}'
Commit
etch append log.json $.entries {"event":"sync"}
log.json 3 lines (+2 -1) ++-
11{
22"entries": [
3-{"event": "start"}
3+{"event": "start"},
4+{"event":"sync"}
45]
56}

add

Ensure an array contains a value. No-op if already present.

Command
$ etch add people/alice.md tags vip
Commit
etch add people/alice.md tags "vip"
people/alice.md 2 lines (+1 -1) +-
11---
22name: Alice Chen
3-tags: [partner, technical]
3+tags: [partner, technical, vip]
44---
55
66## Notes
77
88Key decision-maker.

remove

Ensure an array does not contain a value. No-op if absent.

Command
$ etch remove config.json features dark-mode
Commit
etch remove config.json $.features "dark-mode"
config.json 2 lines (+1 -1) +-
11{
2-"features": ["dark-mode", "notifications"]
2+"features": ["notifications"]
33}
$ etch help formats

Formats

Porcelain commands infer formats from path extensions; plumbing commands make the format explicit.

Porcelain commands infer .json, .jsonl/.ndjson, .yaml/.yml, .md/.markdown, and .csv behavior from the path. Format-explicit commands such as json set, yaml set, frontmatter set, jsonl append, md table, and csv row append choose their parser and writer directly.
When a format-explicit JSON, YAML, or JSONL command writes a path whose extension advertises a different Etch-supported structured format, Etch validates the final bytes against the inferred format before committing. Unknown and extensionless paths are not guessed.
JSON and YAML structured commands share selector and value semantics. JSON edits preserve surrounding representation where possible. YAML and frontmatter edits preserve comments, key order, anchors, aliases, indentation, and scalar spelling where the parser can preserve them.
For Markdown paths, bare structured selectors target YAML frontmatter. If frontmatter is missing, set, append, and add can create it; delete and remove are no-ops when the final target is absent.
JSONL and NDJSON append has no selector. The value is always strict JSON, missing logs are treated as empty, and non-empty logs must end at a record boundary.

Examples

append (jsonl)

Append one compact JSON record, preserving object member order. Missing files are created.

Command
$ etch append events.jsonl '{"kind":"deploy","at":"2026-05-02T14:00:00Z"}'
Commit
etch append events.jsonl {"kind":"deploy","at":"2026-05-02T14:00:00Z"}
events.jsonl 1 line (+1) +
11{"kind":"heartbeat","at":"2026-05-02T13:00:00Z"}
22{"kind":"sync","at":"2026-05-02T13:30:00Z"}
3+{"kind":"deploy","at":"2026-05-02T14:00:00Z"}
$ etch help fields

Inline Fields

Markdown fields: use frontmatter for note-global metadata; use inline fields for body-local metadata.

On Markdown paths, bare structured selectors mutate YAML frontmatter. Markdown address flags such as --body, --section, --item, and --task switch set and delete to Dataview-style inline fields in the Markdown body. Inline field values are strings; --json is not supported for Markdown inline fields.
Frontmatter fits whole-note schema fields such as owner, source, status, and stable IDs. Inline fields fit metadata attached to a paragraph, list item, task, or local note context.
Dataview inline fields are Markdown annotations shaped like [field:: value] or (field:: value). The bracket form is visible in reading view; the parenthesized form is hidden. Etch preserves the surrounding line or list item and rewrites only the addressed field annotation.
Existing fields match first by exact source field name, then by Dataview-normalized field name if the normalized match is unique. Dataview implicit fields such as file.name, task status, and task text are reserved and not writable.
For full Dataview metadata syntax and indexing behavior, see https://blacksmithgu.github.io/obsidian-dataview/.

Examples

  etch set note.md status Driving
  etch set note.md last "2026-05-02" --body
  etch set note.md done "2026-05-01" --task "Send follow-up"

Examples

set (inline)

Set Dataview-style inline fields in Markdown body text. Use --task or --section to target location.

Command
$ etch set tasks/todo.md done "2026-05-02" --task "Send follow-up"
Commit
etch set tasks/todo.md done --task 'Send follow-up' "2026-05-02"
tasks/todo.md 2 lines (+1 -1) +-
11## Actions
22
3-- [ ] Send follow-up
3+- [ ] Send follow-up [done:: 2026-05-02]
44- [ ] Review draft
$ etch help addressing

Markdown Addressing

Markdown addressing uses exact matching with syntax normalization and ambiguity errors.

In command forms, <address> and <placement> stand for Markdown addressing flags. Inline field set/delete commands require an address. Task/list commands accept only the task/list subset.

Forms

  etch set <path.md> <field> <value> <address>
  etch delete <path.md> <field> <address>
  etch task close <path> <text> [<address>]
  etch task open <path> <text> [<address>]
  etch list add <path> <text> [--task] [<placement>]
  etch task add <path> <text> [<placement>]

Inline Field Address

FormMeaning
--bodyAddress inline fields in the whole Markdown body.
--section <heading>Limit the address to one heading section.
--item <text>Address an inline field on one matching list item.
--task <text>Address an inline field on one matching task item.
--item-type <type>Filter --item or --task matches by task, plain, numbered, or bullet. Repeat to combine independent filters.
--headPlace a created inline field at the start of the addressed scope.
--tailPlace a created inline field at the end of the addressed scope.
--before <literal>Place or narrow before a matching literal inside the addressed scope.
--after <literal>Place or narrow after a matching literal inside the addressed scope.
--hiddenUse hidden Dataview field syntax. Accepted by set only.

Task/List Address

FormMeaning
--section <heading>Limit the task/list command to one heading section.
--before <item>For task close/open, narrow the search before a matching list item. For task/list add, place the new item before it.
--after <item>For task close/open, narrow the search after a matching list item. For task/list add, place the new item after it.
--taskWith list add, create a task item instead of a plain list item.
Section selectors accept either a title such as "Status" or an ATX heading such as "## Status". Title-only selectors search all ATX heading levels; ATX selectors include the heading level.
List-item selectors normalize away the list marker, task checkbox, surrounding whitespace, Dataview inline field annotations, and trailing numeric reference-annotation links. Markdown inline syntax is rendered to normalized item text, so "**Buy milk**" and "[Buy milk](https://example.com)" both match "Buy milk".
Item type filters are task, plain, numbered, and bullet. Repeated filters combine across independent axes, such as task+numbered. Contradictory filters fail before planning.
Task/list commands use --section to choose a heading body and --before/--after as list-item anchors. For task close/open, anchors narrow the search; for add commands, anchors choose the insertion point.

Examples

section replace

Replace everything under a heading, preserving surrounding blank-line style.

Command
$ etch section replace notes.md "## Summary" <<'EOF'
Project on track. Next: May 15.
EOF
Commit
etch section replace notes.md '## Summary'
notes.md 2 lines (+1 -1) +-
11## Summary
22
3-Old summary here.
3+Project on track. Next: May 15.
44
55## Details
66
77Some details.

task close

Check off a task checkbox. Matches by text content.

Command
$ etch task close tasks/sprint.md "Write tests"
Commit
etch task close tasks/sprint.md "Write tests"
tasks/sprint.md 2 lines (+1 -1) +-
11## In progress
22
3-- [ ] Write tests
3+- [x] Write tests
44- [ ] Review PR

set (inline)

Set Dataview-style inline fields in Markdown body text. Use --task or --section to target location.

Command
$ etch set tasks/todo.md done "2026-05-02" --task "Send follow-up"
Commit
etch set tasks/todo.md done --task 'Send follow-up' "2026-05-02"
tasks/todo.md 2 lines (+1 -1) +-
11## Actions
22
3-- [ ] Send follow-up
3+- [ ] Send follow-up [done:: 2026-05-02]
44- [ ] Review draft
$ etch help files

Files

File verbs create, replace, delete, move, and copy whole paths inside the transaction.

Commands

  etch create <path> [<content>]
  etch replace <path> <content>
  etch delete <path>
  etch move <src> <dst>
  etch copy <src> <dst>
create no-ops when an existing file already has the same content and fails when it has different content. Omitted create content uses {} for JSON paths and empty content for other paths.
replace requires an existing regular file. delete is idempotent when the path is absent from the transaction base. move and copy fail if their destination exists in the transaction base.

Examples

create

Create a new file. Fails if the file already exists. JSON defaults to {}; other omitted content is empty.

Command
$ etch create people/bob.md
Commit
etch create people/bob.md ""
people/bob.md created empty file
created empty file

replace

Replace an existing file's entire content.

Command
$ etch replace notes/status.txt "complete"
Commit
etch replace notes/status.txt "complete"
notes/status.txt 2 lines (+1 -1) +-
1-open
1+complete

move

Move (rename) a file path.

Command
$ etch move people/bob.md people/robert.md
Commit
etch move people/bob.md people/robert.md
people/bob.md 1 line (-1) -
people/robert.md 1 line (+1) +
people/bob.md
1-# Bob
people/robert.md
1+# Bob

copy

Copy a file path.

Command
$ etch copy templates/default.md tasks/new-task.md
Commit
etch copy templates/default.md tasks/new-task.md
tasks/new-task.md 3 lines (+3) +++
1+# New task
2+
3+- [ ] Triage
$ etch help guards

Guards

Guards assert preconditions for a transaction without printing values or making content changes.

Commands

  etch exists <path>
  etch missing <path>
  etch contains <path> <literal>
For tracked paths, guards read the admitted input view at HEAD, not dirty working-tree bytes. With --untracked, admitted untracked paths use working-tree bytes.
A failed guard exits 1 before mutation side effects. A satisfied guard contributes no content change and never creates a commit by itself. Guards are included in plans and dry-run output as checks.
contains matches literal bytes. It is not a regex, does not normalize line endings, and does not perform case folding. Multi-line literals use heredocs.

Examples

exists

Assert that a path exists. Guards never commit. Use in scripts to gate mutations.

Command
$ etch exists state.json

missing

Assert that a path does not exist.

Command
$ etch missing state.json

contains

Assert that file bytes contain a literal string.

Command
$ etch contains state.json open
$ etch help section

Sections

Markdown sections are heading-delimited body ranges.

Commands

  etch section replace note.md "## Status" "done"
  etch section append note.md Status "new block"
  etch section prepend note.md Status "new block"
Section selectors accept either a title such as Status or an ATX heading such as ## Status. Repeated matching headings are ambiguous. Section payloads are Markdown block fragments: replace preserves existing boundary blank lines, and append/prepend use one blank line between non-empty fragments.

Examples

section replace

Replace everything under a heading, preserving surrounding blank-line style.

Command
$ etch section replace notes.md "## Summary" <<'EOF'
Project on track. Next: May 15.
EOF
Commit
etch section replace notes.md '## Summary'
notes.md 2 lines (+1 -1) +-
11## Summary
22
3-Old summary here.
3+Project on track. Next: May 15.
44
55## Details
66
77Some details.

section append

Append content at the end of a section, before the next heading.

Command
$ etch section append journal.md "## Log" <<'EOF'
- 10:00 Standup
EOF
Commit
etch section append journal.md '## Log' "- 10:00 Standup"
journal.md 1 line (+1) +
11---
22date: "2026-05-02"
33---
44
55## Log
66
77- 09:00 Morning review
88
9+- 10:00 Standup
910## Notes
1011
1112Remember to follow up.

section prepend

Prepend content at the start of a section, right after the heading.

Command
$ etch section prepend journal.md "## Log" <<'EOF'
- 08:00 Early check-in
EOF
Commit
etch section prepend journal.md '## Log' "- 08:00 Early check-in"
journal.md 1 line (+1) +
11## Log
2+- 08:00 Early check-in
23
34- 09:00 Morning review
45- 10:00 Standup
$ etch help tasks

Tasks and Lists

Markdown task/list commands operate on exact source-normalized item text.

Commands

  etch task close note.md "Send follow-up" --section Actions
  etch task open note.md "Send follow-up" --section Actions
  etch list add note.md "Launch notes" --section Actions
  etch task add note.md "Send follow-up" --section Actions
task close changes [ ] to [x] and never creates missing tasks. task open ensures an open task: it reopens [x]/[X], no-ops on [ ], and creates missing tasks only when a destination address such as --section, --before, or --after is supplied. Custom checkbox statuses fail. --before and --after match list items, not arbitrary prose. list add and task add create source from plain item text; do not include "- " or "- [ ]". Without --section, --before, or --after, list insertion succeeds only when there is a single obvious list target.

Examples

task close

Check off a task checkbox. Matches by text content.

Command
$ etch task close tasks/sprint.md "Write tests"
Commit
etch task close tasks/sprint.md "Write tests"
tasks/sprint.md 2 lines (+1 -1) +-
11## In progress
22
3-- [ ] Write tests
3+- [x] Write tests
44- [ ] Review PR

task open

Uncheck a task checkbox. Creates the task if a destination is addressed.

Command
$ etch task open tasks/sprint.md "Review PR"
Commit
etch task open tasks/sprint.md "Review PR"
tasks/sprint.md 2 lines (+1 -1) +-
11## Done
22
33- [x] Write tests
4-- [x] Review PR
4+- [ ] Review PR

task add

Add a new open task item to an addressed section.

Command
$ etch task add tasks/sprint.md "Deploy staging" --section "## Remaining"
Commit
etch task add tasks/sprint.md --section '## Remaining' "Deploy staging"
tasks/sprint.md 1 line (+1) +
11## Remaining
22
33- [ ] Write docs
4+- [ ] Deploy staging

list add

Add a plain list item (no checkbox) to an addressed section.

Command
$ etch list add notes.md "Follow up with Alice" --section "## Action items"
Commit
etch list add notes.md --section '## Action items'
notes.md 1 line (+1) +
11## Action items
22
33- Send proposal
4+- Follow up with Alice
$ etch help table

Tables and CSV

Tables are ordered rows and named columns of string cells.

CSV

  etch table set data.csv all,status done
  etch table row append data.csv '{"id":"1","status":"open"}'
  etch table column add data.csv owner --default Brandon

Markdown

  etch table set notes.md doc @0 all,status done
  etch table row append notes.md "## Inventory" '{"sku":"A1"}'
For Markdown paths, scope is doc or an exact heading selector, and the optional table ordinal is @0, @1, and so on. For CSV paths, scope and table ordinal are omitted because the file is one table.
Ranges have the shape rows,columns. Rows and columns support all, zero-based ordinals, ordinal ranges, exact labels, and bracketed labels for spaces or selector punctuation. row-json is a strict JSON object keyed by column label.

Examples

table set

Set one or more cells in a CSV or Markdown table while preserving Markdown table whitespace when possible.

Command
$ etch table set notes.md "## Inventory" sku=A1,status done
Commit
etch table set notes.md sku=A1,status "done"
notes.md 2 lines (+1 -1) +-
11## Inventory
22
33| sku | status |
44| --- | --- |
5-| A1 | open |
5+| A1 | done |

table row append

Append a row to a CSV or Markdown pipe table.

Command
$ etch table row append data.csv '{"id":"4","status":"open","owner":"dave"}'
Commit
etch table row append data.csv {"id":"4","status":"open","owner":"dave"}
data.csv 1 line (+1) +
11id,status,owner
221,done,alice
332,closed,bob
4+4,open,dave

table row insert

Insert a row before or after one matching row in a CSV or Markdown table.

Command
$ etch table row insert data.csv --after id=1 '{"id":"2","status":"open","owner":"bob"}'
Commit
etch table row insert data.csv --after id=1
data.csv 1 line (+1) +
11id,status,owner
221,done,alice
3+2,open,bob
343,open,carol

table row delete

Delete rows matching a condition.

Command
$ etch table row delete data.csv status=closed
Commit
etch table row delete data.csv status=closed
data.csv 1 line (-1) -
11id,status,owner
221,open,alice
3-2,closed,bob
433,open,carol

table column add

Ensure a column exists, using an optional default value when creating it.

Command
$ etch table column add data.csv priority --default medium
Commit
etch table column add data.csv priority {"after":"","default":"medium"}
data.csv 6 lines (+3 -3) +++---
1-id,status
2-1,open
3-2,closed
1+id,status,priority
2+1,open,medium
3+2,closed,medium

table column rename

Rename a column in a CSV or Markdown table.

Command
$ etch table column rename data.csv owner assignee
Commit
etch table column rename data.csv owner "assignee"
data.csv 2 lines (+1 -1) +-
1-id,status,owner
1+id,status,assignee
221,open,alice
332,closed,bob

table column delete

Ensure a column is absent from a CSV or Markdown table.

Command
$ etch table column delete data.csv owner
Commit
etch table column delete data.csv owner
data.csv 6 lines (+3 -3) +++---
1-id,status,owner
2-1,open,alice
3-2,closed,bob
1+id,status
2+1,open
3+2,closed
$ etch help plans

Plans

--plan emits canonical JSON describing operations, input/output hashes, planned tree, and commit message.

A plan is computed by the same parser and evaluators as execution, stopped before side effects. It is based on HEAD for tracked paths and includes enough hashes to detect stale inputs and behavior changes.
--dry-run lowers the same plan to a mailbox patch intended for git am. Dry-run output is optimized for review; plan JSON is the canonical machine contract.
The plan hash is a SHA-256 hash of canonical JSON bytes and can be used by host runtimes as an approval-cache key.

Examples

--plan

Print the canonical JSON transaction plan without creating a commit or changing files.

Command
$ etch --plan set state.json status complete

--dry-run

Print a git-am-compatible patch preview without creating a commit or changing files.

Command
$ etch --dry-run set state.json status complete
$ etch help commits

Commits

Every successful mutating invocation creates one local git commit unless all mutating operations are no-ops.

Generated commit messages are built from normalized operation descriptors with bounded value previews. Full values live in file contents and are represented in plans by hashes.
Single-op commits use subjects such as etch set note.md title "Hello" when the preview fits. Multi-op commits use a summary subject and a Changes body.
--message replaces the generated message. --subject-prefix, --subject-suffix, --body-prefix, and --body-suffix modify generated messages and are mutually exclusive with --message.
Idempotent no-op operations do not contribute to the commit. If every mutating operation is a no-op, etch exits 0 with nothing to do unless --allow-empty is supplied.

Examples

--message

Override the generated commit message for one mutating invocation.

Command
$ etch --message 'mark state complete' set state.json status complete

--subject-prefix/suffix

Add text before or after the generated commit subject.

Command
$ etch --subject-prefix '[agent] ' set state.json status complete

--body-prefix/suffix

Add a body block before or after the generated commit body.

Command
$ etch --body-suffix 'Reviewed-by: agent' set state.json status complete
$ etch help security

Security

etch is designed as a narrow CWD-scoped, git-backed mutation capability.

etch accepts only relative paths under CWD, rejects .. and .git path segments, and refuses symlink escapes. There is no repo-root mode, script-local root, or etch-specific environment variable that changes the path root.
etch does not perform network operations. The implementation invokes git only for local repository/object/ref/index work needed to plan, commit, preview, and materialize changes.
The script syntax has no variables, command substitution, globbing, pipes, conditionals, or process execution. Composition happens outside etch.
$ etch help conflicts

Conflicts

When materialization cannot merge local checkout changes after the commit lands, etch leaves recovery text on stderr.

The ref update is the durability boundary. If materialization fails, the commit exists and is not rolled back.
Default materialization rebases touched index and working-tree states from old HEAD to new HEAD. Clean merges preserve staged and unstaged local changes; conflicts are written to the working tree when possible.
Resolve conflict markers, then commit or discard the working-tree resolution. For binary or unmergeable local changes, etch fails cleanly without overwriting the current working-tree file.
--no-checkout skips materialization entirely and reports that the working tree and index were not updated for touched paths.

Examples

--no-checkout

Commit the transaction without materializing touched paths into the index and working tree.

Command
$ etch --no-checkout set state.json status complete
$ etch help --all

Command Index

etch mutates structured files and commits each successful mutating invocation.

Core structured edits

CommandClassDescription
idempotentSet JSON/YAML/frontmatter or Markdown inline fields.
idempotentDelete a file or selected JSON/YAML/frontmatter/inline-field value.
non-idempotentAppend a value to an array, or a JSONL record to .jsonl/.ndjson.
idempotentEnsure an array contains a value.
idempotentEnsure an array does not contain a value.

Markdown sections and lists

CommandClassDescription
idempotentReplace the body under one Markdown heading.
non-idempotentAppend a block fragment under one Markdown heading.
non-idempotentPrepend a block fragment under one Markdown heading.
idempotentEnsure one Markdown task is closed.
idempotentEnsure one Markdown task is open, creating it when a destination is addressed.
non-idempotentAdd one open Markdown task.
non-idempotentAdd one Markdown list item.

Tables

Files

CommandClassDescription
idempotentCreate a new file; omitted content uses an extension-aware default.
idempotentReplace an existing file's entire content.
idempotentMove a file path.
idempotentCopy a file path.

Guards

CommandClassDescription
guardGuard that a path exists in the admitted input view.
guardGuard that a path is missing in the admitted input view.
guardGuard that admitted file bytes contain a literal.

Agent setup

CommandClassDescription
introspectionPrint agent setup or durable context prompts.

Advanced structured formats

CommandClassDescription
idempotentSet JSON values.
idempotentDelete a JSON value.
non-idempotentAppend to a JSON array.
idempotentEnsure a JSON array contains a value.
idempotentRemove matching values from a JSON array.
idempotentSet YAML values.
idempotentDelete a YAML value.
non-idempotentAppend to a YAML sequence.
idempotentEnsure a YAML sequence contains a value.
idempotentRemove matching values from a YAML sequence.
idempotentSet Markdown YAML frontmatter.
idempotentDelete Markdown YAML frontmatter.
non-idempotentAppend to a frontmatter sequence.
idempotentEnsure a frontmatter sequence contains a value.
idempotentRemove matching values from a frontmatter sequence.

Advanced logs and Markdown

CommandClassDescription
non-idempotentAppend one compact JSON value as a JSONL/NDJSON record.
idempotentReplace the body under one Markdown heading.
non-idempotentAppend a block fragment under one Markdown heading.
non-idempotentPrepend a block fragment under one Markdown heading.

Advanced table formats

CommandClassDescription
idempotentSet CSV cells.
non-idempotentAppend a CSV row.
non-idempotentInsert a CSV row.
idempotentDelete CSV rows.
idempotentEnsure a CSV column exists.
idempotentRename a CSV column.
idempotentEnsure a CSV column is absent.
idempotentSet Markdown table cells.
non-idempotentAppend a Markdown table row.
non-idempotentInsert a Markdown table row.
idempotentDelete Markdown table rows.
idempotentEnsure a Markdown table column exists.
idempotentRename a Markdown table column.
idempotentEnsure a Markdown table column is absent.
Format-explicit command prefixes select the parser and writer. If the path extension advertises a different Etch-supported structured format, Etch validates the final bytes against the inferred format before committing.