rin
Public Open-source lightweight git hosting.
agents.html · 107 lines · 7.8 KB
Raw
1 {{define "content"}}
2 <div class="container" style="max-width:880px;">
3 <div class="flex items-start justify-between flex-wrap gap-2 mb-4">
4 <div>
5 <h1 class="text-xl font-bold tracking-tight" style="margin:0;">Polar for AI agents</h1>
6 <div class="text-xs text-muted mt-1">A practical guide to cloning, pushing, publishing and automating this Git host.</div>
7 </div>
8 <span class="badge badge-outline font-mono text-xs">GET /agents</span>
9 </div>
10
11 <article class="card">
12 <div class="card-body markdown-body">
13 <h2>Overview</h2>
14 <p>Polar is a self-hosted Git forge at <code>{{.SiteURL}}</code>. It serves standard <strong>Git over HTTPS</strong> (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.</p>
15
16 <h2>Authentication: device flow</h2>
17 <p>Git over HTTPS uses the <strong>OAuth 2.0 Device Authorization Grant (RFC 8628)</strong>: the client asks for a short user code, the human approves it in the browser once, and the client receives a personal access token.</p>
18 <ol>
19 <li>Request a device code from <code>POST /api/v1/device/code</code> with a <code>client_id</code>.</li>
20 <li>Send the user to <code>verification_uri_complete</code> (they must be signed in to Polar).</li>
21 <li>Poll <code>POST /api/v1/device/token</code> with <code>device_code</code> every <code>interval</code> seconds (default 5). While the grant is pending the endpoint answers <code>429 {"error":"authorization_pending"}</code>.</li>
22 <li>On approval you receive <code>{"access_token":"...","token_type":"bearer","username":"...","scope":"git"}</code>.</li>
23 </ol>
24 <pre><code># 1. Start a device grant (no browser session required for this step)
25 curl -sX POST {{.SiteURL}}/api/v1/device/code -d 'client_id=my-agent'
26 # {"device_code":"...","user_code":"WDJB-MJHT","verification_uri":"{{.SiteURL}}/login/device",
27 # "verification_uri_complete":"{{.SiteURL}}/login/device?user_code=WDJB-MJHT","expires_in":600,"interval":5}
28
29 # 2. Ask the user to open verification_uri_complete and approve.
30
31 # 3. Exchange the approved device code for a token
32 curl -sX POST {{.SiteURL}}/api/v1/device/token -d 'device_code=DEVICE_CODE'
33 # {"access_token":"...","token_type":"bearer","username":"rin","scope":"git"}</code></pre>
34 <p>Use the token as the password for HTTPS Git with any username:</p>
35 <pre><code>git clone https://USERNAME:TOKEN@HOST/OWNER/REPO.git</code></pre>
36 <p>This is the same handoff a fresh <code>git push</code> triggers: Polar opens the approval page and the credential helper waits for it. For scripts, <code>scripts/git-credential-polar.sh</code> automates the flow and caches tokens in <code>~/.polar/credentials.json</code>:</p>
37 <pre><code>git config --global credential.helper '!sh /path/to/polar/scripts/git-credential-polar.sh'</code></pre>
38 <p>Tokens are listed and revocable under <em>Settings → Access tokens</em>. Device codes are single-use and expire after <code>expires_in</code> seconds.</p>
39
40 <h2>Git operations</h2>
41 <ul>
42 <li><strong>Clone / fetch / push:</strong> <code>https://HOST/OWNER/REPO.git</code> — standard smart HTTP.</li>
43 <li><strong>Branches and tags:</strong> push them normally; Polar stores refs and shows them in the UI.</li>
44 <li><strong>Public repositories:</strong> readable anonymously when anonymous read is enabled on the instance.</li>
45 <li><strong>Private repositories:</strong> every Git request needs credentials — unauthenticated requests get <code>401</code>, while the web UI answers <code>404</code> so it does not leak existence.</li>
46 <li><strong>Empty repositories:</strong> the first <code>git push -u origin main</code> creates the default branch.</li>
47 </ul>
48
49 <h2>Driving the web UI from a script</h2>
50 <p>The UI is server-rendered HTML with plain forms, which makes it fully scriptable:</p>
51 <ul>
52 <li>Sign in by POSTing <code>/login</code> (<code>username</code>, <code>password</code>) and keeping the <code>polar_session</code> cookie.</li>
53 <li>Every non-GET request needs the session CSRF token: read the hidden <code>_csrf</code> input from any page and send it as the <code>_csrf</code> form field or the <code>X-CSRF-Token</code> header.</li>
54 <li>File uploads are <code>multipart/form-data</code>.</li>
55 </ul>
56 <p><strong>Note:</strong> Personal access tokens (including those issued by the device flow) only authenticate <em>Git over HTTPS</em>. Issues, pull requests, releases and other UI actions require a browser session from password login — a <code>polar_...</code> token cannot replace the session cookie.</p>
57 <pre><code># Close an issue (state: open|closed)
58 curl -b cookies.txt -X POST https://HOST/OWNER/REPO/issues/1/state \
59 -H "X-CSRF-Token: $CSRF" -d 'state=closed'
60
61 # Comment on an issue
62 curl -b cookies.txt -X POST https://HOST/OWNER/REPO/issues/1/comments \
63 -H "X-CSRF-Token: $CSRF" -d 'body=Fixed in the latest build.'
64
65 # Open a pull request (head_branch must already be pushed)
66 curl -b cookies.txt -X POST https://HOST/OWNER/REPO/pulls/new \
67 -H "X-CSRF-Token: $CSRF" \
68 -d 'title=Rework uploads' -d 'body=Release notes...' \
69 -d 'base_branch=main' -d 'head_branch=feature/uploads'
70
71 # Review and merge a pull request
72 curl -b cookies.txt -X POST https://HOST/OWNER/REPO/pulls/4/review \
73 -H "X-CSRF-Token: $CSRF" -d 'state=approved' -d 'body=LGTM'
74 curl -b cookies.txt -X POST https://HOST/OWNER/REPO/pulls/4/merge \
75 -H "X-CSRF-Token: $CSRF"</code></pre>
76 <p>Other form endpoints: <code>POST /OWNER/REPO/issues/new</code> (<code>title</code>, <code>body</code>), <code>POST /OWNER/REPO/upload</code> (<code>files</code>, <code>ref</code>, <code>path</code>, <code>message</code>), <code>POST /OWNER/REPO/settings/collaborators/add</code>, <code>POST /OWNER/REPO/fork</code>.</p>
77
78 <h2>Releases and artifacts</h2>
79 <p>Releases group a git tag, notes and uploaded files. Publishing one is a single multipart POST:</p>
80 <pre><code>curl -b cookies.txt -X POST https://HOST/OWNER/REPO/releases/new \
81 -H "X-CSRF-Token: $CSRF" \
82 -F 'tag_name=v1.2.0' -F 'target_ref=main' \
83 -F 'title=v1.2.0' -F 'body=Release notes...' -F 'is_prerelease=true' \
84 -F 'assets=@dist/app-linux-amd64' -F 'assets=@dist/app-windows-amd64.exe'</code></pre>
85 <ul>
86 <li>The tag is created automatically if missing, pointing at <code>target_ref</code>.</li>
87 <li>Up to 20 assets per release, 100 MB per file. Filenames are sanitized; assets can be deleted individually from the release card.</li>
88 <li>Asset downloads support HTTP <code>Range</code>: <code>GET /OWNER/REPO/releases/&lt;id&gt;/assets/&lt;assetID&gt;/download</code>.</li>
89 <li>Tag archives are always available: <code>GET /OWNER/REPO/archive/v1.2.0.zip</code> or <code>.tar.gz</code>.</li>
90 <li>Raw file contents: <code>GET /OWNER/REPO/raw/&lt;ref&gt;/&lt;path&gt;</code>.</li>
91 </ul>
92
93 <h2>Working agreements</h2>
94 <ul>
95 <li>Prefer branches and pull requests over pushing straight to the default branch in shared repositories.</li>
96 <li>Match the repository's commit message style; explain the change, not the process.</li>
97 <li>Use tags for release points and attach artifacts with stable names (for example <code>polar-linux-amd64</code>).</li>
98 <li>Treat tokens as secrets: never commit them, and revoke what you no longer need.</li>
99 <li>Poll the device token endpoint no faster than the advertised <code>interval</code>; back off on <code>429</code>.</li>
100 </ul>
101
102 <hr>
103 <p class="text-xs text-muted">Static documentation. Endpoint names match this instance; if a field name ever changes, read it from the corresponding HTML form.</p>
104 </div>
105 </article>
106 </div>
107 {{end}}