Five setups
What to expect on Windows with Git for Windows, on a self-hosted forge behind an internal CA, in an organisation with an OAuth policy and SAML, on a headless Codeberg machine, and at the first contact with a host you have never reached.
Not in a joy release yet
The newest joy release is v0.20.0, and it carries no joy-forge
binary, no joy forge command group and no pinned host key file. This
page describes the release that brings them, so that it is written down
before it lands. Until that release is out, cargo install joy-cli and
the installers place joy alone, and joy forge is not a command.
These five setups are the ones support is asked about. Each one says what joy does, what you have to do, and what is honestly still open.
Windows with a default Git for Windows install
What the machine looks like: credential.helper=manager, no sh on the
PATH, no ssh agent service running (Windows ships it disabled), and a
machine-wide proxy in the registry.
What joy does:
- Tokens first. On this machine "no working local ssh credential" is the normal state, so joy reaches an https remote with a token and does not spend a round trip on ssh first.
- Your helper is run directly. joy resolves
managertogit-credential-manager.exethrough the Git for Windows install path in the registry, and never builds the stringgit credential-managerand never runsgit. A helper value that is shell shaped runs under the Git for Windowsusr\bin\sh.exefrom that same registry entry, so a missingshon the PATH does not matter. - The registry proxy applies even when joy names no proxy of its own. Per-user browser settings, PAC files and WPAD do not.
- Key files are checked first. The Windows crypto backend the ssh layer is built against reads classic PEM only: it has no ed25519, no ECDSA and no DSA, and it does not read the OpenSSH key format. joy says so by name for each key it had to skip, instead of reporting "error authenticating".
What you do: joy forge login --host github.com (or
--token-stdin), and use the https remote.
A self-hosted forge behind an internal CA
What the machine looks like: an internal GitHub Enterprise Server, GitLab or Gitea, possibly on an IP literal host and a non-default port, with a certificate signed by your organisation's own CA, and no forge CLI installed anywhere.
What your operator does: ship one forges.yaml with the image (see
Forges). With it the host is claimed
and asked with no forge CLI at all, and the sign in runs through the
OAuth application your operator registered on that instance.
The CA is the part that differs per operating system:
- Linux: install it the normal way (
update-ca-certificates), or name it once withca_bundleorca_dirinforges.yaml, or withhttp.sslCAInfo/http.sslCAPathin Git configuration. All three work. - macOS: add the CA to the login or System keychain and mark it
trusted. The
forges.yamland Git configuration keys are refused there with a sentence that says this, because the engine cannot honour them on that system. - Windows: your administrator installs the CA in the Windows certificate store, usually by group policy. The same refusal sentence applies to the file-based keys.
A certificate joy cannot verify surfaces as the state tls_untrusted,
with the issuer of the certificate the host presented in the detail line,
so an intercepting proxy is recognisable rather than a mystery.
An organisation with an OAuth policy and SAML
What the machine looks like: the organisation restricts which OAuth applications may access it, and enforces SAML single sign-on.
What joy does: it tells the two apart and names the next step for each.
needs_org_approval: "Your organisation must approve Joy for this repository", with "open the approval page" as the next step. An organisation owner has to approve the application; nobody on the machine can.needs_sso: "Your organisation requires single sign-on for this login", with "open the sign-on page" as the next step. GitHub returns the authorisation address in the response itself, so that address is what joy offers you.
Two limits, said plainly:
- These two states ship untested. They cannot be exercised without an organisation that has OAuth application restrictions switched on and a second one with SAML enforced. Until such an estate exists, treat the wording of these two states as unproven, and tell us what you saw.
- Per-repository rights on GitHub are not offered. GitHub's OAuth scopes have no read-only scope for a private repository, so a sign in that may read a private repository may also write to it. On GitLab, Gitea and Forgejo a read-only member does get a read-only credential.
Single sign-on for joyint.com itself is a different question and the answer is no: there is no SAML, OIDC or SCIM in the platform, and it is not part of this work.
A headless Codeberg machine
What the machine looks like: a server or a container with a Codeberg remote, no browser, and nobody in front of it.
The Gitea family, which Codeberg runs, offers no device code flow at all. Its sign in is a browser redirect to a loopback address, which needs a browser on that machine. So on a headless box there is exactly one way in, and it is the supported one:
joy forge login --host codeberg.org --token-stdin < /run/secrets/codeberg-tokenThe token is read from standard input, validated against the forge before
it is stored, and never appears in a command line or a process list. If
the machine has no usable credential store, joy stores it in
forge-tokens.json with mode 0600 and says that is where it went.
One thing this family does not offer is token revocation for an OAuth
client, so joy forge logout removes the stored credential and answers
that it revoked nothing, rather than pretending. Revoke the token in
Codeberg's own settings when you want it gone at the forge too.
The first contact with a host you have never reached
What happens: the machine has no line for that host in any known_hosts
file, so nothing on it can say whether the key the host presents is the
right one.
- At a terminal, joy shows the host, the port, the key type and the
fingerprint as
SHA256:followed by base64, which is the exact string the forges publish on their own pages, and asks whether to trust it. On yes it appends one line to the firstUserKnownHostsFile, hashed when your configuration asks for hashing and bracketed when the port is not 22. - On a server or under an agent, joy never asks and never writes. The
contact fails with the state
needs_host_trust, and the message names the host, the port, the fingerprint, the file that needs the line and the exact line to paste there. - A key that changed is refused everywhere, in every mode, and joy never rewrites the line. The message names both fingerprints, the file and the line number, and says the line has to be removed by hand.
What the fingerprint means
The fingerprint is a hash of the key the host just presented. Comparing it against the one the forge publishes is the one moment where a machine in the middle of your connection can be caught. It is worth the ten seconds it takes.
joy can also ship the published keys of the large public forges as a data file beside the binary, so that a fresh container reaches them without a person. That file ships empty today: pinning trades the check above for trust in the joy release, and it would make joy refuse a legitimate key rotation at those hosts until a new file ships. That trade has not been made yet, so an unknown host is refused on a server exactly like any other.
Forges
The forge connector, signing in from the CLI with joy forge, where a token is stored per operating system, and how an operator registers a self-hosted instance.
What joy reads from your machine
The ssh config keys, known_hosts files, proxy sources, certificate stores, credential helpers and forge CLIs joy reads, per operating system.