<!-- Generated by crates/swarmops-cli/src/reference/mcp_page.rs from the code: do not edit. Change the code, then run SWARMOPS_REGEN_REFERENCE=1 with the regen_reference test. -->

# land

Merges head (with its first-parent chain since base) three-way onto target, main by default, and publishes the result as one changeset in one transaction; on E\_CONFLICT, details.report lists each conflict: resolve them with resolutions, against the report's theirs, its full 64-hex id (a path the target changed since comes back in the report's stale). Give idempotency\_key to make a retry safe.

```yaml
title: "land"
description: "Land a change."
since: "0.1.0"
mutates: true
identity_required: true
cli_command: "swarmops land"
envelope_op: "land"
request_type: "LandReq"
annotations: {"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":false}
max_result_chars: null
```

## Input schema

`arguments` is a `LandReq`: `swarmops schema LandReq` prints the type. A field the type does not know is ignored.

| Field | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `base` | string or null | no |  | Where the change starts: a first-parent ancestor of `head`, whose own changes are not part of it (anything else is `E_INVALID_ARG`). It need not be on the target. When omitted, the merge base of `head` and the target's head, along first parents. |
| `head` | string | yes |  | The changeset to land: the change's head. A revision as the caller wrote it, for the store to resolve: a ref name (`main`, `release/1.2`), a full 64-hex changeset id or a unique prefix of at least 12 hex digits, optionally followed by `~N` for the N-th first-parent ancestor. |
| `idempotency_key` | string or null | no |  | Makes a retry of this land safe: 1 to 64 letters, digits and `-`, such as a uuid v7. A land with a key first looks down the target's first parents, to `base`, for a changeset that landed with the same key: one squashed from this `head` is the replay, which writes nothing (`status` is `replayed`); one from another head is `E_INVALID_ARG`, a key used for another change. |
| `max_attempts` | integer | no | `8` | How many times to try to publish before failing with `E_CAS_RETRY_EXHAUSTED`: 1 to 32. |
| `max_conflict_bytes` | integer | no | `32768` | The most bytes of hunk text an `E_CONFLICT` report carries: past it, the texts are left out (`truncated`), and the line positions and blob ids stay. |
| `message` | string or null | no |  | The landed changeset's message; `head`'s when omitted. |
| `resolutions` | object or null | no |  | What to make of the paths an `E_CONFLICT` report named, decided without a checkout. Each resolution applies to its path while the target holds there what `against` held, whether the path conflicts or not; a path the target changed since is stale, and the land fails `E_CONFLICT` again, with a fresh report that names it in `stale`. Conflicts left unresolved fail it too. `swarmops mcp` refuses an `against` that is not a full 64-hex id (`E_INVALID_ARG`). |
| `target` | string | no | `"main"` | The ref to land on: `main` or `release/<name>`, which must exist. |

### JSON Schema

As `tools/list` gives it: each `$ref` replaced by its definition, so that it stands alone.
Its descriptions' citations of the design documents are left out here.

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "`land`: merge a change three-way onto a target ref and publish it there as one new\nchangeset, in one transaction. The change is `head` with its\nfirst-parent chain after `base`, squashed: the landed changeset's parent is the target's\nhead, so the target stays linear. A conflict is the error `E_CONFLICT`, with the report in\n`details.report`; nothing is recorded then.",
  "properties": {
    "base": {
      "anyOf": [
        {
          "description": "A revision as the caller wrote it, for the store to resolve: a ref name (`main`,\n`release/1.2`), a full 64-hex changeset id or a unique prefix of at least 12 hex digits,\noptionally followed by `~N` for the N-th first-parent ancestor.",
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "description": "Where the change starts: a first-parent ancestor of `head`, whose own changes are not part\nof it (anything else is `E_INVALID_ARG`). It need not be on the target. When omitted, the\nmerge base of `head` and the target's head, along first parents."
    },
    "head": {
      "description": "The changeset to land: the change's head. A revision as the caller wrote it, for the store to resolve: a ref name (`main`,\n`release/1.2`), a full 64-hex changeset id or a unique prefix of at least 12 hex digits,\noptionally followed by `~N` for the N-th first-parent ancestor.",
      "type": "string"
    },
    "idempotency_key": {
      "description": "Makes a retry of this land safe: 1 to 64 letters, digits and `-`, such as a uuid v7. A land\nwith a key first looks down the target's first parents, to `base`, for a changeset that\nlanded with the same key: one squashed from this `head` is the replay, which writes\nnothing (`status` is `replayed`); one from another head is `E_INVALID_ARG`, a key used\nfor another change.",
      "type": [
        "string",
        "null"
      ]
    },
    "max_attempts": {
      "default": 8,
      "description": "How many times to try to publish before failing with `E_CAS_RETRY_EXHAUSTED`: 1 to 32.",
      "format": "uint32",
      "maximum": 32,
      "minimum": 1,
      "type": "integer"
    },
    "max_conflict_bytes": {
      "default": 32768,
      "description": "The most bytes of hunk text an `E_CONFLICT` report carries: past it, the texts are left\nout (`truncated`), and the line positions and blob ids stay.",
      "format": "uint64",
      "minimum": 0,
      "type": "integer"
    },
    "message": {
      "description": "The landed changeset's message; `head`'s when omitted.",
      "type": [
        "string",
        "null"
      ]
    },
    "resolutions": {
      "anyOf": [
        {
          "description": "A land's resolutions (`land --resolve`): what to make of some paths of the merge of the change\nonto the target, decided against one of the target's heads.",
          "properties": {
            "against": {
              "description": "The target's head the resolutions were decided against: the conflict report's `theirs`,\nby its full 64-hex id. A resolution applies while the target holds its path as this\nchangeset does (the same file, the same directory, or nothing). A revision as the caller wrote it, for the store to resolve: a ref name (`main`,\n`release/1.2`), a full 64-hex changeset id or a unique prefix of at least 12 hex digits,\noptionally followed by `~N` for the N-th first-parent ancestor.",
              "type": "string"
            },
            "files": {
              "additionalProperties": {
                "description": "What a land makes of one path, and of every path below it: exactly one of `take`, `content`\nand `delete` (anything else is `E_INVALID_ARG`, a rule the server checks), the rest of the\nmerge as it merged.",
                "properties": {
                  "content": {
                    "anyOf": [
                      {
                        "description": "A `put`'s content, as an object with one key.",
                        "oneOf": [
                          {
                            "additionalProperties": false,
                            "description": "UTF-8 text, verbatim.",
                            "properties": {
                              "inline": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "inline"
                            ],
                            "type": "object"
                          },
                          {
                            "additionalProperties": false,
                            "description": "Bytes in standard, padded base64.",
                            "properties": {
                              "base64": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "base64"
                            ],
                            "type": "object"
                          },
                          {
                            "additionalProperties": false,
                            "description": "A blob the store holds already, by its id (64 hex digits), as `blob_put` returns it: the\ncommit neither sends nor reads its bytes. An id the store holds no blob under (none, or\na tree's or a changeset's) is `E_INVALID_ARG`, and nothing is written. `blob_put` takes\nthe other forms only.",
                            "properties": {
                              "blob": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "blob"
                            ],
                            "type": "object"
                          },
                          {
                            "additionalProperties": false,
                            "description": "A file on the client's machine. The client reads it and sends its bytes, so the store is\nnever asked to read a path.",
                            "properties": {
                              "file": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "file"
                            ],
                            "type": "object"
                          }
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "One file of new content, given as a commit's change gives it (inline, base64, a client\nfile, or a stored blob by id), within a commit's limits; nothing below it."
                  },
                  "delete": {
                    "description": "Nothing there: no file at the path, nor below it.",
                    "type": "boolean"
                  },
                  "mode": {
                    "anyOf": [
                      {
                        "description": "The kind of entry a `put` writes.",
                        "oneOf": [
                          {
                            "const": "file",
                            "description": "A regular file (git mode 100644).",
                            "type": "string"
                          },
                          {
                            "const": "exec",
                            "description": "An executable file (git mode 100755).",
                            "type": "string"
                          },
                          {
                            "const": "symlink",
                            "description": "A symlink; the content is the link's target.",
                            "type": "string"
                          }
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "The kind of the file `content` makes, only beside it; when omitted, the kind of the file\nours holds there, else theirs', else a regular file."
                  },
                  "take": {
                    "anyOf": [
                      {
                        "description": "One side of a land's merge.",
                        "oneOf": [
                          {
                            "const": "ours",
                            "description": "The change: its head.",
                            "type": "string"
                          },
                          {
                            "const": "theirs",
                            "description": "The target: its head when the land merges.",
                            "type": "string"
                          }
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "What one side holds there: `ours`, the change's head, or `theirs`, the target's head."
                  }
                },
                "type": "object"
              },
              "description": "What to make of each path, by its repository path.",
              "type": "object"
            }
          },
          "required": [
            "against",
            "files"
          ],
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "description": "What to make of the paths an `E_CONFLICT` report named, decided without a checkout. Each resolution applies to its path while the\ntarget holds there what `against` held, whether the path conflicts or not; a path the\ntarget changed since is stale, and the land fails `E_CONFLICT` again, with a fresh report\nthat names it in `stale`. Conflicts left unresolved fail it too. `swarmops mcp` refuses\nan `against` that is not a full 64-hex id (`E_INVALID_ARG`)."
    },
    "target": {
      "default": "main",
      "description": "The ref to land on: `main` or `release/<name>`, which must exist.",
      "type": "string"
    }
  },
  "required": [
    "head"
  ],
  "title": "LandReq",
  "type": "object"
}
```

## Annotations

It adds a changeset onto a ref's head and moves the ref to it, keeping all the ref held. Run again with the same arguments, it finds its change on the ref and adds nothing: `replayed` with an `idempotency_key`, `E_NOTHING_TO_LAND` without.

| Annotation | Value | Meaning |
| --- | --- | --- |
| `destructiveHint` | `false` | True: a tool that changes the store may overwrite or delete what is there, not only add to it. |
| `idempotentHint` | `true` | True: calling it again with the same arguments changes nothing more. |
| `openWorldHint` | `false` | True: it reaches beyond a closed set of things. Every tool here stays inside the store. |
| `readOnlyHint` | `false` | True: the tool does not change its environment, the store. |

Its entry in `tools/list` carries no `_meta`.

## CLI command

[`swarmops land`](../commands/land.md) runs the same operation and prints the same envelope.

## Examples

### MCP

```json
{
  "id": 12,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "head": "[head]",
      "idempotency_key": "land-7"
    },
    "name": "land"
  }
}
```

```json
{
  "id": 12,
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "text": "{\"ok\":true,\"op\":\"land\",\"api\":1,\"result\":{\"status\":\"landed\",\"landed\":\"[landed]\",\"rebased_onto\":\"[theirs]\",\"target\":\"main\",\"base\":\"[c1]\",\"attempts\":1,\"relocated\":false,\"files_changed\":1,\"squashed_from\":[\"[head]\"]},\"meta\":{\"repo\":\"[tmp]/store\",\"elapsed_ms\":\"[elapsed_ms]\",\"resolved\":{\"[head]\":\"[head]\",\"main\":\"[theirs]\"},\"auth\":\"trust\"}}",
        "type": "text"
      }
    ],
    "isError": false,
    "structuredContent": {
      "api": 1,
      "meta": {
        "auth": "trust",
        "elapsed_ms": "[elapsed_ms]",
        "repo": "[tmp]/store",
        "resolved": {
          "[head]": "[head]",
          "main": "[theirs]"
        }
      },
      "ok": true,
      "op": "land",
      "result": {
        "attempts": 1,
        "base": "[c1]",
        "files_changed": 1,
        "landed": "[landed]",
        "rebased_onto": "[theirs]",
        "relocated": false,
        "squashed_from": [
          "[head]"
        ],
        "status": "landed",
        "target": "main"
      }
    }
  }
}
```

The server ran as `swarmops mcp --repo [tmp]/store --as agent/worker-17`, after `initialize`. Recorded by the MCP tests. A name in square brackets, such as `[tmp]` or `[c1]`, stands for what differs from run to run: the test's temporary directory, an id, a time, the version.

## Details

It merges `head`, with its first-parent chain since `base`, three-way onto `target` (`main` by
default) and publishes the result as one changeset in one transaction.

On `E_CONFLICT`, `details.report` lists each conflict.
Resolve them in `resolutions`, decided `against` the report's `theirs`, its full 64-hex id: the
server refuses a ref name, a relative revision or a prefix there (`E_INVALID_ARG`).
A path the target changed since comes back in the report's `stale`.
A resolution's `{"file": path}` content follows the rules of [`commit`](../mcp-tools/commit.md).

Give an `idempotency_key` to make a retry safe; run again with the same arguments, a land adds
nothing.

## Return information

A tool result: the envelope, whose `op` is `land`, as `structuredContent` and again as the text of its one `content` block. `isError` is true exactly when the envelope's `ok` is false. On success the envelope's `result` is what [`swarmops land`](../commands/land.md#return-information) returns.

## Errors

A failed call is a tool result with `isError: true`; the envelope's `error.code` is one of the [error codes](../errors.md).

- [`E_INVALID_ARG`](../errors.md#e_invalid_arg): arguments that do not fit `LandReq`, a field named twice among them included, or that break one of the server's own rules.
- [`E_IDENTITY_REQUIRED`](../errors.md#e_identity_required): the server runs with no identity.
- [`E_NOT_A_REPO`](../errors.md#e_not_a_repo): the server's store is not there; the server serves on.
- [`E_INTERNAL`](../errors.md#e_internal): the operation panicked, a bug.

Then the errors of the operation, as [`swarmops land`](../commands/land.md#errors) lists them.

## See also

- [`swarmops land`](../commands/land.md)
- [MCP tools](README.md)
- [MCP integration](../../develop/mcp.md)
- [Error codes](../errors.md)
