clikit
Стандартная библиотека построения CLI поверх s-librarykit.
Новый CLI собирается за ~10 строк: единый root-app с --json/--text/--profile/--version,
4-слойный конфиг с валидацией, JSON-first вывод для агентов и скриптов,
структурированные команды. Сетевой слой — транспорт, retry, секреты, пути — это
зона КОРНЯ librarykit; clikit на нём построен и тянет его как зависимость, но
больше НЕ фасадит (строгие зоны). Единая иерархия ошибок (errors) — общий
контракт между слоями.
librarykit ← КОРЕНЬ: errors · retry · transport · sessions · paths · config_util
▲
clikit ← ЭТОТ КИТ: command_kit · config · output · scaffold + errors.
transport/retry/session/paths — бери из librarykit напрямую.
Установка
uv add s-clikit
Имя дистрибутива — s-clikit, имя для импорта — clikit. librarykit подтянется
автоматически как зависимость.
Быстрый старт
CLI за 10 строк — build_root_app даёт root с флагами --json/--text/--profile/--version:
from clikit import build_root_app, command, AppConfig, emit_data
from librarykit.transport import RestHttpClient # транспорт — зона librarykit
app = build_root_app(brand="acme", help="ACME CLI")
@app.command()
@command
def items():
cfg = AppConfig.load("acme")
client = RestHttpClient(cfg.base_url, access_token=...)
emit_data(..., text_renderer=...)
Запуск: acme items отдаёт машинный JSON; acme items --text — человеко-читаемый
вывод. Скаффолд нового проекта: clikit new <name> (см. clikit.scaffold).
Навык — зона не этого кита
Скаффолд clikit new генерит ТОЛЬКО CLI-пакет. SKILL.md, _skill_meta.toml,
install/ и остальную форму навыка Skillery держит skillkit.canon — кит,
который этот формат читает и ставит, он же его и пишет. Раньше копия канона
жила и здесь, и расходилась: плоская раскладка вместо src/<pkg>/ +
skills/<slug>/, kind = "cli" (такого рода не существует), ни install/, ни
tests/ — навык не проходил validate_canonical_skill.
Собрать навык: skillery new <slug> --kind tooling либо
skillkit.canon.render_* напрямую. Подробности и путь миграции —
docs/SKILL_PROJECT.md, обоснование — ADR-0001 кита
skillkit.
JSON по умолчанию
Дефолтный режим вывода — json (для AI-агентов и скриптинга): без флагов команда печатает машинный JSON Lines в stdout. Человек переключается в текст:
- флагом
--text/--plain; - env
{BRAND}_OUTPUT=text; - в
config.toml→output_format = "text".
--json форсит json (перебивает --text, если переданы оба).
Слои конфига: global + project + local
AppConfig.load(brand) собирает значения по слоям (низ→верх приоритета), per-key
мерж (верхний слой переопределяет только заданные ключи, не заменяет объект целиком):
defaults(модель) < global(config_dir/config.toml)
< project(.<brand>.toml | .<brand>/config.toml — найден ВВЕРХ от cwd до .git)
< local(*.local.toml рядом с project, gitignored)
< ENV({BRAND}_<FIELD>) < init-kwargs
- project-discovery: подъём от cwd до маркера
.git; ищется.<brand>.tomlв корне ИЛИ.<brand>/config.toml— «конфиг рядом с проектом». - local-оверрайд:
.<brand>.local.toml— приватные правки поверх командного конфига (в.gitignore). - Профили (
--profile/{BRAND}_PROFILE→profiles/<p>/) — на уровне global. Активный профиль разрешаетclikit.config.active_profile(brand): сперва контекст исполнения (ExecutionContext), затем env. Корневой callback env не пишет — профиль едет объектом (см. «Контекст исполнения»).
AppConfig построен на corekit.config.ConfigModel (типизация + fail-fast валидация, кит-волна 5 — без pydantic). Пути
по ОС (librarykit.config_util.AppPaths) — на platformdirs (%APPDATA% /
~/Library / ~/.config), ENV-override {BRAND}_HOME.
env-интерполяция секретов
Строковые значения резолвятся из окружения при load (секрет не лежит в git):
api_token = "${ACME_TOKEN}" # из env ACME_TOKEN
base_url = "${ACME_HOST:-http://localhost:8000}" # с дефолтом
Поддержаны ${VAR} и ${VAR:-default}. Подстановка команд $(...) не
поддержана (поверхность атаки). Заряжать env можно load_dotenv_file или keyring
(librarykit.secret_store.SecretStore).
MCP-секция
AppConfig.mcp: dict[str, McpServer] — единая форма манифеста MCP-сервера
(transport/command/args/env/url/headers/enabled):
[mcp.skills-hub]
transport = "stdio"
command = "skills-hub-mcp"
args = ["--stdio"]
env = { TOKEN = "${SH_TOKEN}" }
$schema для редактора
AppConfig.json_schema() отдаёт JSON Schema модели. Команда для CLI —
make_schema_command(MyConfig):
from clikit import make_schema_command, AppConfig
app.command(name="schema")(make_schema_command(MyConfig)) # `acme schema` печатает схему
Контекст исполнения (ExecutionContext)
Контекст запуска — ЯВНЫЙ объект в ContextVar, а не процессное окружение. Корневой
callback собирает его один раз (единственное место чтения env) и ставит на всё
исполнение команды:
from clikit import build_root_app, current_context
app = build_root_app("acme", redact_output=True) # + флаг --unsafe-show-secrets
@app.command()
def whoami():
ctx = current_context() # profile / tenant / home_dir / proxy /
... # output_mode / reveal_secrets / trace_id
Зачем: os.environ — процессный носитель, поэтому два тенанта в одном процессе
делили профиль, {BRAND}_HOME и прокси, а запись env из-под await уводила
сессию чужого аккаунта. ContextVar скоупится по asyncio-task и треду.
- Env читается ТОЛЬКО в
build_context(brand, ...)({BRAND}_PROFILE,{BRAND}_TENANT,{BRAND}_HOME,{BRAND}_PROXY/ALL_PROXY,{BRAND}_UNSAFE_SHOW_SECRETS,{BRAND}_TRACE_ID); явный аргумент старше env. - Свой контекст (сервер, тесты, пул воркеров) —
use_context(ctx)/set_context/reset_context. - Маскировка секретов — свойство контекста:
redact_output=Trueвключает редакцию для ВСЕХ команд (emit_data/emit_tableзовутredactсами), а--unsafe-show-secretsеё снимает. Monkey-patchemit_dataи процессныйglobal _REVEALу потребителей больше не нужны. - Профиль потребители читают через
clikit.config.active_profile(brand)(контекст → env). Тем, кто ещё берёт его изos.environнапрямую, доступен временный опт-инbuild_root_app(..., legacy_profile_env=True).
Публичный API
Зона clikit (clikit.__all__): CliError, AuthRequired, SessionExpired,
RateLimited, NotImplementedYet, ValidationError, init_output_mode, is_json,
console, emit_data, emit_message, emit_error, redact, AppConfig, McpServer,
AdapterConfig, validate_adapters_installed, AdapterProbe, set_adapter_probe,
get_adapter_probe, load_dotenv_file, interpolate_env,
discover_project_config, active_profile, ExecutionContext, build_context,
current_context, has_context, set_context, reset_context, use_context,
context_for, build_root_app, command, async_command, gated,
make_schema_command, scaffold_cli.
Депрекейт (строгие зоны): HttpClient / ApiError / RefreshCallback,
RetryPolicy / DEFAULT_RETRY, SecretStore, AppPaths / atomic_write_text /
chmod_600 / slugify ещё доступны из clikit (back-compat), но кидают
DeprecationWarning. Бери их канон напрямую из librarykit.transport /
librarykit.retry / librarykit.secret_store / librarykit.config_util.
Разработка
uv sync
uv run pytest -q
uv run ruff check clikit
Лицензия
MIT © 2026 Dmitry.
Metadata
Release files for s-clikit 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| s_clikit-0.2.0.tar.gz | 136.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| s_clikit-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 186.1 kB
Release files / s_clikit-0.2.0.tar.gz
| Download URL | s_clikit-0.2.0.tar.gz |
|---|---|
| Size | 136.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c9b3a7c1cdd2ce8f62d4ef249f351d6b9344485f04d09e1c4c408dc56ad151c2
|
|
BLAKE2b-256 checksum How to use checksums |
3d8f841d6b80546340cc11f47d1177e06feecd8aaacc0f32465ad722abf5f4a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / s_clikit-0.2.0-py3-none-any.whl
| Download URL | s_clikit-0.2.0-py3-none-any.whl |
|---|---|
| Size | 49.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c7f569e1ca7bdfba1bd7d9b833dbcd176900d8919e3d00509a7e9457c44b0679
|
|
BLAKE2b-256 checksum How to use checksums |
fb076e53cb3659b508eb14d124a310a2c43fd92b226f701adc85ea30662eaeba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|