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 from npm. On Linux, macOS or WSL, use a user-owned prefix:
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:
npm install --global @clunkyard/git
clunkyard-git login
The helper needs only Git and Node. The shared @clunkyard/cli 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:
# 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:
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:
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.