s-skillkit
Локальное ядро управления навыками (skills): только локальная ФС-механика — ни
сети, ни auth. Из librarykit берётся ровно один модуль — librarykit.proc
(единый запуск подпроцессов: на Windows без всплывающих консольных окон и с
обязательным таймаутом); uv, git и npm кит зовёт только через него.
Что внутри
-
SkillStore(skillkit.installer) — материализация навыка в центральный стор и линковка (junction на Windows / symlink на POSIX) в scope агента:install_from_git/install_from_path/install/materializeupdate(инкрементальный sha-diff),link_existing,migrate_scoperemove(keep-local / purge / force)- P0 stub-would-clobber guard (stub не затирает живой контент);
- гейт принадлежности:
removeснимает ТОЛЬКО то, что кит ставил сам — каталог с нашей_skill_meta.jsonили ссылку в наш стор. Чужое (руками положенный навык в общем каталоге вроде~/.agents/skills) не удаляется, а попадает вRemoveResult.skipped_foreign+.message. Обойти можно лишь явно:remove(..., force=True)— на случай установок доисторических версий кита без меты.
-
targets—IAgentTarget+detect_agent/get_target(Claude Code, Codex, OpenCode, Antigravity). Форма навыка везде одна: каталог +SKILL.mdвнутри (плоский<имя>.mdне читает ни один агент). Раскладка сверена с живым опытом 2026-07-21 (навыки-пробы с кодовым словом вdescription):агент global project доказательность claude_code~/.claude/skills/<project>/.claude/skills/канон агента codex~/.agents/skills/<project>/.agents/skills/документация (живьём не проверено: аккаунт 402) opencode~/.config/opencode/skills/<project>/.opencode/skills/ОПЫТ antigravity~/.gemini/config/skills/нет ( ScopeUnsupported)ОПЫТ Antigravity (
agy) читает РОВНО один каталог; рабочие.agents/skillsи.gemini/skillsон не читает, поэтому project-scope у него — явная ошибка, а не тихая запись в никуда. Чтобы agy вообще видел навыки, в~/.gemini/settings.jsonнуженexperimental.skills = true— этот общий с gemini-cli файл кит НЕ трогает. OpenCode читает ещё три места (~/.opencode/skills,~/.agents/skills,<project>/.agents/skills), но кит туда не пишет и не убирает: он туда никогда и не ставил, а.agentsвдобавок общий с Codex — у каталога один владелец.Агент отдаёт и расположение своих конфигов:
mcp_config()(MCP-серверы; Claude Code —~/.claude.json, Codex —~/.codex/config.toml, Antigravity —~/.gemini/config/mcp_config.json, ключmcpServers),hook_config()(хуки). Смену раскладки закрывает механизмlegacy_dirnames(ЧТЕНИЕ старых путей +resolve_slug_dir/remove/migrate_scope). Из встроенных заявлен у Codex:~/.codex/skills— канон до 0.3.0, откуда наши установки теперь находятся, снимаются и переезжают на новый канон. Соседи по старому каталогу не страдают благодаря гейту принадлежности. Объявлять сюда «просто читаемые агентом» каталоги нельзя — только те, куда кит РЕАЛЬНО ставил. -
hook_register— хуки навыка ([[hooks]]) в настройки агента:register_hook/unregister_hook/list_hooks. Идемпотентно, чужие хуки не задеваются, агент с неизвестным форматом →status=manual(не падение). -
manifest—build_manifestдля publish + ридеры frontmatter /_skill_meta.toml. -
filter—.skillignore/files-allowlist фильтр (pathspec). -
project— проектный манифест.skills-hub/skills.toml. -
Paths— инъекция каталогов (store_dir/config_dir/bin_dir).Paths.default()— нативная раскладка через platformdirs.
Инъекция вместо завязки на конфиг
Кит НЕ читает env/config. Каталоги передаются явным Paths; git-учётка —
инъектируемым credential_resolver (callable url -> url). Потребитель (CLI)
читает env-токен и собирает резолвер:
from skillkit import SkillStore, Paths, get_target
paths = Paths.default() # или из ClientConfig
def resolver(url: str) -> str:
token = os.environ.get("SKILLS_HUB_GIT_TOKEN")
if token and url.startswith("https://") and "@" not in url:
return url.replace("https://", f"https://oauth2:{token}@", 1)
return url
store = SkillStore(get_target(None), paths.store_dir, credential_resolver=resolver)
Канон «супер-навыка» (навык + CLI + онбординг)
Супер-навык — навык, который несёт собственный CLI-инструмент. Канон нужен,
чтобы ОДИН и тот же навык одинаково ставился тремя путями: локальным
install-скриптом, skillery install из хаба и skillery install --path/--from-git.
Структура репозитория
<repo>/
pyproject.toml # пакет CLI-инструмента (публикуется на PyPI)
src/<tool>/ # исходники CLI
install/install.sh|.ps1 # локальный установщик (см. ниже)
skills/<name>/ # САМ НАВЫК — только это материализуется агенту
SKILL.md # инструкция для ИИ-агента
_skill_meta.toml # ДЕКЛАРАЦИЯ навыка (источник истины)
references/ agents/
Навык может лежать и в корне репо (SKILL.md рядом с _skill_meta.toml) — тогда
подпапка не нужна. Если навык в подпапке, хаб хранит её в Skill.skill_path, и
манифест версии читается ИМЕННО оттуда (иначе tooling-поля теряются).
_skill_meta.toml — полная декларация
description = "Atlas - local-first PM портфеля проектов и задач."
version = "0.3.0"
kind = "tooling" # prompt | comprehensive | tooling
tags = ["pm", "cli"]
# Release notes ЭТОЙ версии — «что изменилось». Опционально: нет поля — нет
# release notes. Хаб сохраняет текст у версии навыка и показывает на странице
# версий. Можно строкой (в т.ч. многострочной """...""") или списком пунктов.
changelog = [
"Добавлен `atlas backlog` — пул сырых идей.",
"Починен триаж забытых задач.",
]
# ВАЖНО (TOML): top-level массивы объявляются ДО заголовков [[...]] —
# иначе tomllib отнесёт ключ ВНУТРЬ таблицы, а не на верхний уровень.
runtime_dependencies = [
{ kind = "pip", spec = "atlas-pm==0.3.0" }, # чем ставится CLI
]
[[cli]] # какие команды навык приносит
command_name = "atlas"
entrypoint = "atlas.cli:app"
[[hooks]] # хук в настройки агента (ставится и СНИМАЕТСЯ)
event = "SessionStart" # обязателен
command = "atlas session-hook" # обязателен: встроенная команда CLI
matcher = "startup|resume" # опц. — когда именно
timeout = 15 # опц., секунды
status_message = "Atlas triage…" # опц.
marker = "session-hook" # опц. — по чему узнаём СВОЙ хук (дефолт: command)
[onboarding] # что делать ПОСЛЕ установки
summary = "Локальный PM портфеля: проекты, задачи, эпики."
next_steps = [
"atlas setup # правила в CLAUDE.md/AGENTS.md + SessionStart-хук",
"atlas task triage # что в работе / застряло / забыто",
]
docs = "https://github.com/<owner>/<repo>#readme"
Как ставится: две дороги, один источник истины
Локальный install-скрипт (install/install.sh|.ps1) — для человека «с нуля»:
ставит uv (если нет) → uv tool install <пакет> → запускает post-setup
инструмента (напр. atlas setup). Скрипты держим ASCII-only: их тянут через
irm | iex / curl | sh, и не-ASCII может побиться.
skillery install <skill> — та же логика, но декларативно:
- материализует папку навыка агенту (global или project scope);
- читает
_skill_meta.tomlиз установленного навыка и ставитruntime_dependencies+ регистрируетcli[]/mcp[]/hooks[](apply_tooling_artifacts); - печатает
[onboarding]— «что делать дальше».
revert_tooling_artifacts (disable/remove) снимает ровно эти артефакты — в том
числе хук: осиротевший хук продолжал бы звать удалённую команду на каждом старте
сессии агента. Чужие хуки и чужие настройки в файле не задеваются.
Источник истины для tooling — декларация в самом навыке, а не то, что доехало
в манифесте бандла хаба: у навыка в подпапке бандл может прийти без cli/
runtime_dependencies, поэтому инсталлятор до-читывает _skill_meta.toml.
Детект: не навреди стороннему навыку
Установка CLI запускается только по явной декларации (runtime_dependencies /
cli в _skill_meta.toml). Эвристики вида «рядом лежит pyproject.toml — значит
надо поставить пакет» ЗАПРЕЩЕНЫ: сторонний навык часто живёт в чужом репо, и такая
догадка поставила бы левый пакет. Навык без _skill_meta.toml (просто SKILL.md)
материализуется как есть — ничего не выполняется и не ставится.
Онбординг обязателен для супер-навыка
Навык, приносящий CLI, ОБЯЗАН объявить [onboarding].next_steps. Инсталлятор
печатает их сразу после установки, чтобы ИИ-агент довёл настройку сам, а не
оставлял пользователя с установленным, но ненастроенным инструментом. Контракт
вывода: в text-режиме — человекочитаемый список, в --json — структурные поля
(next_steps) в stderr, чтобы не засорять stdout с основным payload'ом.
Зависимости
tomli-w, pathspec, platformdirs. requires-python >=3.11. MIT.
Metadata
Release files for s-skillkit 0.5.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_skillkit-0.5.0.tar.gz | 340.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| s_skillkit-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 535.3 kB
Release files / s_skillkit-0.5.0.tar.gz
| Download URL | s_skillkit-0.5.0.tar.gz |
|---|---|
| Size | 340.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
503887bb1ecebdc96ff8aa686916944c69b8f042ead0e15f764c827a60cdf800
|
|
BLAKE2b-256 checksum How to use checksums |
4b77aa201b252114bbb696aa583ef57ffb21800758dbbd6f0601295823901936
|
| 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_skillkit-0.5.0-py3-none-any.whl
| Download URL | s_skillkit-0.5.0-py3-none-any.whl |
|---|---|
| Size | 195.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3f5f4eb7c9d7df05a1d27b1c2044db60b68e246c8748d757d73807af1bf5c397
|
|
BLAKE2b-256 checksum How to use checksums |
d3f6dcc6df8fb22b834cdf6397455f91ea32a925d32a419b1206bf8b3ce711ea
|
| 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}
|