Skip to main content

max / makenotwork

docs: the git notes JSON API
Author: Max Johnson <me@maxj.phd> · 2026-08-09 02:42 UTC
Signed with PGP, not checked
Commit: 1c0534ed202e2a89bbd99740e7d7a22beb936ffa
Parent: f1146e9
1 file changed, +34 insertions, -0 deletions
@@ -81,6 +81,40 @@
81 81
82 82 Your notes are safe in the inbox ref and the next push to that namespace merges them.
83 83
84 + ## Reading and Writing Notes From a Script
85 +
86 + There is a JSON API under `/api/git/username/repo-name/notes`, for tooling that wants to annotate a commit without running git. A build script recording its result, a review bot recording a verdict.
87 +
88 + Reads need no credential on a public repository:
89 +
90 + ```
91 + curl https://makenot.work/api/git/username/repo-name/notes
92 + curl 'https://makenot.work/api/git/username/repo-name/notes/<commit>?namespace=review'
93 + curl 'https://makenot.work/api/git/username/repo-name/notes/search?q=timeout'
94 + ```
95 +
96 + Writes need a personal access token with push permission, the same token `git push` over HTTPS uses. Create one under Access Tokens on your SSH keys settings page, and send it as the HTTP Basic password. The username half is ignored:
97 +
98 + ```
99 + curl -u x:$MNW_TOKEN -X PUT \
100 + -H 'Content-Type: application/json' \
101 + -d '{"namespace":"builds","content":"passed on 2 targets"}' \
102 + https://makenot.work/api/git/username/repo-name/notes/<commit>
103 +
104 + curl -u x:$MNW_TOKEN -X DELETE \
105 + 'https://makenot.work/api/git/username/repo-name/notes/<commit>?namespace=builds'
106 + ```
107 +
108 + A write is a real git commit on `refs/notes/<namespace>`, so a note written this way is fetched, read and pushed like any other. Two writers annotating the same commit are merged rather than one overwriting the other, and the response says `"merged": true` when that happened, meaning the stored note is not exactly what you sent.
109 +
110 + A session cookie is not accepted for writes. A token is, which is what a script has.
111 +
112 + Namespace and content rules are the browser's: `refs/notes/mnw/*` is refused, and content is capped at 50,000 characters.
113 +
114 + Search is the one endpoint answered from the index rather than from your repository, since a full-text query cannot be served by walking a tree. Its response carries `"indexed": false` when MNW has not yet indexed the repository, so an empty result is never mistaken for no matches.
115 +
116 + The full request and response shapes are in the [OpenAPI spec](https://makenot.work/api/openapi.json), under the Git Notes tag.
117 +
84 118 ## Namespaces
85 119
86 120 The default namespace is `commits`, which is what bare `git notes` uses. Any other name gives you a separate track of annotation on the same commits: `review`, `design`, `deploys`.