# Develop a private bot with Git

Private Git uses your existing Clunkyard bot project. Browser edits, WebDAV edits
and Git pushes publish to the same source revision history. You need Git and
Node 20 or later, plus your chosen language's toolchain to build locally.

Install [@clunkyard/git](https://www.npmjs.com/package/@clunkyard/git) from npm.
On Linux, macOS or WSL, use a user-owned prefix:

```sh
npm install --global --prefix "$HOME/.local" @clunkyard/git
export PATH="$HOME/.local/bin:$PATH"
clunkyard-git login
```

Add the PATH line to your shell profile to keep the command available. If your
Node installation already gives npm a user-owned global prefix, you can omit
`--prefix` and keep its existing PATH. No administrator access is needed.

In Windows PowerShell, use npm's normal user prefix:

```powershell
npm install --global @clunkyard/git
clunkyard-git login
```

The helper needs only Git and Node. The shared
[@clunkyard/cli](player-kit.md) installs your selected language's SDK and local
match engine when you build or run a trial.

Create an **agent access key** on your Account page and enter it at the hidden
prompt. The helper stores the key in your user configuration directory, outside
the project. It authorizes your account, so revoke it from Account when you no
longer need it. A secret manager can supply standard input with
`clunkyard-git login --token-stdin`. Keep keys out of command arguments, remote
URLs and committed files.

Open your bot in the workbench, expand **Connections → Private Git** and use
the complete clone command shown there. It includes your saved project’s
address and folder name; you do not need to copy its ID separately. Then work
normally:

```sh
# Paste the complete git clone command from the workbench.
cd my-robot
npx @clunkyard/cli build
npx @clunkyard/cli match 42 2d classic
# Edit your robot, then repeat the same match.
git add bot.vane
git commit -m "Improve target selection"
git push origin main
```

For a JavaScript or TypeScript clone that does not yet contain npm package
files, run `npx @clunkyard/cli migrate` before the first build. Commit the
resulting `package.json` and `package-lock.json` and keep `node_modules/`
ignored. Other languages use their installed compiler or interpreter.

If you already developed a robot in a language starter, commit that work in its
starter repository first. Create a Clunkyard bot in the same language and clone
its private remote into a separate directory. Copy the committed starter files
into that clone, keeping the clone's own `.git` directory. For example, on
Unix or WSL, run this from the new private clone:

```sh
git -C ../starter-vane archive HEAD | tar -x
```

This copies tracked files without importing the starter's Git history. With a
file manager, copy robot source, `bot.json`, README, Makefile, `.gitignore`
and any normal language build files. For JavaScript or TypeScript, include
`package.json` and `package-lock.json`. Leave `.git`, `.clunkyard`,
`node_modules/`, build output and replays behind. In
`bot.json`, set `name` to your robot's name and check that `language`, `entry`
and `protocol` still describe the chosen starter. The destination bot ID stays
in the remote URL, not in `bot.json`. Build and run a local trial in this clone,
then `git add`, commit and push. Do not replace the private clone's remote or
force-push the unrelated starter history.

Each accepted push saves the final source tree as an immutable Clunkyard
revision and requests its normal hosted build. Check My bots for compilation
results and run a trial before entering tournaments. A saved push can still
have a failed build; fix the code and push another commit.

If another editor saves while you work, fetch its commit before pushing:

```sh
git fetch origin
git log --oneline --all --graph
git merge origin/main
# Resolve any conflicts, build and test again.
git push origin main
```

The remote preserves the exact accepted commit IDs, including multiple offline
commits and merges. A second clone sees the same history. Browser and WebDAV
saves add normal Clunkyard-authored commits to `main`. The first clone begins
Git history at your current saved project; older application revisions remain
available in Clunkyard's revision history.

Only `main` is available initially. Push up to 32 new commits at once, within the
project's file, source and history limits. Force pushes, new remote branches,
tags, symlinks and submodules are unavailable. Binary files and executable bits
are supported. Existing empty directories and other Unix permission bits remain
application metadata because Git does not represent them. Historical source
`.git` files and platform metadata are excluded from the Git view and cannot be
replaced by a push.

Retry `git push` after a connection failure. The helper retains a non-secret
operation receipt under your local Git directory and asks the server to resolve
that operation. It does not resubmit an uncertain provider write. If the server
reports that an operation is still resolving, keep the receipt and retry later.

For CI, supply `CLUNKYARD_AGENT_KEY` through your CI secret store. It is restricted
to `CLUNKYARD_ORIGIN`, which defaults to `https://clunkyard.com`. Credentials saved
by login are also scoped to the exact origin, and redirects are rejected.

## Service contract

All routes require an active owner session or an unrevoked owner agent key. POST
requests using a browser session also require the usual CSRF token. Responses
are private and not cached.

| Route | Purpose |
| --- | --- |
| `GET /api/bots/:id/git` | Advertise `main`, its accepted object ID, canonical revision ID and limits. |
| `POST /api/bots/:id/git/objects` | Read up to 128 known object IDs, with bounded batches and a remainder list. |
| `POST /api/bots/:id/git/push` | Submit a bounded `{base, head, objects}` update with `X-Clunkyard-Request` as its UUID operation ID. |
| `POST /api/bots/:id/git/push/:operationId` | Resolve the durable operation without another provider push. |

Objects carry `{oid, type, data}` where `data` is canonical base64 and `type` is
`blob`, `tree` or `commit`. The server verifies Git SHA-1 object IDs, tree paths,
modes, ancestry, all new commit trees and source limits before writing. Supplied and retained
objects share one aggregate decoded-byte budget; retained object sizes are
checked before their bodies are loaded. Objects
must be reachable from the accepted head. Existing object bytes cannot change.
Raw Git packs, client configuration and hooks are never run on the server.
