OKF здесь используется как практический формат базы знаний: Objective → Key Facts → Key Flows → Failure modes → Follow-ups.
Цель документа — быстро передать контекст проекта человеку или агенту, который будет чинитьagentctx.
Сделать agentctx kubectx-like CLI для безопасного переключения локальных Codex auth-профилей.
- Активный auth Codex находится в
~/.codex/auth.json. agentctxхранит копии auth-файлов в~/.agentctx/profiles/<profile>/auth.json.- Секреты и токены нельзя печатать в stdout/stderr/logs.
- Перед переключением активный auth должен бэкапиться.
- Если текущий Codex auth обновился, он должен автоматически синхронизироваться в текущий профиль перед switch.
- UX должен быть похож на
kubectx: минимум подкоманд, управление через позиционные аргументы и флаги.
agentctxбез аргументов показывает список профилей или открывает interactive selector черезfzf.agentctx <NAME>переключает профиль.agentctx -переключает на предыдущий профиль.agentctx -c/--currentпоказывает текущий профиль.agentctx -d <NAME>удаляет профиль.agentctx -u/--unsetочищает current marker.agentctx =.сохраняет или переименовывает текущий auth в профиль с именем email из JWT.
List or interactive mode.
- Если
stdinиstdout— TTY,fzfдоступен, иAGENTCTX_IGNORE_FZFне задан, должен открыться interactive selector. - Если interactive невозможен, выводится plain list.
work@example.com
personal@example.com
Switch to profile <NAME>.
- Проверить имя профиля.
- Взять lock.
- Проверить profile auth JSON.
- Auto-sync текущего marker profile, если active auth изменился.
- Создать backup текущего active auth.
- Атомарно заменить
~/.codex/auth.json. - Обновить
currentиpreviousmarkers.
Save or rename current active auth using email from JWT.
- Имя профиля должно быть email пользователя из JWT claim
email. - Пользователь не обязан передавать имя вручную.
- Если текущий auth ещё не связан с профилем — создать профиль
<jwt-email>. - Если текущий auth уже связан с профилем с другим именем — переименовать профиль в
<jwt-email>. - Если текущий профиль уже называется
<jwt-email>— обновить сохранённый auth из active auth.
agentctx =.Saved current Codex auth as profile "user@example.com".
Same as agentctx =., but validates explicit email.
<EMAIL>должен совпадать сemailиз JWT.- Если не совпадает — ошибка, профиль не создаётся и не переименовывается.
agentctx user@example.com=.Saved current Codex auth as profile "user@example.com".
Mismatch:
agentctx other@example.com=.error: profile name must match JWT email: user@example.com
Rename existing profile.
- Это обычный rename и не обязан использовать JWT email.
- Если
<NEW_NAME>уже существует — операция должна завершиться ошибкой без перезаписи.
Надёжно получать email пользователя из JWT внутри auth.json.
- JWT может лежать не только в верхнем ключе.
- Нужно искать рекурсивно по JSON.
- Приоритетные ключи:
id_tokenjwttokenaccess_token
- JWT payload декодируется как base64url без проверки подписи.
- Для имени профиля используется claim
email. - Email нормализуется в lowercase.
- Invalid JSON → ошибка
invalid JSON. - Symlink active auth → ошибка, операция запрещена.
- JWT не найден → ошибка
JWT email not found. - JWT найден, но claim
emailотсутствует → ошибкаJWT email not found. - Email невалиден как имя профиля → ошибка invalid profile name.
Разрешённые символы для профиля:
A-Z a-z 0-9 . _ % + @ -
Запрещено:
- пустое имя;
.;..;- имя, начинающееся с
-; - legacy CRUD words:
saveusesyncbackupdoctorrenamedeletelistcurrent
Для email-профиля дополнительно требуется форма:
local@domain.tld
~/.codex/auth.json
~/.agentctx/
profiles/
<profile>/
auth.json
metadata.json
backups/
auth-<timestamp>.json
current
previous
lock
metadata.json не должен содержать токены.
Допустимые поля:
{
"name": "user@example.com",
"created_at": "2026-06-25T14:30:00Z",
"updated_at": "2026-06-25T14:30:00Z",
"source": "~/.codex/auth.json",
"auth_sha256": "..."
}- Не печатать token/JWT/auth content.
- Reject symlink для active auth и profile auth.
- Reject non-regular files.
- Валидировать JSON перед копированием.
- Atomic writes через temp file +
os.replace. - Permissions:
- dirs:
0700 - auth/profile/backup files:
0600
- dirs:
- Lock на операции save/switch/rename/delete/unset.
- Backup перед switch.
Сделать UX как у kubectx.
agentctxбез аргументов в interactive terminal должен открыватьfzf.- Выбранный профиль сразу становится активным.
- Если пользователь отменил выбор — вернуть ошибку.
- Если
fzfнедоступен или shell не interactive — показать список.
AGENTCTX_IGNORE_FZF=1Отключает interactive selector.
pip3 install agentctx не обновляет уже установленную версию, если пакет уже установлен.
Обновить из PyPI:
pip3 install --upgrade agentctxУстановить локальный build:
pip3 install --force-reinstall dist/agentctx-<version>-py3-none-any.whlОпубликовать текущую версию:
poetry publishНе использовать make publish, если версия уже поднята вручную: target дополнительно делает poetry version minor.
agentctx/cli.py— routing команд.agentctx/profiles.py— profile model operations.agentctx/auth.py— safe auth operations, JSON/JWT helpers, atomic writes.agentctx/paths.py— filesystem paths and test env overrides.agentctx/errors.py— domain exceptions.
tests/test_cli.py— CLI behavior.tests/test_auth_safety.py— security behavior.tests/test_paths.py— path overrides.
poetry check
poetry run pytest
poetry buildManual QA:
agentctx =.
agentctx -c
agentctx
agentctx other@example.com=.
agentctx user@example.com
agentctx -
agentctx -d user@example.com
agentctx -u
agentctx -V- Нужно ли полностью запретить ручные non-email profile names для rename
NEW=OLD? - Нужно ли искать email не только в JWT claim
email, но и в других полях auth JSON? - Нужно ли показывать текущий профиль с маркером
*в plain list, как в старом плане? - Нужно ли заменить
fzfна встроенный interactive selector, еслиfzfне установлен? - Нужно ли мигрировать старые профили
work,personalв email-профили автоматически?