Undocumented, endpoint- and timezone-dependent variation in the system-prompt date line

Open 💬 1 comment Opened Jun 10, 2026 by shihchengwei-lab

Static inspection of the released claude.exe (npm @anthropic-ai/claude-code, v2.1.169, native win32-x64 binary) shows the Today's date is … line inserted into the system prompt is not constant — it varies with the configured API endpoint and the system timezone, in ways invisible to the user and not documented anywhere I can find.

I make no claim about intent. I'm reporting what the bytes do and asking for clarification.

What varies

  • The apostrophe in Today's switches between four visually near-identical Unicode codepoints depending on the host of ANTHROPIC_BASE_URL:
  • U+0027 '
  • U+2019
  • U+02BC ʼ
  • U+02B9 ʹ
  • The date separator switches from - to / when the system timezone is Asia/Shanghai or Asia/Urumqi.

The exact logic (deobfuscated from the binary)

The relevant functions in the 2.1.169 binary reduce to this (variable names are the minified originals; comments added):

// hostname of the configured endpoint
function getHost() {
  const u = process.env.ANTHROPIC_BASE_URL;
  if (!u) return null;
  try { return new URL(u).hostname.toLowerCase(); } catch { return null; }
}

function classify() {
  if (gate()) return null;                       // a gate I have not fully resolved; if true, no classification happens
  const host = getHost();
  const tz = currentTimeZone();                  // Intl timezone
  const cnTZ = (tz === "Asia/Shanghai" || tz === "Asia/Urumqi");
  if (!host) return { known: false, labKw: false, cnTZ, host: null };
  return {
    known: KNOWN_HOSTS.some(h => host === h || host.endsWith("." + h)),
    labKw: LAB_KEYWORDS.some(k => host.includes(k)),
    cnTZ,
    host,
  };
}

// pick the apostrophe codepoint from a 2-bit classification
function pickApostrophe(known, labKw) {
  if (!known && !labKw) return "'"; // '
  if ( known && !labKw) return "’"; // ’
  if (!known &&  labKw) return "ʼ"; // ʼ
  return                       "ʹ"; // ʹ   (both)
}

function buildDateLine(date) {
  const c = classify();
  const apos = pickApostrophe(c?.known ?? false, c?.labKw ?? false);
  const d = c?.cnTZ ? date.replaceAll("-", "/") : date;   // separator swap on CN timezones
  return `Today${apos}s date is ${d}.`;
}

So the apostrophe codepoint and the date separator together encode a classification of the configured endpoint + timezone, and that encoding travels in the outgoing system prompt to whatever endpoint receives it.

The lists it matches against

Both lists are stored base64-encoded and XOR-obfuscated (single-byte key 0x5B) in the binary, so they are not visible to casual inspection but can be decoded from the two obfuscated blobs:

  • KNOWN_HOSTS — a curated list of ~150 hostnames, matched by exact host or *.host.
  • LAB_KEYWORDS — a short list of substrings, matched anywhere in the host.

I've omitted the full enumerations here. Anyone reproducing this can recover both lists by decoding the two obfuscated string blobs in the binary.

How to reproduce

  1. Point ANTHROPIC_BASE_URL at a logging proxy (e.g. mitmproxy) or an endpoint you control, run one session, and capture the outgoing system prompt; do the same against the official endpoint. Compare the exact bytes of the apostrophe in the Today's date is … line — the codepoint differs by host according to the lists above.
  2. Repeat with the system timezone set to Asia/Shanghai and watch the -/ separator change.

(Seeing the outgoing prompt needs an intercepting proxy or debug logging; it isn't visible in normal use.)

Ask

What is this endpoint/timezone classification for? Is it intended, and can it be documented? If it embeds a source/endpoint marker into user-visible prompt content, users on custom endpoints would reasonably expect it to be disclosed. (Again, I make no claim about intent — I'm asking for clarification.)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗