- BrainTools - https://www.braintools.ru -
## Как Claude запоминает ваш компьютер: разбираем локальные идентификаторы и сбрасываем их скриптом
Я давно пользуюсь Claude Desktop и Claude Code на Windows. В какой-то момент стало интересно: когда я выхожу из аккаунта и захожу заново, насколько «с чистого листа» меня видит сервер? Оказалось, что аккаунт — это только половина истории. Claude помечает ещё и саму машину, причём отдельно от логина, и эти метки живут на диске между сессиями.
В статье разберу, где именно лежат идентификаторы устройства, как клиент их генерирует (с кусками кода из app.asar и бинаря CLI), что из этого переживает наивное «удалить папку», и покажу PowerShell-скрипт, который приводит локальный слой в состояние первого запуска. Чаты при этом остаются на месте.
Весь код открыт (скрипт для сброса эти идентификаторов): https://github.com/Soulringen/aegis-claude [1]
> Дисклеймер. Это исследование того, что клиент пишет на диск вашего же компьютера, и утилита для управления своими локальными данными. Никакого вмешательства в чужие системы или серверную часть здесь нет.
—
## С чего всё началось
Первое, что бросается в глаза — файл ~/.claude.json (на Windows это %USERPROFILE%.claude.json). Внутри, помимо кэшей фич и списка проектов, лежат два долгоживущих идентификатора:
“`json
{
“userID”: “29751f55233dc772e0f88584ffbd5317d59c84d782caf321b2ad408cc237bfb1”,
“machineID”: “c6604aae3f882f340123383c64ddf99644b7d2f060177351910f4de23ecedddb”,
“firstStartTime”: “2026-06-10T21:27:47.643Z”,
“oauthAccount”: {
“accountUuid”: “…”,
“emailAddress”: “…”,
“organizationUuid”: “…”
}
}
“`
machineID и userID — это 32 случайных байта в hex (отсюда длина 64 символа). Важный момент: они не привязаны к аккаунту. То есть под какой учёткой бы вы ни зашли на этой машине, пара ID остаётся прежней. Это ровно то, что позволяет связать разные аккаунты, работавшие на одном ПК.
Чтобы убедиться, что это не просто кэш, я вытащил логику [2] генерации прямо из бинаря CLI (claude.exe, это упакованный Bun-проект). После деминификации она выглядит так:
“`js
function getUserID(e) {
let n = oe(), r = ce();
if (typeof r.userID === “string” && qc.test(r.userID)) return r.userID;
if (n.generatedUserID) return n.generatedUserID;
let s = Dc(32).toString(“hex”); // 32 случайных байта -> hex
return n.setGeneratedUserID(s), Ce((g) => ({ …g, userID: s }), e), s;
}
function getMachineID(e) {
let n = oe(), r = ce();
if (typeof r.machineID === “string” && qc.test(r.machineID)) return r.machineID;
if (n.generatedMachineID) return n.generatedMachineID;
let s = Dc(32).toString(“hex”);
return n.setGeneratedMachineID(s), Ce((g) => ({ …g, machineID: s }), e), s;
}
“`
Логика простая: есть валидное значение в конфиге — используем его; нет — генерируем новое и сохраняем. Значит, достаточно убрать значение из конфига, и при следующем запуске появится новый ID. Там же рядом нашёлся summonSidKey и, что интереснее, chromeExtension.pairedDeviceId — привязка к расширению Claude для Chrome.
Отдельная подстава: CLI периодически сохраняет резервные копии конфига в ~/.claudebackups.claude.json.backup.*. Если удалить только основной файл, клиент может поднять старый machineID из бэкапа. Это нужно учитывать при чистке.
—
## Десктоп: ant-did и реестр устройств
У десктопного приложения своя система меток в %APPDATA%Claude. Центральный файл — ant-did:
“`js
var $Ht = “ant-did”;
function readAntDid(e) {
let t = Buffer.from(e, “base64”).toString(“utf-8”).trim();
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t) ? t : void 0;
}
function ensureAntDid() {
let e = path.resolve(app.getPath(“userData”), $Ht);
let t = readFile(e);
if (t !== void 0) return t;
let n = fs.lstatSync(e);
if (!n.isFile() || n.nlink > 1) throw Error(“ant-did is not a plain file”);
// …
let id = randomUUID();
writeFileSync(e, Buffer.from(id, “utf-8”).toString(“base64”), { mode: 384, flag: “wx” });
return id;
}
“`
Это случайный UUID, записанный в base64. Он один на OS-аккаунт и подставляется во все события телеметрии. Что характерно, это ровно тот же did, который лежит в %APPDATA%Claudesentrysession.json — то есть крэш-репорты Sentry используют тот же идентификатор устройства.
Рядом — ant-device-registry.json. Он привязывает машину к каждому аккаунту:
“`json
{
“17132d96-…”: “pk1:<ключ_устройства>:cf3c2a51-…”,
“acaed4ef-…”: “pk1:<ключ_устройства>:8379cfe6-…”
}
“`
Ключами идут UUID аккаунтов, значениями — записи pk1:… с ключом устройства. У меня в этом файле оказалось две учётки с общим ключом устройства. Это уже серверная связка: даже если вычистить всё локально, сервер помнит, что эти аккаунты регистрировали одно и то же устройство.
Дальше по мелочи, но каждое — стабильный идентификатор или соль:
– remote-control-state.json → telemetrySalt (соль телеметрии, мятится через mintSalt());
– ccd-ids.json → salt (ещё одна соль);
– config.json → first_launch_at, lastKnownAccountUuid, кэш токенов oauth:tokenCache;
– claude_desktop_config.json → remoteToolsDeviceName (имя устройства, по сути hostname) и карты настроек по аккаунтам.
—
## Chromium-слой, о котором все забывают [3]
Десктоп Claude — это Electron, поэтому внутри живёт полноценный Chromium-профиль. И вот о нём в большинстве «гайдов по сбросу» вообще не вспоминают. В %APPDATA%Claude лежат:
– NetworkCookies — cookies claude.ai [4], включая ajs_anonymous_id, anthropic-device-id, activitySessionId;
– Local Storageleveldb, IndexedDB, Session Storage — веб-хранилище;
– Preferences — там, например, spellcheck.dictionaries: ["ru"] и media.device_id_salt;
– Local State — os_crypt.encrypted_key и uninstall_metrics.installation_date2.
Связь аналитики с устройством видна прямо в коде десктопа:
“`js
e.SEGMENT_ANONYMOUS_ID = “ajs_anonymous_id”;
e.DEVICE_ID_KEY = “anthropic-device-id”;
// …
event_data: {
device_id: await get(“anthropic-device-id”),
anonymous_id: await get(“ajs_anonymous_id”),
// …
}
“`
То есть ajs_anonymous_id + anthropic-device-id уходят в события GrowthBook/аналитики. Причём один и тот же ajs_anonymous_id я нашёл и в Local Storage обычного Chrome (там, где открывал claude.ai [4] в браузере) — а это уже совсем другой профиль, который десктопный сброс не трогает.
Ещё одно неочевидное место — %TEMP%claudecache-break-state-*.json: по файлу на сессию, в имени — UUID. И каталог %LOCALAPPDATA%ClaudeDesktopRollbackBackups, где после обновлений остаётся старая копия ant-did и всего RoamingClaude. Снесёте текущий — всё поднимется из отката.
—
## Что переживает наивное «удалить папку»
Это ключевой вывод исследования. Даже если идеально вычистить все файлы выше, устройство всё равно опознаётся по тому, что к файлам не относится:
| Канал | Что утекает | Лечится удалением файлов? |
| — | — | — |
| Локаль ОС | ru-RU, раскладка 1049 | нет |
| Часовой пояс | Russian Standard Time (UTC+3) | нет |
| Spellcheck | dictionaries: ["ru"] | частично |
| IP / TLS / HTTP2 | гео, ASN, JA3 | нет |
| OAuth-связка | accountUuid уже склеен с pk1 на сервере | нет |
| Браузер | cookies claude.ai [4] в обычном Chrome/Edge | нет (другой профиль) |
Вывод простой: локальный сброс идентификаторов — это один слой из нескольких. Он нужен, чтобы новый вход не садился на старый machineID/ant-did, но сам по себе он не делает вас «новым пользователем» в глазах сервера. Поэтому в утилите я сознательно не обещаю «обход бана» — она делает ровно одно: приводит локальные метки устройства в состояние первого запуска.
—
## Скрипт
Собрал всё в один PowerShell-скрипт (PowerShell 5.1 уже есть в любой Windows 10/11, зависимостей нет, права администратора не нужны — всё в профиле пользователя).
Ключевые решения:
По умолчанию — предпросмотр. Скрипт сначала показывает, что нашёл, и не удаляет ничего, пока вы явно не выберете 1.
“`text
Mode: PREVIEW (deletion starts only after you choose 1)
Current markers:
CLI machineID : c6604aae…dddb
CLI userID : 29751f55…bfb1
ant-did : MGU5Y2E2…M2M2
device registry entries: 2
telemetrySalt : 2023f2d5…5a4f
“`
Чаты не трогаются. Диалоги Claude Code (~/.claudeprojects), сессии и settings.json выводятся отдельным блоком «Kept» и остаются на диске.
Сначала гасим процессы. Пока жив Claude.exe, leveldb и cookies залочены. Скрипт останавливает процессы Claude и cowork-службу, ждёт, и только потом удаляет, с повторной попыткой для занятых файлов.
Защита от junction/symlink. Перед rmdir /s дерево проверяется на reparse-point, чтобы удаление не ушло по ссылке наружу:
“`powershell
function Test-TreeHasReparsePoint {
param([string]$Path)
$queue = New-Object System.Collections.Generic.Queue[string]
Автор: SlippinJimmy
Источник [5]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/36436
URLs in this post:
[1] https://github.com/Soulringen/aegis-claude: https://github.com/Soulringen/aegis-claude**
[2] логику: http://www.braintools.ru/article/7640
[3] забывают: http://www.braintools.ru/article/333
[4] claude.ai: http://claude.ai
[5] Источник: https://habr.com/ru/articles/1089810/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1089810
Нажмите здесь для печати.