From 15ad1a0b51ee91ff51089a9edc90a00ea7fcf29f Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Mon, 17 Aug 2026 04:12:19 -0400 Subject: [PATCH 1/2] fix(telemetry): treat API-key Codex auth as a supported install Signed-off-by: Yordis Prieto --- apps/server/src/telemetry/Identify.test.ts | 43 ++++++++++++++++++++++ apps/server/src/telemetry/Identify.ts | 20 ++++++++-- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/apps/server/src/telemetry/Identify.test.ts b/apps/server/src/telemetry/Identify.test.ts index ab151821789..91216c12f91 100644 --- a/apps/server/src/telemetry/Identify.test.ts +++ b/apps/server/src/telemetry/Identify.test.ts @@ -77,6 +77,49 @@ it.layer(NodeServices.layer)("telemetry identity", (it) => { ), ); + it.effect("falls back quietly when Codex authenticates with an API key", () => { + const logs: CapturedLog[] = []; + const logger = makeCaptureLogger(logs); + + return Effect.gen(function* () { + const config = yield* ServerConfig.ServerConfig; + const fileSystem = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const homeDirectory = path.join(config.baseDir, "home"); + const codexAuthPath = path.join(homeDirectory, ".codex", "auth.json"); + const anonymousId = "api-key-fallback-anonymous-id"; + const privateApiKey = "sk-private-openai-api-key"; + + yield* fileSystem.makeDirectory(path.dirname(codexAuthPath), { recursive: true }); + yield* fileSystem.writeFileString( + codexAuthPath, + `{"auth_mode":"apikey","OPENAI_API_KEY":"${privateApiKey}"}`, + ); + yield* fileSystem.writeFileString(config.anonymousIdPath, anonymousId); + + const identifier = yield* Identify.getTelemetryIdentifierForHome(homeDirectory); + + assert.equal(identifier, sha256(anonymousId)); + assert.isUndefined(findIdentityLog(logs, "codex", "TelemetryIdentityDecodeError")); + assert.isUndefined(findIdentityLog(logs, "codex", "TelemetryIdentityReadError")); + const allLogs = logs + .map((log) => + [String(log.message), ...Object.values(log.annotations).map(String)].join("\n"), + ) + .join("\n"); + assert.notInclude(allLogs, privateApiKey); + }).pipe( + Effect.provide( + Layer.merge( + ServerConfig.layerTest(process.cwd(), { + prefix: "t3-telemetry-identify-apikey-", + }), + Logger.layer([logger], { mergeWithExisting: false }), + ), + ), + ); + }); + it.effect("logs structured decode context and falls back from malformed Codex auth", () => { const logs: CapturedLog[] = []; const logger = makeCaptureLogger(logs); diff --git a/apps/server/src/telemetry/Identify.ts b/apps/server/src/telemetry/Identify.ts index b6c3d0066df..7c252c442c2 100644 --- a/apps/server/src/telemetry/Identify.ts +++ b/apps/server/src/telemetry/Identify.ts @@ -10,10 +10,17 @@ import * as Schema from "effect/Schema"; import * as ServerConfig from "../config.ts"; +/** + * Codex omits `tokens` entirely when the install authenticates with an API key + * rather than a ChatGPT account, so an absent `tokens` is a supported install + * and not a malformed file. + */ const CodexAuthJsonSchema = Schema.Struct({ - tokens: Schema.Struct({ - account_id: Schema.String, - }), + tokens: Schema.optional( + Schema.Struct({ + account_id: Schema.String, + }), + ), }); const ClaudeJsonSchema = Schema.Struct({ @@ -183,7 +190,9 @@ const getCodexAccountId = Effect.fn("TelemetryIdentity.getCodexAccountId")(funct ), ); - return Option.some(authJson.tokens.account_id); + return authJson.tokens === undefined + ? Option.none() + : Option.some(authJson.tokens.account_id); }); const getClaudeUserId = Effect.fn("TelemetryIdentity.getClaudeUserId")(function* ( @@ -250,6 +259,9 @@ const upsertAnonymousId = Effect.gen(function* () { * 1. ~/.codex/auth.json tokens.account_id * 2. ~/.claude.json userID * 3. ~/.t3/telemetry/anonymous-id + * + * A missing file or an API-key-only Codex auth.json falls through quietly. Only + * unreadable or malformed files warn. */ export const getTelemetryIdentifierForHome = Effect.fn("getTelemetryIdentifierForHome")( function* (homeDirectory: string) { From 16003cec072382a0da9bd0fbcca3a1e87a905874 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Mon, 17 Aug 2026 04:29:53 -0400 Subject: [PATCH 2/2] docs(fork): record API-key Codex auth support as a divergence Signed-off-by: Yordis Prieto --- .../0007-codex-api-key-auth-is-supported.md | 27 +++++++++++++++++++ docs/fork/README.md | 7 ++--- 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 docs/fork/0007-codex-api-key-auth-is-supported.md diff --git a/docs/fork/0007-codex-api-key-auth-is-supported.md b/docs/fork/0007-codex-api-key-auth-is-supported.md new file mode 100644 index 00000000000..0040bf47785 --- /dev/null +++ b/docs/fork/0007-codex-api-key-auth-is-supported.md @@ -0,0 +1,27 @@ +# 0007: API-key Codex installs are not reported as broken + +- PR: [TrogonStack/t3code#15](https://github.com/TrogonStack/t3code/pull/15) +- Status: active + +## What you can do now + +- Run Codex authenticated with an API key instead of a ChatGPT account + without a warning and a stack trace on every server start. Telemetry falls + back to the anonymous identifier quietly, the same way it already did when + there is no Codex auth file at all. +- An auth file that really is unreadable or corrupt still warns, so the + warning keeps meaning something. + +## Why + +API keys are a supported way to authenticate Codex, so an install using one +is healthy and should not read as a malfunction in the logs. A warning that +fires on every start of a working setup is worse than no warning, because it +teaches you to scroll past the one that matters. + +## Upstream considerations + +Nothing here is fork-specific, so this belongs upstream as an ordinary bug +fix. Submit it, then delete this entry once it merges. The surface is small +enough that carrying it in the meantime costs nothing at sync time, though it +does sit in a shared file, so a sync must not drop it. diff --git a/docs/fork/README.md b/docs/fork/README.md index d86972f85fd..c8249d1b7c1 100644 --- a/docs/fork/README.md +++ b/docs/fork/README.md @@ -27,6 +27,7 @@ Each entry uses these sections: ## Ledger -| # | Divergence | PR | Status | -| ---- | ------------------------------------------------------------------------------------- | -------------------------------------------------- | ------ | -| 0003 | [Native subagent threads for Claude orchestrators](./0003-native-subagent-threads.md) | [#3](https://github.com/TrogonStack/t3code/pull/3) | active | +| # | Divergence | PR | Status | +| ---- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------ | +| 0003 | [Native subagent threads for Claude orchestrators](./0003-native-subagent-threads.md) | [#3](https://github.com/TrogonStack/t3code/pull/3) | active | +| 0007 | [API-key Codex installs are not reported as broken](./0007-codex-api-key-auth-is-supported.md) | [#15](https://github.com/TrogonStack/t3code/pull/15) | active |