Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

303 lines · 21.3 KBRaw History
1---
2title: Profile and preferences
3description: Change your username, display name and profile picture, choose light, dark or system appearance, and link your GitHub account for imports.
4---
5
6Your profile is how other people see you on Diffinery: your username, display name and profile picture. This page also covers the **Appearance** setting (light, dark or following your system), **Linked accounts** (your GitHub account, for imports) and points to every other per-user setting under **Settings**.
7
8## Where your settings are
9
10Open **Settings** by clicking your picture and username at the top right of any page, or go to `https://diffinery.com/settings`. The sidebar has these pages:
11
12| Page | Path | What it holds |
13| --- | --- | --- |
14| **Profile** | `/settings` | Profile picture, username, display name, and read-only account details |
15| **Account** | `/settings/account` | Exporting your data and deleting your account. See [Exporting and deleting your account](/docs/accounts/account-data). |
16| **Appearance** | `/settings/appearance` | Light, dark or system theme |
17| **Pull requests** | `/settings/pull-requests` | **Turn on auto-merge for pull requests I open**, and its merge method. See [Merge on green automatically](/docs/collaboration/merge-on-green#your-own-pull-requests). |
18| **Passkeys and sessions** | `/settings/security` | Passkeys and signed-in browsers. See [Passkeys and sign-in](/docs/accounts/passkeys-and-sign-in). |
19| **Access tokens** | `/settings/tokens` | Personal access tokens. See [Personal access tokens](/docs/accounts/tokens). |
20| **Agents** | `/settings/agents` | Agent accounts you or your organizations own. See [Agents](/docs/agents/overview). |
21| **Organizations** | `/settings/orgs` | Organizations you belong to, and creating new ones. See [Organizations](/docs/accounts/organizations). |
22| **Notifications** | `/settings/notifications` | What you hear about in the notifications list and by email. See [Notifications](/docs/accounts/notifications). |
23| **Linked accounts** | `/settings/linked-accounts` | GitHub accounts linked to yours, so imported work is credited to you. See [Linked accounts](#linked-accounts). |
24| **Imports** | `/imports` | The GitHub imports you started, and **Import from GitHub**. See [Migrate from GitHub](/docs/migrate-from-github). |
25
26Site administrators also see a **Site administration** group with **People and invitations**, **Email** and **Audit log** (see [Site administration](/docs/admin/site-administration)).
27
28Every settings page needs you to be signed in in the browser. Profile, appearance and passkey changes can't be made with an access token, except the profile picture, which has an API (see [Profile picture API](#profile-picture-api)).
29
30## Your profile
31
32**Settings → Profile** (`/settings`) has two boxes: **Profile picture** (see [Profile pictures](#profile-pictures)) and a form with:
33
34| Field | Editable | Notes |
35| --- | --- | --- |
36| **Username** | Yes | Your login, the owner part of your repository URLs (`https://diffinery.com/diffy/...`) and your `@mention` handle |
37| **Display name** | Yes | Optional. Shown on your profile page and in the settings sidebar, with your username under it, and returned as `name` by the API. If you leave it blank (or enter only spaces), Diffinery shows your username in its place and the API returns `"name": null`. |
38| **Email** | No | Your account's email address. Notification emails go here. It can't be changed in Settings. |
39| **Account type** | No | `user` for a person |
40| **Joined** | No | When the account was created |
41| **Site admin** | No | `yes` for site administrators, otherwise `no` |
42
43Change the username or display name and click **Save profile**. You see "Profile saved."
44
45Your public profile page is `https://diffinery.com/diffy`. It shows your picture, display name, username, your organizations and the repositories the viewer can see. On your own profile page there is an **Edit profile** button that opens **Settings → Profile**. Profile pages need the viewer to be signed in.
46
47### Change your username
48
49A username starts with a letter or digit, then uses letters, digits, `-` and `_`, up to 100 characters. Dots aren't allowed, and the name can't be reserved (for example `api`, `settings`, `login`, `admin`, `docs`) or already used by a person, organization or agent. The **Username** field checks the characters in your browser before you save, with the same rules as the server; the organization and agent name fields work the same way.
50
51Renaming changes the URL of every repository you own. The old URLs keep working (see [Old URLs after a transfer or rename](/docs/repositories/overview#old-urls-after-a-transfer-or-rename) for how each kind behaves), but update existing clones:
52
53```sh
54git remote set-url origin https://diffinery.com/new-name/website.git
55```
56
57After a rename, `https://diffinery.com/old-name` and your repositories' old web and API URLs redirect to the new name, and Git and container images keep being served under the old name, until someone else takes the old name, which is free for them to take. Your picture moves with you: Diffinery forgets cached copies of the picture under the old name.
58
59| Message | What to do |
60| --- | --- |
61| "invalid or reserved login" | The name is reserved, or breaks the rules above. Pick another. |
62| "login already taken" | Another person, organization or agent uses it. Pick another. |
63
64There is no API for changing your username or display name; use the web UI. `GET /api/v3/user` returns them as `login` and `name`.
65
66## Profile pictures
67
68People and organizations can upload a profile picture. Without one, Diffinery draws a picture from the first letter or digit of the name (see [Initials when there is no picture](#initials-when-there-is-no-picture)). Pictures appear next to your name everywhere in the web UI: the header, comments, pull requests, member and collaborator lists, and the user and organization pages.
69
70### Upload your picture in the web UI
71
721. Go to **Settings → Profile** (`/settings`).
732. In the **Profile picture** box, under **Upload a new picture**, choose a file. The hint reads "JPEG, PNG or WebP, up to 5 MB. It is cropped to a centred square."
743. The current picture is replaced by a preview of the cropped square, with "Preview. Save to use this picture." If your browser can't open the file, you see "No preview for this file; it will be checked when you save."
754. Click **Save picture**. The status shows "Uploading…", then the page reloads with "Profile picture updated."
76
77Your browser does part of the work before uploading: it cuts out the centred square, shrinks it to at most 512 by 512 pixels and converts it to WebP (or PNG, if the browser can't produce WebP). The server then checks and processes that upload like any other. If the browser can't decode the file, it uploads the original file and the server's checks decide.
78
79### What Diffinery does with a picture
80
81| Step | Detail |
82| --- | --- |
83| Format check | The format is detected from the file's first bytes, not its name or `Content-Type`. JPEG, PNG and WebP are accepted. Anything else (GIF, HEIC, SVG, ...) is refused with "Use a JPEG, PNG or WebP image." |
84| Size check | At most 5 MB (5,242,880 bytes) and at most 3072 by 3072 pixels |
85| Crop | The centred square of the picture is kept; the rest of a non-square picture is cut off. There is no manual crop control. |
86| Orientation | The EXIF orientation of a JPEG (as written by phone cameras) is applied, so the picture isn't sideways |
87| Resize | The square is resized to 64, 128 and 256 pixels |
88| Encode | Each size is saved as WebP (quality 80). The original upload isn't kept. |
89| Replace | The previous picture's files are deleted |
90
91Transparent areas of a PNG or WebP stay transparent.
92
93### Limits for profile pictures
94
95| Limit | Value |
96| --- | --- |
97| Formats | JPEG, PNG, WebP |
98| File size | 5 MB |
99| Dimensions | 3072 by 3072 pixels |
100| Stored sizes | 64, 128 and 256 pixels square, WebP |
101
102### Remove your picture
103
104When you have a picture, the **Profile picture** box has a **Remove picture** button ("Shows initials instead."). Click it and confirm "Remove your profile picture?". You see "Profile picture removed." and your initials come back everywhere.
105
106### Initials when there is no picture
107
108Without an uploaded picture, Diffinery serves a generated SVG picture: the first letter or digit of the name in white, upper case, on a colored background. The color is computed from the name, so it stays the same for that name. A name with no letters or digits shows `?`.
109
110In the web UI, people and organizations appear as circles and agents as rounded squares.
111
112### Organization pictures
113
114An organization's picture is managed on its **Settings** tab (`https://diffinery.com/acme?tab=settings`), which only organization owners (and site administrators) can open. It has the same **Profile picture** box:
115
1161. Open the organization, click **Settings**.
1172. Under **Upload a new picture**, choose a file and click **Save picture**. You see "Organization picture updated."
1183. To go back to initials, click **Remove picture** and confirm "Remove the picture of acme?". You see "Organization picture removed."
119
120Through the API, organization owners (and site administrators) can change the picture; see the next section. Organization admins and members can't change it.
121
122### Agent pictures
123
124The web UI has no upload control for agents, so they show initials until a picture is uploaded. An agent can set its own picture through the API with one of its own tokens, the same way a person does (`PUT /api/v3/user/avatar`).
125
126### Profile picture API
127
128These endpoints are a Diffinery extension (GitHub has no API for uploading a profile picture). The request body is the raw image file, not a form or JSON.
129
130| Method and path | Who | Response |
131| --- | --- | --- |
132| `PUT /api/v3/user/avatar` | You (the token's account) | `200` with `{"avatar_url": "..."}` |
133| `DELETE /api/v3/user/avatar` | You | `200` with `{"avatar_url": "..."}` (the initials URL) |
134| `PUT /api/v3/orgs/{org}/avatar` | Owners of the organization, site administrators | `200` with `{"avatar_url": "..."}` |
135| `DELETE /api/v3/orgs/{org}/avatar` | Owners of the organization, site administrators | `200` with `{"avatar_url": "..."}` |
136
137The token needs the `write` or `admin` scope and must not be restricted to repositories. A browser session works too.
138
139Upload a picture:
140
141```sh
142curl -X PUT https://diffinery.com/api/v3/user/avatar \
143 -H "Authorization: Bearer dfy_..." \
144 --data-binary @me.jpg
145```
146
147```json
148{ "avatar_url": "https://diffinery.com/api/avatars/diffy?v=1760350000" }
149```
150
151The `v` value is the new picture's version. Upload an organization's picture:
152
153```sh
154curl -X PUT https://diffinery.com/api/v3/orgs/acme/avatar \
155 -H "Authorization: Bearer dfy_..." \
156 --data-binary @logo.png
157```
158
159Remove it again:
160
161```sh
162curl -X DELETE https://diffinery.com/api/v3/user/avatar -H "Authorization: Bearer dfy_..."
163```
164
165```json
166{ "avatar_url": "https://diffinery.com/api/avatars/diffy" }
167```
168
169The `diffinery api` CLI command sends text bodies only, so use `curl` (or another HTTP client) to upload a picture.
170
171Errors:
172
173| Status | Message | Cause |
174| --- | --- | --- |
175| 401 | `sign in required` | No token was sent |
176| 403 | `changing a profile picture needs a write or admin token that is not limited to repositories` | The token has only the `read` scope, or is restricted to repositories |
177| 403 | `only organization owners can change its picture` | You are an admin or member of the organization, but not an owner |
178| 404 | `not found` | The organization doesn't exist, or you aren't a member |
179| 413 | `That picture is larger than 5 MB. Use a smaller file.` | The body is over 5 MB |
180| 422 | `Send the picture as the request body.` | The request had no body |
181| 422 | `Use a JPEG, PNG or WebP image.` | The body isn't JPEG, PNG or WebP |
182| 422 | `That picture could not be read. Use a JPEG, PNG or WebP image.` | The file is damaged or its header can't be read |
183| 422 | `That picture is 4000×3000 pixels; the limit is 3072×3072.` | The picture is larger than 3072 by 3072 pixels |
184
185Error bodies are JSON with a `message` field, like every API error.
186
187Every change is recorded in the audit log as `avatar.update` or `avatar.remove`, with the account kind and whether it came from the web UI or the API.
188
189### The avatar URL
190
191Every person, organization and agent has a picture at:
192
193```text
194https://diffinery.com/api/avatars/{login}
195```
196
197This is the `avatar_url` in every user and organization object the REST API returns (for example `GET /api/v3/user`, the `user` of an issue, or `owner` of a repository), as on GitHub.
198
199| Query parameter | Values | Default |
200| --- | --- | --- |
201| `s` | Size in pixels. Diffinery serves the smallest stored size at least this big: `64`, `128` or `256`. Larger values get `256`. | `128` |
202| `v` | A picture version, as returned by the upload API. Pins the URL to that picture so it can be cached for a long time. | none |
203
204```sh
205# The 64-pixel picture of diffy
206curl -o diffy.webp "https://diffinery.com/api/avatars/diffy?s=64"
207```
208
209The response is `image/webp` for an uploaded picture, or `image/svg+xml` for initials. The URL needs no sign-in or token, so you can use it in `<img>` tags, README files and other tools. A name that doesn't exist also gets an initials picture, so the URL doesn't reveal which accounts exist.
210
211### Caching
212
213| URL | `Cache-Control` | When a new picture shows up |
214| --- | --- | --- |
215| With the current `v` | `public, max-age=86400, immutable` | Never changes; a new picture gets a new `v` |
216| Without `v` (or with an old `v`) | `public, max-age=600, stale-while-revalidate=86400` | Within about 10 minutes |
217
218The header, the settings pages, profile and organization pages and member lists use the versioned URL, so your new picture shows there right away after you save. Other places use the plain URL (for example issue and pull request conversations in the web UI, API clients and other sites), so they can show the old picture for up to about 10 minutes, and browsers may show a cached copy a little longer while they check for a new one. Diffinery also keeps a copy at Cloudflare's edge for up to 10 minutes; uploading or removing a picture clears that copy in the data center that handled the change, and other data centers pick up the change when their copy expires.
219
220## Appearance
221
222**Settings → Appearance** (`/settings/appearance`) sets the color theme of the web UI. The page says "Choose how Diffinery looks to you. The choice follows your account to every browser you sign in to."
223
224| Theme option | Description in the page | Behaviour |
225| --- | --- | --- |
226| **Sync with system** | "Light or dark, following your device's setting." | The default. Follows your operating system or browser's light or dark mode, and switches when it does. |
227| **Light** | "Always light." | Always the light theme |
228| **Dark** | "Always dark." | Always the dark theme |
229
230To change it:
231
2321. Go to **Settings → Appearance**.
2332. Under **Theme**, pick **Sync with system**, **Light** or **Dark**.
2343. Click **Save appearance**. You see "Appearance saved."
235
236### How the appearance setting is stored and applied
237
238- The choice is saved on your account, so every browser you sign in to uses it from the next page you open. There is no need to set it per device.
239- The page is rendered with the theme already applied, so there is no flash of the wrong theme while it loads, and it works with JavaScript turned off.
240- Saving **Light** or **Dark** also stores the choice in a cookie in the browser you saved it from (`dfy_theme`, kept for 400 days). Pages you open there while signed out, such as the sign-in page, invite pages and these docs, use it too. Saving **Sync with system** removes the cookie.
241- In other browsers, pages you open while signed out follow the system setting until you sign in.
242- The theme applies to every page of the web UI, including syntax-highlighted code and diffs, which use the GitHub Light Default and GitHub Dark Default color themes.
243- Emails aren't affected: they follow the light or dark mode of your mail app.
244
245There is no API or CLI command for the appearance setting.
246
247## Linked accounts
248
249**Settings → Linked accounts** (`/settings/linked-accounts`) is the **Linked GitHub accounts** page. When someone [imports from GitHub](/docs/migrate-from-github), issues, pull requests, comments and reviews written by a linked GitHub account are credited to your Diffinery account instead of a placeholder ("mannequin") for the GitHub user. Link your account before the import runs: work that was already imported stays with the mannequin.
250
251### Link with a public gist
252
253No GitHub token is needed:
254
2551. Under **Step 1 · get a code**, leave **GitHub Enterprise API URL** blank for github.com, or enter your GitHub Enterprise API URL (for example `https://ghe.example.com/api/v3`), and click **Get my code**.
2562. Copy the code (it starts with `diffinery-link-`). On GitHub, create a **public** gist whose description or one of whose files contains it.
2573. Under **Step 2 · verify your gist**, enter **Your GitHub username on github.com** (or on your Enterprise host) and click **Verify and link**. You see "GitHub account linked."
258
259Diffinery reads your public profile and gists without a token, from that one GitHub host, and stores GitHub's numeric user id with the link, so a later rename of your GitHub account doesn't break it. You can delete the gist afterwards.
260
261### Link with GitHub OAuth
262
263If the site administrator configured a GitHub OAuth app, the page also has **Link with GitHub**: click **Continue to GitHub**, approve read-only access to your profile, and you come back with the account linked. OAuth links github.com accounts only; use a gist for GitHub Enterprise.
264
265### Manage your links
266
267- Each link shows the GitHub login, the host (`on github.com`) and when it was linked. Click **Unlink** and confirm "Unlink diffy?" to remove it; you see "Account unlinked."
268- You can link several GitHub accounts (for example one on github.com and one on an Enterprise host). A GitHub account can be linked to only one Diffinery account.
269- Only people can link accounts; agents can't.
270- Linking, unlinking and a site administrator clearing a link are recorded in the audit log (`account.link_github`, `account.unlink_github`, `account.link_cleared`).
271- The same actions are available in the REST API under `/api/v3/diffinery/user/linked-accounts` with a personal token that has the `admin` scope and isn't restricted to repositories. See [Link your GitHub account](/docs/migrate-from-github#link-your-github-account).
272
273| Message | What to do |
274| --- | --- |
275| "create a PUBLIC gist whose description or a file contains diffinery-link-..., then try again" | Make sure the gist is public (not secret) and contains the exact code, then click **Verify and link** again. |
276| "GitHub user diffy was not found" | Check the username and, for Enterprise, the API URL. |
277| "GitHub user diffy is linked to another Diffinery account" | Unlink it from that account first, or ask a site administrator to clear the link. |
278
279## Notification preferences
280
281Your notification preferences (which groups you hear about in the notifications list and by email, watching new repositories, emails about your own activity) are on **Settings → Notifications**, and can also be read and changed with `GET` and `PUT /api/v3/diffinery/notification-settings`. See [Notifications](/docs/accounts/notifications#notification-settings).
282
283## How profiles differ from GitHub
284
285- There is no bio, location, website, company, pronouns or status field. The profile has a username, a display name and a picture.
286- Your email address comes from your invitation and isn't editable in Settings. Diffinery has no list of secondary email addresses.
287- Profile pictures are uploaded to Diffinery. There is no Gravatar support (`gravatar_id` is always empty in API responses).
288- Diffinery has an API to upload and remove profile pictures for users and organizations; GitHub doesn't.
289- GitHub's theme settings have more options (for example separate day and night themes and high-contrast themes). Diffinery has light, dark and sync with system.
290- After a username change, Diffinery redirects your profile and your repositories' old web, API and Git URLs until someone takes the old name; GitHub redirects the repositories only.
291
292## Troubleshooting
293
294| Message or symptom | What to do |
295| --- | --- |
296| "That picture is larger than 5 MB. Use a smaller file." | Use a file of 5 MB or less. In the web UI, files the browser can open are shrunk before uploading, so this mostly happens with the API or with files the browser can't preview. |
297| "Use a JPEG, PNG or WebP image." | Convert the picture to JPEG, PNG or WebP. |
298| "That picture is ... pixels; the limit is 3072×3072." | Resize the picture to at most 3072 by 3072 pixels, or upload it in the web UI, which shrinks it first. |
299| "Choose a picture to upload." | Pick a file before clicking **Save picture**. |
300| The old picture still shows in comments or in another tool | Those places use the unversioned avatar URL, which can be cached for about 10 minutes. Wait, or in your own tools use the URL with `?v=` from the upload response. |
301| `403 changing a profile picture needs a write or admin token...` | Create a token with the `write` or `admin` scope and no repository restriction, under **Settings → Access tokens**. |
302| The theme doesn't change on the sign-in page | Signed-out pages use the cookie of the browser where you last saved **Light** or **Dark**, or the system setting. Sign in, or save the setting again in this browser. |
303| "login already taken" or "invalid or reserved login" | See [Change your username](#change-your-username). |