gitstalk
Docs: Git compatibility

Git compatibility live

It is just git. Clone, branch, commit and push with the git you already have. Pushing a bean/<name> branch submits a change; the verdict comes back on the push and as a ref anyone can fetch. Nothing is installed on the client beyond a credential.

Push a change, read the verdict

$ git clone https://gitstalk.dev/acme/api.git && cd api
$ git switch -c add-truncate origin/sprout
# edit, then
$ git commit -am "Add truncate(text, n)"
$ git push -o wait origin HEAD:refs/heads/bean/add-truncate
remote: gitstalk: new bean add-truncate received at 3f9a1c2: "Add truncate(text, n)"
remote: gitstalk: pre-land check started: your change is merged onto the sprout and the whole suite runs on that tree
remote: gitstalk: LANDED: add-truncate passed its pre-land check and is on the sprout as 8d41e07
remote: gitstalk:   it moves to the stalk once CI validates the sprout; git fetch origin sprout stalk
-o wait holds the push open until the bean has a verdict. Without it the push returns as soon as the bean is received.

When a bean comes back red, the push says what broke, and which landed beans it collided with:

$ git push -o wait origin HEAD:refs/heads/bean/tax-in-total
remote: gitstalk: RED: tax-in-total was not landed. Merged onto the sprout, these tests failed:
remote: gitstalk:   - test/discount.test.js
remote: gitstalk: it collided with these landed beans (accepted behaviour; keep both):
remote: gitstalk:   - add-discount "Add percentage discounts"
remote: gitstalk:     intent: discounted(items, rate) takes rate off the cart total.
remote: gitstalk: output:
remote: gitstalk:   not ok 1 - discounted takes 10% off a 100.00 cart
remote: gitstalk:   expected 90, got 99
remote: gitstalk: fix: git fetch origin sprout && git rebase origin/sprout
remote: gitstalk:      then fix, commit and git push -f origin HEAD:refs/heads/bean/tax-in-total
remote: gitstalk:      and keep working; git push -o bean=tax-in-total origin HEAD:refs/wait/any waits for its next verdict
A red names the failing tests, the landed beans it collided with and their intent, the suite output and the exact commands to fix it. A conflict quotes the conflicting hunks (up to 40 lines), both sides, and who landed the sprout's side.

Every refusal and verdict message is explained, keyed by its exact text, in Troubleshooting.

URLs

A repository is cloned from the web host, where its page is, with a GitHub-style URL (the .git suffix optional). The repository page shows it:

Terminal
git clone https://<host>/<owner>/<repo>.git

The older gateway URL, https://<gateway host>/git/<owner>/<repo>.git, still works. A repository you may not see answers 404, exactly as a missing one does, on every transport.

SSH planned

Git over SSH is built, not public yet. SSH on port 22 needs a paid Cloudflare feature (Spectrum), so it is not offered. It has been tested end to end on a staging stack. HTTPS works today. What is live: you can register an SSH key in Settings (/gitstalk:setup does it for you), which approves your machine, but the git remote it sets is an HTTPS URL. Once SSH is public, remotes will look like ssh://git@<ssh host>/<owner>/<repo>.git and follow the same rules as HTTPS in every row below.

Push is submit

You push What happens
refs/heads/bean/<name>, a new name A new bean. Its title is the commit subject, its intent the message. A Task: <id> trailer links a task.
the same bean after a red or a conflict The fix: the new head is checked again. Force-push after a rebase is expected.
a new commit to a bean still in check Refused: its verdict comes first. The message says how to wait for it.
a bean that already landed, or is parked or dropped Refused: push the work again as a new bean.
sprout, stalk, main Refused: landing is never a push. Only the engine moves these lines.
any other ref, a deletion, two beans at once Refused, with the rule.

Refusals happen inside the git protocol, before anything reaches storage, so git prints a normal ! [remote rejected] line with the reason rather than an HTTP error. Bean names start with a letter or digit, then use letters, digits, ., _ and -, up to 32 characters in all.

Push options

Option Effect
-o wait Hold the push until the verdict: landed, red, conflict, parked or dropped. Progress lines as the engine reports them and a keepalive every 15 s; gives up after 600 s and says where the verdict will be.
-o wait=<seconds> The same, up to 1,800 s.
-o task=<id> Links a task (overrides the trailer).
-o intent=<text> The bean's intent and title, instead of the commit message.
-o bean=<name> On a push to a wait ref (below): a bean to wait for. Repeat it for several.

An unknown option is ignored, and the push says so.

What the push prints

Every line starts remote: gitstalk:. The ones you will meet:

Line starts Meaning
new bean … received The push was accepted as a bean (or a new push to a bean you already had).
pre-land check started Your change is merged onto the sprout and the whole suite runs on that tree.
LANDED It passed and is on the sprout. It moves to the stalk after validation.
RED The merged tree failed. Failing tests, collided beans and the fix commands follow.
CONFLICT It does not merge onto the sprout. Conflicting hunks follow.
PARKED / DROPPED It needs a person (parked), or fell off (dropped), with the reason.
validated: on the stalk The sprout commit passed validation and reached the stalk.
changes protected paths, approval rules What protected paths and approval rules decided.

Status refs

Ref What
refs/heads/sprout The staged line: every landed bean.
refs/heads/stalk The stable line: validated sprout commits.
refs/heads/bean/<name> The bean's pushed head.
refs/beans/<name>/status An annotated tag: <phase>: <reason>, then the verdict's lines.
Phase Meaning
checking The pre-land check is running.
waiting Reserved. Waits count it as checking, but a git push does not write it today (the Changes tab shows waiting for a bean held on a decision or on a red sprout).
landed On the sprout.
green Validated: on the stalk.
red The merged tree failed its checks.
conflict It does not merge onto the sprout.
parked It needs a person.
dropped It fell off.
Read a status
git fetch origin '+refs/beans/*:refs/beans/*'
git for-each-ref 'refs/beans/' --format='%(refname:lstrip=2) %(contents:subject)'
git cat-file -p refs/beans/add-total/status

Waiting without polling

An agent that has pushed several beans and run out of work makes one blocking call that the first verdict wakes. A push to a wait ref stores nothing:

Wait refs
git push -o bean=a -o bean=b origin HEAD:refs/wait/any   # returns at the first verdict
git push -o bean=a -o bean=b origin HEAD:refs/wait/all   # returns when none is checking
git push origin HEAD:refs/wait/all                       # every bean in flight pushed with my credential

It holds up to 9 minutes by default, under the 10-minute limit of an agent's shell tool, and prints each verdict as it arrives. -o wait and MCP bean_wait use the same wait: the verdict wakes them, nothing polls. Why it exists: agents replaced blocking pushes with sleep loops.

Importing and leaving

Any public git URL can be imported when you create a repository. Importing a private repository and two-way sync with another forge are planned. Your history stays plain git: clone it, and push it anywhere else. Branch names other than bean/*, sprout and stalk are not accepted on push today, and tag pushes are refused.

Sources