---
title: memhtml session commit
description: "Land the session's overlay on its ref as one commit, or report why it cannot: `refused`, `rebase-needed`, or `worktree-dirty`."
---

## 1. Synopsis

Land the session's overlay on its ref as one commit, or report why it cannot: `refused`, `rebase-needed`, or `worktree-dirty`.

```sh
memhtml session commit --message <string> [options]
```

## 2. Arguments

This command takes no positional arguments.

## 3. Flags

| Flag | Type | Default | Values | Description |
| --- | --- | --- | --- | --- |
| `--id` | string | *no default* | *no fixed set* | The session to commit. Defaults to $MEMHTML_SESSION; with neither, the call is ERR_MISSING_ARGUMENT. |
| `--message` | string | *no default* | *no fixed set* | The commit summary. Rendered as `memhtml(session): <summary>` with a Memhtml-Session trailer. When HEAD is the session's ref, the shared index and working tree move to the new commit with it (`worktreeSynced: true`); uncommitted state at a path the commit writes or removes is answered `worktree-dirty` and nothing moves. A ref that moved past the session's base is `rebase-needed`: run `session rebase` and commit again. The checkout move and the ref swap run under the checkout lock `.memhtml/checkout.lock`, which every v1 write holds from its stage to its commit, so neither commits the other's files; the commit waits up to 15 s for it, then fails with ERR_STORAGE (`checkout.locked`) having moved nothing. The commit it builds is written to the log as `pending` before anything shared moves, so a call killed at any point is settled by the next `session commit`: `committed` with `recovered: true` when it had landed, else the checkout is put back and the commit is made again. A `session put` or `session exec` that appends to such a log settles it first the same way, so what it appends lands on the next commit: on top of the landed commit, whose ops leave the log (`baseSha` in its payload names that commit), or beside the ops that never landed. A `committed` outcome also writes the new commit's snapshot (`snapshot`: path, bytes, ms, pruned; null when that best-effort write failed), so the next load hits the cache. Before it commits, the log gains the repoints its archives and moves lack against the version it commits over, appended at its end, since a record the ref gained after the exec may cite a path the log vacates; when they would take a log within the 200-op cap over it, nothing is written and the commit is refused with a `format` violation on that archive or move. A log with no ops has nothing to land: it is answered `refused` with no violations, and nothing is committed or written. **Required.** |
| `--drop-refused` | flag | *no default* | *no fixed set* | On a `refused` outcome, drop every op that touches a path a violation names, record each in `.memhtml/sessions/<id>.dropped.jsonl`, and commit the rest; repeat until the commit is clean or nothing is left. `dropped` lists each removed op with its reasons. A batch-cap refusal names no path, so it is never dropped; the refusal of an archive or a move whose new repoints would pass the cap names that op, so it is dropped and the rest lands. A dropped archive or move always takes its own repoints with it, listed in `dropped` under its reasons, so no holder loses its other ops to them. When nothing holds its destination and the record is still live, at its source or where a chain of dropped moves and archives of it began (nothing is rewritten through a path two of them aim at, or one two of them leave while another aims at it or the log puts there; a path only the version's record leaves twice still names it), an op kept at a dropped move's destination is made at the record's path and an edge a kept op aims at the destination is aimed back at it, which its reasons say; an edge to a held destination keeps naming the record there, and one to the slot of a record the log put is left as written. A drop on a record that cites a path the log vacates takes that record's repoint with its other ops, so the repoints the kept ops need are appended again, and `dropped` does not list them, nor a pair taken at a dropped move's destination that comes back at the holder's own path. Through the head server it also takes a `rebase-needed` round off the caller: the server rebases the session onto its tip and commits again inside the same commit permit, up to 3 times, and answers the last round, with `rebased` counting the rebases (0 on the local path, which returns `rebase-needed` as without the flag) and `dropped` every round's drops. Meant for a runtime's end-of-run commit, where there is no agent turn left to fix a line: an agent in a turn should read the refusal and rewrite the line instead. |
| `--server` | flag | `true` | *no fixed set* | Ask the head server on .memhtml/head.sock to commit (`memhtml head serve`); `--no-server` always commits here. The server reads the session's log, judges it against the version at the session's base from what it holds (its tip, an ancestor built from it, or a load for a base off its ref's history), runs the same commit this process would, one commit at a time, then holds the new commit and writes its snapshot; the payload is the same either way, with `via` `server` or `local` and `server` saying why (`used`, `base`, `reason`, `detail`). The commit runs here when no server accepts within 100 ms, when the server answers a 4xx (an older server without the route), or when it declines (`server.reason` `other-ref` for a session on a ref the server does not follow, `session-unreadable`, `base-unservable`, or `busy` after 20000 ms behind another commit). When the server took the commit and answered 5xx, or gave no answer within `MEMHTML_COMMIT_DEADLINE_MS` (60000 ms by default), the call fails with ERR_STORAGE naming `session status` and does not commit here, because the server may have moved the ref. |

Every command also accepts the [global flags](/reference/global-flags/).

## 4. Response

On success the command writes one JSON envelope to stdout, and its `type` is `session.committed`.

On failure it writes the failure envelope, whose `code` comes from [error codes](/reference/error-codes/).

[The JSON envelope](/reference/envelope/) gives the fields both shapes carry. [Response types](/reference/response-types/) lists every value `type` takes across the binary.

## 5. Further reading

No guide block names this command. The [guide](/reference/guide/) is the workflow prose the CLI ships beside the command table: which command to reach for, and in what order.

## 6. Provenance

A loader generates this page from `apps/cli/src/commands.ts` while the site builds, so no file in the repository holds it: the `COMMANDS` array there is the one source of argument parsing, of `memhtml manifest`, and of `AGENTS.md`. Change the registry and this page changes with it.