Skip to main content

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-patch emit_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)

Source distribution for s-clikit 0.2.0
File Size Uploaded
s_clikit-0.2.0.tar.gz 136.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for s-clikit 0.2.0
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page