s-skillkit 0.3.7__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/CHANGELOG.md +25 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/PKG-INFO +1 -1
- s_skillkit-0.4.0/docs/adr/0000-template.md +20 -0
- s_skillkit-0.4.0/docs/adr/0001-kanon-navyka-zhivet-v-skillkit.md +122 -0
- s_skillkit-0.4.0/docs/adr/README.md +30 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/pyproject.toml +10 -1
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/__init__.py +32 -4
- s_skillkit-0.4.0/skillkit/canon.py +1046 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/hook_register.py +1 -1
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/installer/__init__.py +6 -6
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/installer/meta.py +3 -3
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/manifest.py +114 -3
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/mcp_register.py +1 -1
- s_skillkit-0.4.0/skillkit/plugin_register.py +260 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/targets/__init__.py +2 -2
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/targets/antigravity.py +27 -1
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/targets/base.py +80 -3
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/targets/claude_code.py +28 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/targets/detect.py +2 -2
- s_skillkit-0.4.0/tests/test_canon.py +233 -0
- s_skillkit-0.4.0/tests/test_claude_frontmatter.py +60 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_destructive_ownership_gate_2026_07_21.py +6 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_manifest.py +67 -0
- s_skillkit-0.4.0/tests/test_plugin_register.py +163 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_targets.py +1 -1
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/uv.lock +1 -1
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/.gitignore +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/.gitlab-ci.yml +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/AGENTS.md +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/LICENSE +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/README.md +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/binary_installer.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/bootstrap.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/collections.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/config.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/deps_installer.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/errors.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/filter.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/installer/differ.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/installer/fetchers.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/installer/fsops.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/installer/models.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/installer/ownership.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/linker.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/path_store.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/paths.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/pkg_manager.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/proc.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/project.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/targets/codex.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/targets/opencode.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/telemetry.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/tooling.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/skillkit/uv_bootstrap.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/conftest.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_agent_skill_layouts_2026_07_21.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_artifact_ownership_2272.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_binary_installer.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_bootstrap.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_collections.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_config.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_deps_binary.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_deps_installer.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_errors.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_filter.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_git_install.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_hooks.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_installer.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_legacy_paths_no_orphans_2026_07_21.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_mcp_register.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_no_raw_subprocess.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_packaging_lock.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_path_store.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_paths.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_pkg_manager.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_pkgsrc_not_in_agent_zone.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_proc.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_project.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_remove_ownership_guard_2026_07_21.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_stub_guard.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_telemetry_adapter.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_tooling.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_transactional_install.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_traversal_guard.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_typed_fields.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_uv_bootstrap.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_w268_subdir_skill.py +0 -0
- {s_skillkit-0.3.7 → s_skillkit-0.4.0}/tests/test_w272_empty_manifest_guard.py +0 -0
|
@@ -6,6 +6,31 @@
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
### Added — канон навыка переехал в кит: `skillkit.canon` (#162)
|
|
10
|
+
|
|
11
|
+
- **Один источник правды вместо трёх.** Форма навыка (раскладка `src/<пакет>/` +
|
|
12
|
+
`skills/<slug>/` + `install/` + `tests/`, frontmatter `SKILL.md`, порядок ключей
|
|
13
|
+
`_skill_meta.toml`, `pyproject` с синхронной версией и командой) жила в трёх
|
|
14
|
+
копиях: `clikit.scaffold`, `skillery_cli.templates` и
|
|
15
|
+
`reverse_factory.factory.canon`. Копии разошлись: скаффолд `clikit` собирал
|
|
16
|
+
плоскую раскладку с `kind = "cli"` — родом, которого нет вовсе, — и такой навык
|
|
17
|
+
не проходил валидатор. Канон перенесён в кит целиком, вместе с тестами.
|
|
18
|
+
- **Почему в `skillkit`.** Всё, что рендерит канон, читает и ставит этот же кит:
|
|
19
|
+
`manifest` разбирает `_skill_meta.toml`, `targets` раскладывает папку навыка по
|
|
20
|
+
агентам, `bootstrap` поднимает зависимости и self-check, а сгенерированный
|
|
21
|
+
`install/install.py` — тонкая обёртка над китом. Обоснование и отклонённые
|
|
22
|
+
варианты — `docs/adr/0001-kanon-navyka-zhivet-v-skillkit.md`.
|
|
23
|
+
- **Что появилось:** `SkillLayout` / `layout`, `SkillMeta`, `render_skill_md`,
|
|
24
|
+
`render_skill_meta`, `render_pyproject`, `render_install_docs`,
|
|
25
|
+
`render_skillgateignore`, `validate_canonical_skill`, `ALLOWED_KINDS`,
|
|
26
|
+
`module_name` / `command_name`, `read_declared_name` / `stamp_declared_name`.
|
|
27
|
+
- **Форма против смысла.** Канон держит форму; тело `SKILL.md` и описание
|
|
28
|
+
приносит производитель через `body=` / `description=`. Тело по умолчанию —
|
|
29
|
+
нейтральный каркас AK-канона (роутер + пять секций с TODO), без упоминаний
|
|
30
|
+
конкретной фабрики: кит остаётся брендо-нейтральным.
|
|
31
|
+
- **Зависимостей не прибавилось:** модуль на голом stdlib (`re`, `tomllib`,
|
|
32
|
+
`dataclasses`, `pathlib`).
|
|
33
|
+
|
|
9
34
|
### Fixed — гейт принадлежности у CLI-команд и MCP-серверов (#2272)
|
|
10
35
|
|
|
11
36
|
- **Навык больше не забирает чужую команду.** `path_store.add_cli` снимал ЛЮБОЙ
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: s-skillkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Локальное ядро управления навыками: install из git/локальной папки, junction/symlink-линковка в scope агента, .skillignore-фильтр, build manifest, project-манифест. 0 завязок на сеть/auth — stdlib + tomli-w + pathspec + platformdirs.
|
|
5
5
|
Author: Dmitry
|
|
6
6
|
License: MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# NNNN. Краткий заголовок решения
|
|
2
|
+
|
|
3
|
+
- **Статус:** proposed | accepted | superseded (→ ADR-NNNN) | deprecated
|
|
4
|
+
- **Дата:** ГГГГ-ММ-ДД
|
|
5
|
+
|
|
6
|
+
## Контекст
|
|
7
|
+
|
|
8
|
+
Какую ситуацию/проблему решаем. Что вынуждает принять решение сейчас: ограничения, требования, силы, которые тянут в разные стороны. Достаточно, чтобы понять «почему» без внешнего контекста.
|
|
9
|
+
|
|
10
|
+
## Решение
|
|
11
|
+
|
|
12
|
+
Что именно решили — одной-двумя фразами, в настоящем времени: «Делаем X». Конкретно и проверяемо.
|
|
13
|
+
|
|
14
|
+
## Последствия
|
|
15
|
+
|
|
16
|
+
Что становится проще и что — сложнее/дороже после принятия. Плюсы, минусы, новые обязательства и ограничения, которые теперь придётся держать.
|
|
17
|
+
|
|
18
|
+
## Альтернативы
|
|
19
|
+
|
|
20
|
+
Какие варианты рассматривали и **почему отклонили** (в этом ценность записи). Кратко: вариант → причина отказа / отложено до условия.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# 0001. Канон навыка живёт в skillkit — рядом с тем, кто его читает
|
|
2
|
+
|
|
3
|
+
- **Статус:** accepted
|
|
4
|
+
- **Дата:** 2026-09-01
|
|
5
|
+
|
|
6
|
+
## Контекст
|
|
7
|
+
|
|
8
|
+
«Навык в каноне Skillery» — это набор файлов строго определённой формы:
|
|
9
|
+
`skills/<slug>/SKILL.md` с frontmatter, `skills/<slug>/_skill_meta.toml`,
|
|
10
|
+
`src/<пакет>/` (src-layout), `tests/`, `install/`, `.skillgateignore`,
|
|
11
|
+
`pyproject.toml` с той же версией и той же консольной командой, что в манифесте.
|
|
12
|
+
|
|
13
|
+
Эту форму на диск кладут РАЗНЫЕ производители, и каждый завёл свою копию правил:
|
|
14
|
+
|
|
15
|
+
1. **`clikit.scaffold`** (790 строк) — свои `render_skill_md` / `render_skill_meta` /
|
|
16
|
+
`render_pyproject` / `render_install_skill` / `render_self_check` /
|
|
17
|
+
`render_smoke_test`. Раскладка ДРУГАЯ: плоский `<pkg>/` вместо `src/<pkg>/`,
|
|
18
|
+
`SKILL.md` и `_skill_meta.toml` в КОРНЕ вместо `skills/<slug>/`,
|
|
19
|
+
`kind = "cli"` — рода, которого нет в списке допустимых
|
|
20
|
+
(`prompt` / `comprehensive` / `tooling`), — ни `install/`, ни `tests/`.
|
|
21
|
+
2. **`skillery_cli.templates`** (802 строки) — свои `render_skill_meta_toml`,
|
|
22
|
+
онбординг-триада `scripts/{install_skill,self_check,smoke_test}.py`,
|
|
23
|
+
`render_pyproject`, CLI-скелет. В докстроке прямо написано «зеркалит
|
|
24
|
+
`clikit.scaffold.render_cli_module`» — то есть копия по замыслу.
|
|
25
|
+
3. **`reverse_factory.factory.canon`** (1033 строки) — раскладка, рендер,
|
|
26
|
+
`validate_canonical_skill`; три производителя фабрики уже сведены на него
|
|
27
|
+
фитнес-функцией `test_factory_canon_single_source.py`.
|
|
28
|
+
|
|
29
|
+
Цена расхождения не гипотетическая: навык, собранный `clikit.scaffold_cli`, не
|
|
30
|
+
проходит `validate_canonical_skill` — его топологию перед публикацией переводили
|
|
31
|
+
РУКАМИ. Ровно этот ручной шаг канон и должен был убрать.
|
|
32
|
+
|
|
33
|
+
Выбирать источник пришлось сейчас потому, что канон фабрики только что обкатан
|
|
34
|
+
живьём (генерация → `uv sync` → `uv run pytest` → боевой прогон установщика,
|
|
35
|
+
reverse-factory 84c7749), и держать рядом с работающим ещё две копии — значит
|
|
36
|
+
гарантированно разойтись с ним снова.
|
|
37
|
+
|
|
38
|
+
## Решение
|
|
39
|
+
|
|
40
|
+
**Единственный канон навыка — модуль `skillkit.canon`.** Туда переносится
|
|
41
|
+
проверенный канон фабрики целиком: раскладка (`SkillLayout`, `layout`), рендер
|
|
42
|
+
(`render_skill_md` / `render_skill_meta` / `render_pyproject` /
|
|
43
|
+
`render_install_docs` / `render_skillgateignore`) и валидатор
|
|
44
|
+
`validate_canonical_skill` вместе с его тестами.
|
|
45
|
+
|
|
46
|
+
Почему именно `skillkit`, а не `clikit` и не фабрика:
|
|
47
|
+
|
|
48
|
+
- **Писатель формата обязан жить рядом с читателем.** Всё, что рендерит канон,
|
|
49
|
+
читает и ставит этот же кит: `_skill_meta.toml` разбирает `skillkit.manifest`,
|
|
50
|
+
папку навыка раскладывает по агентам `skillkit.targets`, зависимости и
|
|
51
|
+
self-check поднимает `skillkit.bootstrap`. Сгенерированный `install/install.py`
|
|
52
|
+
— буквально тонкая обёртка над `skillkit`. Разведи их по разным репозиториям —
|
|
53
|
+
и они разойдутся молча, как уже разошлись.
|
|
54
|
+
- **`clikit` — не та зона.** Кит отвечает за плоть CLI (command-kit, вывод,
|
|
55
|
+
конфиг, транспорт) и про навыки не знает ничего. То, что он рендерил
|
|
56
|
+
`_skill_meta.toml` с несуществующим `kind = "cli"`, — прямое следствие того,
|
|
57
|
+
что формат жил не у своего владельца.
|
|
58
|
+
- **Фабрика — потребитель, а не библиотека.** `reverse-factory` тянет playwright,
|
|
59
|
+
camoufox, nodriver. Сделать её зависимостью клиента `skillery` нельзя.
|
|
60
|
+
- **Кит уже общий.** И `reverse-factory`, и `skillery-cli` уже объявляют
|
|
61
|
+
`s-skillkit>=0.3.7` — новая зависимость никому не заводится.
|
|
62
|
+
- **Канон ничего не тянет.** Модуль на голом stdlib (`re`, `tomllib`,
|
|
63
|
+
`dataclasses`, `pathlib`): TOML пишем сами, читаем через `tomllib`. Лёгкий кит
|
|
64
|
+
остаётся лёгким.
|
|
65
|
+
|
|
66
|
+
Граница «форма против смысла»: канон держит ФОРМУ (frontmatter, аллоулист
|
|
67
|
+
`files`, порядок ключей манифеста, раскладку файлов, состав `install/`), а СМЫСЛ
|
|
68
|
+
приносит производитель через `body=` / `description=`. Поэтому тело `SKILL.md` по
|
|
69
|
+
умолчанию в ките нейтральное (каркас AK-канона с TODO), а реверс-специфичное тело
|
|
70
|
+
остаётся в фабрике.
|
|
71
|
+
|
|
72
|
+
Остальные места зовут канон, а не копируют его:
|
|
73
|
+
|
|
74
|
+
- `reverse_factory.factory.canon` — тонкий ре-экспорт `skillkit.canon` плюс своё
|
|
75
|
+
реверс-тело `SKILL.md`. Путь модуля сохранён: по нему ходят шесть импортёров и
|
|
76
|
+
фитнес-функция.
|
|
77
|
+
- `clikit.scaffold` — рендер навыка удалён целиком; кит скаффолдит только CLI.
|
|
78
|
+
|
|
79
|
+
## Последствия
|
|
80
|
+
|
|
81
|
+
Правило канона теперь ровно одно на всю экосистему: правка формы навыка делается
|
|
82
|
+
в `skillkit.canon`, и её видят все производители сразу. Валидатор и рендер лежат
|
|
83
|
+
рядом, поэтому «рендер выдал то, что валидатор не принимает» ловится тестом в
|
|
84
|
+
самом ките.
|
|
85
|
+
|
|
86
|
+
`clikit` перестал уметь генерировать навык — это НАМЕРЕННАЯ потеря. Кто
|
|
87
|
+
скаффолдил навык через `clikit.scaffold_cli(skill=True)`, получал невалидный
|
|
88
|
+
навык; теперь он получает CLI-пакет и берёт навык у `skillkit.canon` (или у
|
|
89
|
+
`skillery new`). Обратная совместимость сломана осознанно: сохранять способ
|
|
90
|
+
сделать заведомо непроходящий навык — хуже, чем убрать его.
|
|
91
|
+
|
|
92
|
+
Кит подрос: `skillkit` перестал быть чисто ФС-механикой и взял на себя ещё и
|
|
93
|
+
рендер. Оправдание — тот же аргумент, что и в решении: формат, который кит
|
|
94
|
+
читает, он же должен и писать. Брендо-нейтральность при этом сохранена: имён
|
|
95
|
+
конкретных продуктов и фабрик в модуле нет.
|
|
96
|
+
|
|
97
|
+
Обязательство на будущее: `skillery-cli` пока держит свою копию (`templates/`).
|
|
98
|
+
Пока миграция не закончена, у канона фактически два писателя, и расхождение
|
|
99
|
+
возможно — это записано отдельной задачей и закрывается фитнес-функцией на
|
|
100
|
+
стороне клиента, а не договорённостью.
|
|
101
|
+
|
|
102
|
+
## Альтернативы
|
|
103
|
+
|
|
104
|
+
**Оставить канон в `reverse-factory`, остальным импортировать оттуда.** Отклонено:
|
|
105
|
+
фабрика тянет браузерный стек (playwright / camoufox / nodriver), и клиент
|
|
106
|
+
`skillery`, который ставится пользователю одной командой, не может от неё
|
|
107
|
+
зависеть. Библиотечный код в приложении — инверсия слоёв.
|
|
108
|
+
|
|
109
|
+
**Сделать каноном `clikit`.** Отклонено: чужая зона. `clikit` — плоть CLI, про
|
|
110
|
+
навыки не знает; именно его версия канона и разошлась сильнее всех
|
|
111
|
+
(`kind = "cli"`, плоская раскладка). Кроме того, `clikit` не зависит от
|
|
112
|
+
`skillkit`, а канон обязан согласовываться с читателем манифеста — пришлось бы
|
|
113
|
+
либо заводить зависимость снизу вверх, либо снова дублировать знание.
|
|
114
|
+
|
|
115
|
+
**Отдельный кит `skillcanonkit`.** Отклонено как лишняя сущность: канон — 1000
|
|
116
|
+
строк stdlib, целиком про навык, и уже сейчас неотделим от `manifest`/`targets`.
|
|
117
|
+
Новый кит дал бы четвёртый репозиторий, четвёртый выпуск и четвёртую версию в
|
|
118
|
+
чужих зависимостях ради модуля, у которого один естественный владелец.
|
|
119
|
+
|
|
120
|
+
**Не переносить, а описать канон документом и проверять линтером.** Отклонено:
|
|
121
|
+
документ не рендерит. Копии остались бы копиями, а расхождение ловилось бы
|
|
122
|
+
постфактум — ровно так и жили до сих пор.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# ADR — журнал архитектурных решений
|
|
2
|
+
|
|
3
|
+
**Что это.** ADR (Architecture Decision Record) — короткий документ на **одно** архитектурное решение: контекст → что решили → почему → последствия. Лежат здесь, в `docs/adr/`, со **сквозной нумерацией** (`0001-…`, `0002-…`). Шаблон — [`0000-template.md`](0000-template.md).
|
|
4
|
+
|
|
5
|
+
**Зачем.** «Почему» проекта нельзя держать в комментариях к задачам и переписке — оно теряется. ADR — дистиллят решения: агент читает его **перед** правкой и не «чинит» то, что было выбрано сознательно. Дёшев по токенам: одно решение прочитать проще, чем реконструировать его из истории коммитов.
|
|
6
|
+
|
|
7
|
+
## Когда заводить ADR — когда сошлись 3 условия
|
|
8
|
+
|
|
9
|
+
1. решение **дорого откатить** (влияет на структуру, данные, контракты);
|
|
10
|
+
2. без контекста оно **выглядит странно** (кто-то потом захочет «починить»);
|
|
11
|
+
3. были **реальные альтернативы** и выбор — осознанный трейдофф.
|
|
12
|
+
|
|
13
|
+
Если хотя бы одно условие не выполнено — ADR не нужен, хватит `comment` на задаче в Atlas.
|
|
14
|
+
|
|
15
|
+
## Правила ведения
|
|
16
|
+
|
|
17
|
+
- **Нумерация сквозная**, файл — `NNNN-краткий-слаг.md` (`0001-operating-model-foundamentals.md`).
|
|
18
|
+
- **Не редактировать задним числом.** Принятое решение — исторический факт. Если решение отменено новым — старому ставим `Статус: superseded` (со ссылкой на новое ADR), а не переписываем его.
|
|
19
|
+
- **«Схлопывание».** Когда цепочка `superseded` разрослась, допустимо свести её к одному ADR с текущим состоянием — ради экономии контекста агента. Прежние помечаем как схлопнутые.
|
|
20
|
+
- **Статусы:** `proposed` → `accepted` → (`superseded` / `deprecated`).
|
|
21
|
+
|
|
22
|
+
## Что НЕ идёт в ADR
|
|
23
|
+
|
|
24
|
+
- **состояние** (ветка/worktree, стадия) — это тег/поле задачи в Atlas;
|
|
25
|
+
- **ход работы / handoff** — `comment` на задаче в Atlas;
|
|
26
|
+
- **черновой план реализации** — scratchpad, в `.gitignore`, в репо не коммитится.
|
|
27
|
+
|
|
28
|
+
Полная модель фиксации артефактов (4 слоя) — в `ai-ecosystem-core/AGENT-OPERATING-MODEL.md`, раздел «Модель фиксации артефактов».
|
|
29
|
+
|
|
30
|
+
**Методология:** практика ADR (Michael Nygard), компактный формат Matt Pocock (`github.com/mattpocock/skills`, grill-with-docs), примеры в NATS / AG2.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "s-skillkit"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Локальное ядро управления навыками: install из git/локальной папки, junction/symlink-линковка в scope агента, .skillignore-фильтр, build manifest, project-манифест. 0 завязок на сеть/auth — stdlib + tomli-w + pathspec + platformdirs."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -55,6 +55,15 @@ select = ["E", "F", "I", "B", "UP", "N", "SIM", "RUF"]
|
|
|
55
55
|
# возвращает (store, target, store_dir); читаемее, чем индексирование).
|
|
56
56
|
ignore = ["RUF001", "RUF002", "RUF003", "RUF022", "RUF059"]
|
|
57
57
|
|
|
58
|
+
[tool.ruff.lint.per-file-ignores]
|
|
59
|
+
# canon.py несёт ДОСЛОВНЫЕ шаблоны генерируемых файлов (install.ps1 / install.sh /
|
|
60
|
+
# install.py / _skill_meta.toml). Перенос строки внутри такого шаблона — это правка
|
|
61
|
+
# ЧУЖОГО файла, который потом ляжет на диск навыка: команда PowerShell,
|
|
62
|
+
# разорванная ради длины, просто не выполнится. Ограничение длины снято для
|
|
63
|
+
# модуля целиком, потому что `# noqa` внутри многострочного литерала уехал бы в
|
|
64
|
+
# сам вывод.
|
|
65
|
+
"skillkit/canon.py" = ["E501"]
|
|
66
|
+
|
|
58
67
|
[tool.pytest.ini_options]
|
|
59
68
|
asyncio_mode = "auto"
|
|
60
69
|
testpaths = ["tests"]
|
|
@@ -10,8 +10,11 @@ platformdirs. Запуск подпроцессов (uv/git/cmd/powershell) —
|
|
|
10
10
|
локальная папка / stub) + junction/symlink-линковка в scope агента,
|
|
11
11
|
инкрементальный update по sha-diff, remove/keep-local/purge, migrate_scope.
|
|
12
12
|
Включает P0 stub-would-clobber guard.
|
|
13
|
-
- ``targets`` — ``
|
|
13
|
+
- ``targets`` — ``AgentTarget`` + детект агента (Claude Code / Codex /
|
|
14
14
|
OpenCode / Antigravity). Раскладки сверены с живым опытом 2026-07-21.
|
|
15
|
+
- ``canon`` — КАНОН раскладки навыка: рендер (SKILL.md / _skill_meta.toml /
|
|
16
|
+
pyproject / install/ / .skillgateignore) и ``validate_canonical_skill``.
|
|
17
|
+
Писатель формата живёт рядом с читателем (``manifest``/``targets``) — ADR-0001.
|
|
15
18
|
- ``manifest`` — build manifest для publish + ридеры frontmatter / _skill_meta.toml
|
|
16
19
|
(в т.ч. артефакты установки: cli / mcp / runtime_dependencies / onboarding /
|
|
17
20
|
hooks).
|
|
@@ -44,6 +47,7 @@ from __future__ import annotations
|
|
|
44
47
|
from skillkit import (
|
|
45
48
|
binary_installer,
|
|
46
49
|
bootstrap,
|
|
50
|
+
canon,
|
|
47
51
|
collections,
|
|
48
52
|
deps_installer,
|
|
49
53
|
filter,
|
|
@@ -64,6 +68,18 @@ from skillkit.binary_installer import (
|
|
|
64
68
|
platform_asset_name,
|
|
65
69
|
)
|
|
66
70
|
from skillkit.bootstrap import bootstrap_skill, run_self_check
|
|
71
|
+
from skillkit.canon import (
|
|
72
|
+
ALLOWED_KINDS,
|
|
73
|
+
SkillLayout,
|
|
74
|
+
SkillMeta,
|
|
75
|
+
layout,
|
|
76
|
+
render_install_docs,
|
|
77
|
+
render_pyproject,
|
|
78
|
+
render_skill_md,
|
|
79
|
+
render_skill_meta,
|
|
80
|
+
render_skillgateignore,
|
|
81
|
+
validate_canonical_skill,
|
|
82
|
+
)
|
|
67
83
|
from skillkit.collections import LocalCollectionError
|
|
68
84
|
from skillkit.config import SkillkitConfig, configure, reset_to_defaults
|
|
69
85
|
from skillkit.errors import (
|
|
@@ -111,7 +127,7 @@ from skillkit.targets import (
|
|
|
111
127
|
ClaudeCodeTarget,
|
|
112
128
|
CodexTarget,
|
|
113
129
|
HookConfigDescriptor,
|
|
114
|
-
|
|
130
|
+
AgentTarget,
|
|
115
131
|
McpConfigDescriptor,
|
|
116
132
|
OpenCodeTarget,
|
|
117
133
|
agent_skill_dir,
|
|
@@ -120,7 +136,7 @@ from skillkit.targets import (
|
|
|
120
136
|
)
|
|
121
137
|
from skillkit.uv_bootstrap import ensure_uv
|
|
122
138
|
|
|
123
|
-
__version__ = "0.
|
|
139
|
+
__version__ = "0.4.0"
|
|
124
140
|
|
|
125
141
|
__all__ = [
|
|
126
142
|
"__version__",
|
|
@@ -168,7 +184,7 @@ __all__ = [
|
|
|
168
184
|
"stamp_ownership",
|
|
169
185
|
"skill_dir_name",
|
|
170
186
|
# targets
|
|
171
|
-
"
|
|
187
|
+
"AgentTarget",
|
|
172
188
|
"BaseAgentTarget",
|
|
173
189
|
"ClaudeCodeTarget",
|
|
174
190
|
"CodexTarget",
|
|
@@ -179,6 +195,17 @@ __all__ = [
|
|
|
179
195
|
"agent_skill_dir",
|
|
180
196
|
"detect_agent",
|
|
181
197
|
"get_target",
|
|
198
|
+
# канон раскладки навыка (рендер + валидатор)
|
|
199
|
+
"ALLOWED_KINDS",
|
|
200
|
+
"SkillLayout",
|
|
201
|
+
"SkillMeta",
|
|
202
|
+
"layout",
|
|
203
|
+
"render_install_docs",
|
|
204
|
+
"render_pyproject",
|
|
205
|
+
"render_skill_md",
|
|
206
|
+
"render_skill_meta",
|
|
207
|
+
"render_skillgateignore",
|
|
208
|
+
"validate_canonical_skill",
|
|
182
209
|
# manifest
|
|
183
210
|
"BuiltManifest",
|
|
184
211
|
"build_manifest",
|
|
@@ -194,6 +221,7 @@ __all__ = [
|
|
|
194
221
|
"bootstrap_skill",
|
|
195
222
|
"run_self_check",
|
|
196
223
|
# подмодули (ФС-механика навыка)
|
|
224
|
+
"canon",
|
|
197
225
|
"linker",
|
|
198
226
|
"filter",
|
|
199
227
|
"manifest",
|