{{define "content"}}

Polar for AI agents

A practical guide to cloning, pushing, publishing and automating this Git host.
GET /agents

Overview

Polar is a self-hosted Git forge at {{.SiteURL}}. It serves standard Git over HTTPS (smart HTTP) plus a web UI for issues, pull requests, releases and repository settings. Everything the UI does is a plain HTML form POST — there is no separate REST API for repositories, so agents drive the same endpoints.

Authentication: device flow

Git over HTTPS uses the OAuth 2.0 Device Authorization Grant (RFC 8628): the client asks for a short user code, the human approves it in the browser once, and the client receives a personal access token.

  1. Request a device code from POST /api/v1/device/code with a client_id.
  2. Send the user to verification_uri_complete (they must be signed in to Polar).
  3. Poll POST /api/v1/device/token with device_code every interval seconds (default 5). While the grant is pending the endpoint answers 429 {"error":"authorization_pending"}.
  4. On approval you receive {"access_token":"...","token_type":"bearer","username":"...","scope":"git"}.
# 1. Start a device grant (no browser session required for this step)
curl -sX POST {{.SiteURL}}/api/v1/device/code -d 'client_id=my-agent'
# {"device_code":"...","user_code":"WDJB-MJHT","verification_uri":"{{.SiteURL}}/login/device",
#  "verification_uri_complete":"{{.SiteURL}}/login/device?user_code=WDJB-MJHT","expires_in":600,"interval":5}

# 2. Ask the user to open verification_uri_complete and approve.

# 3. Exchange the approved device code for a token
curl -sX POST {{.SiteURL}}/api/v1/device/token -d 'device_code=DEVICE_CODE'
# {"access_token":"...","token_type":"bearer","username":"rin","scope":"git"}

Use the token as the password for HTTPS Git with any username:

git clone https://USERNAME:TOKEN@HOST/OWNER/REPO.git

This is the same handoff a fresh git push triggers: Polar opens the approval page and the credential helper waits for it. For scripts, scripts/git-credential-polar.sh automates the flow and caches tokens in ~/.polar/credentials.json:

git config --global credential.helper '!sh /path/to/polar/scripts/git-credential-polar.sh'

Tokens are listed and revocable under Settings → Access tokens. Device codes are single-use and expire after expires_in seconds.

Git operations

  • Clone / fetch / push: https://HOST/OWNER/REPO.git — standard smart HTTP.
  • Branches and tags: push them normally; Polar stores refs and shows them in the UI.
  • Public repositories: readable anonymously when anonymous read is enabled on the instance.
  • Private repositories: every Git request needs credentials — unauthenticated requests get 401, while the web UI answers 404 so it does not leak existence.
  • Empty repositories: the first git push -u origin main creates the default branch.

Driving the web UI from a script

The UI is server-rendered HTML with plain forms, which makes it fully scriptable:

  • Sign in by POSTing /login (username, password) and keeping the polar_session cookie.
  • Every non-GET request needs the session CSRF token: read the hidden _csrf input from any page and send it as the _csrf form field or the X-CSRF-Token header.
  • File uploads are multipart/form-data.
# Close an issue (state: open|closed)
curl -b cookies.txt -X POST https://HOST/OWNER/REPO/issues/1/state \
  -H "X-CSRF-Token: $CSRF" -d 'state=closed'

# Comment on an issue
curl -b cookies.txt -X POST https://HOST/OWNER/REPO/issues/1/comments \
  -H "X-CSRF-Token: $CSRF" -d 'body=Fixed in the latest build.'

# Open a pull request (head_branch must already be pushed)
curl -b cookies.txt -X POST https://HOST/OWNER/REPO/pulls/new \
  -H "X-CSRF-Token: $CSRF" \
  -d 'title=Rework uploads' -d 'body=Release notes...' \
  -d 'base_branch=main' -d 'head_branch=feature/uploads'

# Review and merge a pull request
curl -b cookies.txt -X POST https://HOST/OWNER/REPO/pulls/4/review \
  -H "X-CSRF-Token: $CSRF" -d 'state=approved' -d 'body=LGTM'
curl -b cookies.txt -X POST https://HOST/OWNER/REPO/pulls/4/merge \
  -H "X-CSRF-Token: $CSRF"

Other form endpoints: POST /OWNER/REPO/issues/new (title, body), POST /OWNER/REPO/upload (files, ref, path, message), POST /OWNER/REPO/settings/collaborators/add, POST /OWNER/REPO/fork.

Releases and artifacts

Releases group a git tag, notes and uploaded files. Publishing one is a single multipart POST:

curl -b cookies.txt -X POST https://HOST/OWNER/REPO/releases/new \
  -H "X-CSRF-Token: $CSRF" \
  -F 'tag_name=v1.2.0' -F 'target_ref=main' \
  -F 'title=v1.2.0' -F 'body=Release notes...' -F 'is_prerelease=true' \
  -F 'assets=@dist/app-linux-amd64' -F 'assets=@dist/app-windows-amd64.exe'
  • The tag is created automatically if missing, pointing at target_ref.
  • Up to 20 assets per release, 100 MB per file. Filenames are sanitized; assets can be deleted individually from the release card.
  • Asset downloads support HTTP Range: GET /OWNER/REPO/releases/<id>/assets/<assetID>/download.
  • Tag archives are always available: GET /OWNER/REPO/archive/v1.2.0.zip or .tar.gz.
  • Raw file contents: GET /OWNER/REPO/raw/<ref>/<path>.

Working agreements

  • Prefer branches and pull requests over pushing straight to the default branch in shared repositories.
  • Match the repository's commit message style; explain the change, not the process.
  • Use tags for release points and attach artifacts with stable names (for example polar-linux-amd64).
  • Treat tokens as secrets: never commit them, and revoke what you no longer need.
  • Poll the device token endpoint no faster than the advertised interval; back off on 429.

Static documentation. Endpoint names match this instance; if a field name ever changes, read it from the corresponding HTML form.

{{end}}