Account API and device sign-in

Cleetus accounts are shared by cleetus.app, this portal, the IDE, the iPhone companion and the CLI. Clients sign in with OpenID Connect against auth.cleetus.dev and check membership at api.cleetus.dev. This guide describes the hosted identity contract and the account UI in published Cleetus IDE 0.2.0 and extension 1.12.1. See Install and update for downloads and verification instructions. Artifact acceptance does not establish a fresh installed-app account or credential-persistence check.

Endpoints

Sign-in domain https://auth.cleetus.dev
Authorize https://auth.cleetus.dev/oauth2/authorize
Token https://auth.cleetus.dev/oauth2/token
Sign out https://auth.cleetus.dev/logout
Issuer and keys Published by the issuer's /.well-known/openid-configuration
API https://api.cleetus.dev
OpenAPI https://api.cleetus.dev/openapi.json

The API console shows the live issuer, client IDs and redirect URIs for the environment you are viewing.

Use Account in the IDE

Cleetus account and membership view with a labeled local fixture member

Local browser fixture, with a visible test strip and fixture identity. This image does not show a live account, payment or verified customer entitlement.

  1. Open Account in Studio or the native title bar. In a compatible VS Code build, run Cleetus: Account and Membership from the command palette.
  2. Choose Sign in to Cleetus. Your system browser opens Cleetus's hosted sign-in page, where you can use your password manager and an existing Cleetus browser session. The editor does not collect your password or verification code.
  3. Return to the account view to inspect your profile, membership and Verified access. Choose Refresh account when you need a fresh service check.
  4. Use Manage membership or Edit profile for the hosted account controls. Payments and profile changes stay on the Cleetus website.

Cancel sign-in ends the local attempt. A delayed callback cannot sign you back in after cancellation or logout. Sign-in has a five-minute deadline. If another window owns the registered callback port, finish or cancel that attempt first; Cleetus does not guess another port.

A Cleetus account is separate from Claude Code, Codex and ACP provider sign-in. It does not supply their subscriptions, model access or credentials. Native provider login, trust and channel consent remain with the provider. See the IDE account section and coding-agent setup.

Browser return page

IDE 0.2.0 and extension 1.12.1 show a branded Return to Cleetus page after the hosted sign-in response reaches the local callback. Response received means the response arrived; it does not confirm a verified account or membership. Return to the editor where you started sign-in and check Account for the result. You can close the browser tab.

The callback page clears the one-time query parameters from its address and loads no external images, fonts or scripts. It does not display identity, authorization codes or tokens. Provider sign-in remains separate.

Branded Cleetus browser return page with response-received guidance

Local screenshot fixture of the return page. It contains no account identity or OAuth response data and does not establish a live sign-in or accepted installer.

Implement desktop sign-in

Use the authorization code flow with PKCE (S256). The IDE client is public and has no client secret. Read its public client ID and issuer from the deployment's API console; do not use the website client ID for a desktop callback.

  1. Generate random code_verifier, state and nonce, then derive the challenge.
  2. Bind the registered loopback callback http://localhost:47615/callback. The current IDE accepts that exact origin and path. The separately registered cleetus://auth/callback scheme is not implemented as an IDE fallback.
  3. Open the system browser at the authorize endpoint with response_type=code, the IDE client_id, exact redirect_uri, scope=openid email profile, state, nonce, challenge and code_challenge_method=S256.
  4. Accept a single matching callback, then exchange the authorization code and verifier at the token endpoint. Reject mismatched state, duplicate parameters, unregistered redirect origins and paths, and a conflicting issuer.
  5. Verify the ID token's RS256 signature against the pinned issuer's JWKS. Check issuer, audience, token kind, subject, nonce and expiry before accepting it.
  6. Store the refresh credential only in the host's secure credential store. The desktop host retains ID/access tokens in memory; it does not expose tokens, authorization URLs or callback codes to the renderer, project files or chat.

The current hosted IDE client issues refresh credentials for up to 90 days and ID/access tokens for one hour; validate the actual token expiry. Hosts without secure credential storage cannot sign in. Cancellation, logout and disposal invalidate pending work; a late token or profile response cannot restore access. Never use an embedded login web view.

Desktop storage and recovery

Account sign-in requires the host's secure credential store and its credential transaction capability. The current adapter supports local POSIX desktop hosts with private filesystem ownership. Remote extension hosts and Windows hosts do not yet offer this account capability. Existing free, local and offline project features remain available on those hosts without signing in.

The desktop account store uses version 2 immutable encrypted SecretStorage records. A small nonsecret local pointer identifies the committed credential generation; it contains no tokens or profile details. Credentials are not copied into project files or renderer storage. Upgrading from an unreleased account prototype asks for an explicit new sign-in and leaves its older credential keys unused.

Cancellation before publication retains the previously committed account. Once a new generation is published, cancellation cannot promise to undo that commit. An uncertain refresh requires a new system-browser sign-in instead of replaying a refresh credential that the identity provider may already have rotated. Missing or delayed encrypted records report storage unavailable and grant no access. Damaged state or an unconfirmed recovery lock can require owner review; do not delete the pointer or recovery records to bypass that state. No uncertain account operation is automatically replayed.

Load the account

For identity and membership, make this call after sign-in and on application launch. The excerpt shows compatible profile fields; the response also includes the server-owned catalog described below:

curl -s https://api.cleetus.dev/v1/me \
  -H "Authorization: Bearer $CLEETUS_ID_TOKEN"
{
  "user": {
    "id": "84d884b8-f071-706c-bd11-338dff1a1b44",
    "email": "rowdy@example.com",
    "name": "Rowdy Tester"
  },
  "membership": {
    "active": true,
    "plan": "member",
    "tier": "pro",
    "source": "subscription",
    "status": "active",
    "currentPeriodEnd": 1796083200,
    "cancelAtPeriodEnd": false,
    "hasBillingAccount": true,
    "mode": "live"
  },
  "entitlements": ["member", "premium-teams", "premium-tools"],
  "checkedAt": "2026-10-31T13:28:06.618Z"
}
  • Show user.name, falling back to user.email. People edit their name at cleetus.app/account; PATCH /v1/me with {"name": "…"} works too.
  • Check recognised entitlement names, such as member, from a fresh verified account response. Unknown names do not grant access. A profile field, local preference or coding-agent capability cannot grant membership features.
  • membership explains the entitlement in words, for messages such as "Your payment is past due". Don't gate on status; statuses can be added.

Send the ID token so the API records the account email. An access token also authorizes, but carries no email. GET /v1/membership remains for clients that only need the membership.

Tiers and feature grants

The deployed catalog names Scout · Free (free), Wrangler · Pro (pro) and Foreman · Team (team). Live paid production grants and purchases have not been tested. See Membership and saved settings for the included resources and ordinary account UI flow. Existing prebuilt teams, custom teams, tools and local project data remain free; the catalog does not retroactively put them behind membership.

The public GET /v1/membership/catalog describes the tier names and known features. /v1/me includes that same catalog, adds membership.tier, and returns effective entitlement IDs. The legacy membership.plan remains free or member; eligible active legacy paid members map to Wrangler. These labels and membership.active are not a substitute for a verified feature grant.

The fixed feature IDs are premium-teams and premium-tools for Wrangler or Foreman, and team-governance for Foreman. Premium access requires the fresh signed-in profile, the required tier, the server grant, server-enabled availability and no user opt-out. An unknown or disabled feature is denied. Operators/builds control availability; a user's preference cannot turn a grant on. A test-mode subscription may still have legacy active billing fields, but it receives no paid production feature grants. Explicit complimentary access uses the service-assigned tier independently of test billing.

Existing checkout without a body continues to select Wrangler. An explicit request must be exactly { "tier": "pro" } or { "tier": "team" }. Foreman requires a separately configured Team Stripe price; Cleetus never sells it using the Pro price. This documentation does not set prices, open a sales configuration or perform a purchase.

Saved preferences

Signed-in Scout accounts can save these preferences without buying membership. GET /v1/settings returns a version 1 document:

{
  "version": 1,
  "revision": 0,
  "values": {
    "startupView": "command",
    "reduceMotion": false,
    "compactLayout": false,
    "disabledFeatures": []
  }
}

startupView accepts command, teams or design. The two layout preferences are booleans. disabledFeatures accepts unique opt-outs for the three known paid feature IDs; clearing an opt-out never creates membership or access.

To save, send authenticated PUT /v1/settings with exactly { "revision": 0, "values": { ... } }, using the revision and complete values you loaded. Omit version from the request; the response includes it. The server consistently reads the authenticated user's record and conditionally writes the next revision. Concurrent or stale writes return 409. Reload the saved preferences, compare them with your draft, then save deliberately; conflicts are not silently merged or replayed. Unknown properties and malformed saved records are rejected rather than replaced with empty settings.

Provider credentials, environment values, project/machine paths, tool commands, transcripts and team data are excluded from this sync. The IDE retains its existing local settings for those. Preferences are separate from billing and cannot upgrade a tier or grant a feature. The API reference specifies the exact request and response schemas.

Fresh verification and offline display

  • Verify /v1/me after sign-in and on application launch. Refresh account explicitly requests another check. The IDE coalesces concurrent reads.
  • Paid access requires a validated, unexpired current ID token and a fresh successful server response bound to that token's account. The IDE's live profile authority expires after five minutes, or sooner when the token or paid membership period ends. Failed verification withdraws verified entitlements.
  • Cached profile and membership data are display-only. A cached member string, future billing date or complimentary status never grants offline paid access. The IDE labels these details last known, offline or unverified and shows no verified access until a fresh check succeeds.
  • Existing free and local/offline functionality stays available without a Cleetus account. The account flow does not retroactively gate those features.
  • After a 401, refresh once and retry. An invalid or expired credential needs a fresh system-browser sign-in; do not loop or silently restore old grants.
  • The backend provides POST /v1/membership/sync for billing reconciliation. After checkout, return to the IDE and choose Refresh account. This guide does not claim that the IDE automatically performs billing synchronization.

Client displays do not replace server authorization for protected resources. Keep account and entitlement decisions outside the renderer; do not infer access from a plan label or an agent's model inventory.

Sign out

IDE Sign out removes local account authority before credential cleanup and requests revocation of its own refresh token. If local deletion or server revocation cannot be confirmed, the account view reports that limitation. This does not sign out a provider CLI, clear your Cleetus browser session, erase saved work or promise rollback of dispatched actions.

Use the website's sign-out controls to end its browser session. Sign out everywhere also revokes the IDE refresh credential; already-issued tokens have their provider-defined expiry. The IDE must refresh or sign in again when its credential is refused.

Buying and managing membership

Send people to https://cleetus.app/account to subscribe, update their card, download receipts or cancel. Payments are processed by Stripe for AdaptiveBase LLC. Clients never handle card details.

Saved computer directory

GET /v1/settings/computers reads a separate, authenticated account document:

{
  "version": 1,
  "revision": 0,
  "computers": [],
  "preferredHostID": null,
  "autoReconnect": true
}

To save, PUT /v1/settings/computers with exactly revision, computers, preferredHostID and autoReconnect; omit version. Each computer has exactly hostID, name, address and fingerprint. At most 32 unique host IDs are allowed: 1–128 ASCII letters, digits, ., _, : or -. Names must be nonblank, free of control characters, and at most 80 UTF-8 bytes. Fingerprints are exactly 64 lowercase hexadecimal characters. An address is an HTTPS root URL, at most 512 UTF-8 bytes, without user information, query, fragment or a non-root path. IPv4, IPv6, .local names and FQDNs are accepted without any server DNS lookup or network request. The server returns canonical URL spelling, including a / root, lowercase host, and omission of the default 443 port. preferredHostID is null or one of the listed host IDs. The full input is limited to 32 KiB UTF-8; the response is limited to 64 KiB.

The account comes solely from the validated token subject. Saves compare the current revision atomically and return version 1 with revision increased by one. A 409 means another client changed the list: read, compare and deliberately save again. Remove a computer by sending the complete desired list without it, updating the preferred host if necessary. An interrupted save may already have committed. Read the directory after an unknown outcome; do not automatically replay the write or treat an unavailable read as an empty list. Missing records receive the defaults above; corrupt or inaccessible saved records return 503 and are retained. This document is separate from /v1/settings preferences.

These are directory hints, not connection authorization. A restored computer still requires the installation's separately stored pairing credentials, pinned TLS verification and current host authentication. Its presence does not mean it is connected or online, and autoReconnect cannot authorize a new pairing or an agent action. Pairing secrets, invitations, sessions, tokens and credentials are never stored here; unknown fields are rejected. Removing directory metadata does not revoke an existing installation's pairing. Clients must keep a signed-in account's read/draft/save context isolated across account changes.

Computer engine inventory

GET /v1/settings/computers/{hostID}/engines returns the account-reported engine inventory for an existing saved computer: exactly version:1, hostID, fingerprint, revision, inventoryHash and engines. Missing inventory has revision 0 and an empty list. This advisory data does not prove the Mac is online, a provider is signed in, a model is available now, or that an action is authorized. Unknown host returns 404; changed pins require review (409), and damaged saved data is retained (503). Existing computer-directory documents are unchanged.

The first-party IDE reports only locally observed/cached metadata, without starting agents, probing providers or signing in. It PUTs exactly revision, fingerprint and engines to that endpoint using its existing IDE ID token. Each of at most 16 engines has exactly id, name, backend, status and models. Backends are native, terminal, sdk or unknown; status is available, requires_sign_in, unavailable or unknown. Each engine has at most 16 cached models with exact id and name; empty means unknown/unadvertised. IDs are unique and bounded; engine IDs use 1–64 ASCII letters/digits/._:-, engine names are at most 80 UTF-8 bytes, and model IDs/names at most 160 bytes. The full input is at most 32 KiB; secrets, raw provider errors, private paths and unknown fields are excluded.

The server canonicalizes engine and model order by ID, hashes the UTF-8 compact JSON array (engine keys id,name,backend,status,models; model keys id,name), and returns lowercase SHA256 in inventoryHash. Unchanged inventory returns changed:false with no backend mutation or push, even at a stale revision. Changed inventory uses atomic CAS on both the directory revision and inventory revision, returning revision+1 and changed:true. Changes are capped at 120 per hour per host. An ambiguous write must be reconciled by GET/hash, never replayed automatically. A native IDE may register its own known host/pin through the existing full-directory CAS while preserving all other entries and preferences; this is metadata ownership, not a new pairing or physical host attestation.

After a changed commit, the backend may send a bounded, best-effort advisory engine_inventory APNs hint through existing confirmed active account/host bindings. Its distinct category has no action buttons or approval authority; the phone performs a fresh authenticated GET. No engine names, models, provider credentials or account identifiers enter the notification. A durable dispatch reservation prevents duplicate sends after unknown outcomes. Provider acceptance does not guarantee delivery or immediate background execution; foreground reads remain the fallback. Inventory hints have separate minute limits of two per binding and six per account so they do not consume approval/issue alert minute capacity; the existing daily storage budgets remain shared. The native reporter does not send a second notification.

CLI device-code sign-in and revocation

The CLI's default cleetus signin flow displays a short code and the fixed https://cleetus.app/device verification page. Open it in your normal browser, sign in, compare the device details, and explicitly approve the request. The CLI keeps its own PKCE verifier and redeems the protected authorization code directly with Cognito. It does not ask you to paste a password or provider credential into chat, and the backend does not store your CLI refresh token.

The code expires after a short window. Cancelled or expired requests need a new explicit sign-in. If the final outcome is unknown, let the CLI reconcile its saved enrollment rather than repeatedly approving or replaying it.

The account site's Devices section lists managed CLI account grants. Review the exact device before choosing Revoke Cleetus account access. Revocation blocks that grant's subsequent protected Cleetus API requests; it does not stop already running local agents, revoke phone pairing or sign you out of coding agents. An unavailable revocation response is not proof that it succeeded; refresh the device list before deciding what to do next.

cleetus signin-loopback remains a separate legacy PKCE connection and is not a managed device entry. On SSH it needs the shown loopback callback port forwarded. See the CLI guide and the optional encrypted Linux host setup. The ordinary IDE and iPhone flows keep their own sign-in clients and secure credential stores.