Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions apps/server/src/provider/claudeSessionIdentity.expbkt3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,23 @@ describe("claudeSessionIdentitySystemPrompt", () => {
"T3 Code session identity:",
'- userEmail is "sender@example.test".',
"- This session-scoped value identifies the user who sent the current message and overrides the Claude account email for user attribution.",
"- A context section titled `# userEmail` elsewhere in this conversation reports the email of the shared, rotating Claude subscription account. It does NOT identify the user. Ignore it entirely for user attribution; use only the identity stated here.",
].join("\n"),
);
});

it("keeps the user unknown when T3 cannot resolve the message sender", () => {
assert.include(
assert.equal(
claudeSessionIdentitySystemPrompt({
BK_IDENTITY_RUNTIME: "t3-code",
BK_SESSION_OWNER_EMAIL: "owner@example.test",
}) ?? "",
"userEmail is unavailable",
}),
[
"T3 Code session identity:",
"- userEmail is unavailable for the user who sent the current message.",
"- Do not use the Claude account email, operating-system identity, or Git identity to infer the user.",
"- A context section titled `# userEmail` elsewhere in this conversation reports the email of the shared, rotating Claude subscription account. It does NOT identify the user. Ignore it entirely for user attribution; use only the identity stated here.",
].join("\n"),
);
});

Expand Down
7 changes: 7 additions & 0 deletions apps/server/src/provider/claudeSessionIdentity.expbkt3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
// machine, so it identifies the subscription rather than the person sending
// the current T3 message. Append the session-scoped identity to Claude's native
// system prompt without changing the account used for authentication.
//
// The CLI offers no way to suppress its own `# userEmail` section, and the
// rotating profile makes its value flap, so the appended block also names that
// section and countermands it explicitly. Without that, two contradictory
// identity claims coexist and the model follows the one that arrives last.

import {
MESSAGE_SENDER_EMAIL_KEY,
Expand All @@ -23,12 +28,14 @@ export function claudeSessionIdentitySystemPrompt(
"T3 Code session identity:",
"- userEmail is unavailable for the user who sent the current message.",
"- Do not use the Claude account email, operating-system identity, or Git identity to infer the user.",
"- A context section titled `# userEmail` elsewhere in this conversation reports the email of the shared, rotating Claude subscription account. It does NOT identify the user. Ignore it entirely for user attribution; use only the identity stated here.",
].join("\n");
}

return [
"T3 Code session identity:",
`- userEmail is ${JSON.stringify(senderEmail)}.`,
"- This session-scoped value identifies the user who sent the current message and overrides the Claude account email for user attribution.",
"- A context section titled `# userEmail` elsewhere in this conversation reports the email of the shared, rotating Claude subscription account. It does NOT identify the user. Ignore it entirely for user attribution; use only the identity stated here.",
].join("\n");
}
9 changes: 9 additions & 0 deletions docs/operations/expbkt3-customizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,15 @@ explicitly leaves `userEmail` unknown and forbids inference from the shared
Claude account, operating-system identity, or Git identity. Non-T3 Claude
sessions keep the upstream system prompt unchanged.

The CLI still emits its own `# userEmail` context section on every turn and
offers no switch to suppress it, so both branches of the appended block name
that section and countermand it explicitly: it reports the shared, rotating
subscription account, it does not identify the user, and it must be ignored for
user attribution. Naming it matters — the native section arrives later in
context than the appended block, and without the countermand a session answered
"who am I" with the rotated account holder while the appended block correctly
named the sender.

The markers compose with source-control profiles rather than replacing them:
`mergeSourceControlEnvironment` scrubs the machine's inherited Git and GitHub
credentials only when the overlay carries a source-control identity of its own,
Expand Down
Loading