skillsinc 0.1.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.
Files changed (36) hide show
  1. skillsinc-0.1.0/LICENSE +21 -0
  2. skillsinc-0.1.0/PKG-INFO +150 -0
  3. skillsinc-0.1.0/README.md +124 -0
  4. skillsinc-0.1.0/pyproject.toml +232 -0
  5. skillsinc-0.1.0/pyproject.toml.orig +140 -0
  6. skillsinc-0.1.0/src/skillsinc/__init__.py +3 -0
  7. skillsinc-0.1.0/src/skillsinc/__main__.py +80 -0
  8. skillsinc-0.1.0/src/skillsinc/applier.py +207 -0
  9. skillsinc-0.1.0/src/skillsinc/blocks.py +87 -0
  10. skillsinc-0.1.0/src/skillsinc/cli.py +118 -0
  11. skillsinc-0.1.0/src/skillsinc/commands.py +90 -0
  12. skillsinc-0.1.0/src/skillsinc/config.py +342 -0
  13. skillsinc-0.1.0/src/skillsinc/diff.py +359 -0
  14. skillsinc-0.1.0/src/skillsinc/entries.py +490 -0
  15. skillsinc-0.1.0/src/skillsinc/exceptions.py +27 -0
  16. skillsinc-0.1.0/src/skillsinc/frontmatter.py +87 -0
  17. skillsinc-0.1.0/src/skillsinc/jsonc.py +313 -0
  18. skillsinc-0.1.0/src/skillsinc/lock.py +60 -0
  19. skillsinc-0.1.0/src/skillsinc/manifest.py +135 -0
  20. skillsinc-0.1.0/src/skillsinc/models.py +172 -0
  21. skillsinc-0.1.0/src/skillsinc/paths.py +84 -0
  22. skillsinc-0.1.0/src/skillsinc/plan.py +116 -0
  23. skillsinc-0.1.0/src/skillsinc/planner.py +492 -0
  24. skillsinc-0.1.0/src/skillsinc/profiles/__init__.py +3 -0
  25. skillsinc-0.1.0/src/skillsinc/profiles/base.py +249 -0
  26. skillsinc-0.1.0/src/skillsinc/profiles/claude.py +166 -0
  27. skillsinc-0.1.0/src/skillsinc/profiles/codex.py +263 -0
  28. skillsinc-0.1.0/src/skillsinc/profiles/copilot.py +146 -0
  29. skillsinc-0.1.0/src/skillsinc/profiles/hooks.py +155 -0
  30. skillsinc-0.1.0/src/skillsinc/profiles/registry.py +43 -0
  31. skillsinc-0.1.0/src/skillsinc/profiles/shared.py +59 -0
  32. skillsinc-0.1.0/src/skillsinc/py.typed +0 -0
  33. skillsinc-0.1.0/src/skillsinc/report.py +245 -0
  34. skillsinc-0.1.0/src/skillsinc/settings.py +39 -0
  35. skillsinc-0.1.0/src/skillsinc/sources.py +481 -0
  36. skillsinc-0.1.0/src/skillsinc/starter.py +107 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mike Hill
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: skillsinc
3
+ Version: 0.1.0
4
+ Summary: Sync one library of agent skills, instructions, agents, and prompts into every AI coding harness you use.
5
+ Keywords: agents,skills,claude-code,codex,copilot,sync
6
+ Author: Mike Hill
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Software Development
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: pyyaml>=6.0.3
20
+ Requires-Dist: tomlkit>=0.13.3
21
+ Requires-Python: >=3.12
22
+ Project-URL: Homepage, https://github.com/mikejhill/skillsinc
23
+ Project-URL: Issues, https://github.com/mikejhill/skillsinc/issues
24
+ Project-URL: Changelog, https://github.com/mikejhill/skillsinc/blob/main/CHANGELOG.md
25
+ Description-Content-Type: text/markdown
26
+
27
+ # SkillSinc
28
+
29
+ [![CI](https://github.com/mikejhill/skillsinc/actions/workflows/ci.yml/badge.svg)](https://github.com/mikejhill/skillsinc/actions/workflows/ci.yml)
30
+ [![Release](https://github.com/mikejhill/skillsinc/actions/workflows/release.yml/badge.svg)](https://github.com/mikejhill/skillsinc/actions/workflows/release.yml)
31
+ [![License](https://img.shields.io/github/license/mikejhill/skillsinc)](LICENSE)
32
+
33
+ Write your agent skills, instructions, agents, prompts, MCP servers, reference files, and hooks once. SkillSinc copies them into Claude Code, GitHub Copilot, VS Code, Codex, and the shared `~/.agents` folder, converting formats where it must and saying so when a conversion loses something.
34
+
35
+ It replaces hand-copying, symlinks, and per-tool sync scripts with one command that shows you every change before it makes it.
36
+
37
+ ## How it works
38
+
39
+ ```mermaid
40
+ graph LR
41
+ Library[Your library<br/>skills/ instructions/ agents/ prompts/] --> Plan[skillsinc plan]
42
+ Plan --> Claude[~/.claude]
43
+ Plan --> Copilot[~/.copilot]
44
+ Plan --> VSCode[VS Code prompts]
45
+ Plan --> Codex[~/.codex/AGENTS.md]
46
+ Plan --> Agents[~/.agents/skills]
47
+ ```
48
+
49
+ - **Your library is the source of truth.** A sync makes each destination match it: new items are added, changed items updated, removed items deleted.
50
+ - **SkillSinc only touches what it wrote.** It records every file it owns. An existing file it did not write blocks that destination until you review it and pass `--adopt`.
51
+ - **Nothing is written without a plan.** `skillsinc plan` lists every change; `skillsinc sync` applies the same plan.
52
+ - **Lossy conversions are opt-in.** If a harness cannot represent a field (for example, Claude ignores Copilot `tools` lists), the item is skipped until the route sets `allow_lossy = true`.
53
+ - **A broken source never deletes anything.** If a library cannot be read completely, its destinations are left untouched.
54
+
55
+ ## Install
56
+
57
+ Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
58
+
59
+ ```bash
60
+ uv tool install git+https://github.com/mikejhill/skillsinc.git
61
+ ```
62
+
63
+ ## Quick start
64
+
65
+ 1. Write a configuration. It enables a destination for every harness folder found on this machine and creates an empty library at `~/.config/skillsinc/library` (`$XDG_CONFIG_HOME/skillsinc/library`). Pass `--source DIR` to use an existing library instead:
66
+
67
+ ```bash
68
+ skillsinc init
69
+ ```
70
+
71
+ 2. Preview the changes:
72
+
73
+ ```bash
74
+ skillsinc plan
75
+ ```
76
+
77
+ 3. Apply them:
78
+
79
+ ```bash
80
+ skillsinc sync
81
+ ```
82
+
83
+ Run `skillsinc sync` again whenever the library changes, or schedule it with Task Scheduler, launchd, or a systemd timer using the [scheduling examples](docs/guides/scheduling.md). An overlapping run exits without writing.
84
+
85
+ ## Library layout
86
+
87
+ The layout matches GitHub Copilot's file conventions, so an existing Copilot library works unchanged:
88
+
89
+ ```text
90
+ my-agent-library/
91
+ ├── skills/<name>/SKILL.md # plus any supporting files
92
+ ├── instructions/<name>.instructions.md
93
+ ├── agents/<name>.agent.md
94
+ ├── prompts/<name>.prompt.md
95
+ ├── mcp/<name>.json # one MCP server definition per file
96
+ ├── resources/<name>.md # reference files, copied as written
97
+ ├── hooks/<name>.json # one Copilot CLI hook file per file
98
+ └── plugins/<plugin>/ # Claude Code plugin layout, expanded into the kinds above
99
+ ```
100
+
101
+ `INTENT.md`, `*.intent.md`, and hidden files are never distributed. A plugin's `skills/`, `agents/`, `commands/`, and `.mcp.json` are synced as skills, agents, prompts, and MCP servers; everything else in it (hooks, scripts, LSP servers) is reported as a loss. See [decision 0005](docs/decisions/0005-plugins-expand-into-kinds.md).
102
+
103
+ ## What each harness receives
104
+
105
+ | Profile | Skills | Instructions | Agents | Prompts | MCP servers | Resources | Hooks |
106
+ | --------- | --------- | ---------------------------- | -------------------- | -------------------- | ------------------------------ | ------------------------------------- | ----------------------- |
107
+ | `claude` | `skills/` | `rules/<name>.md` (`paths`) | `agents/<name>.md` | `commands/<name>.md` | `~/.claude.json` `mcpServers` | `resources/` + `CLAUDE.md` `@` import | `settings.json` `hooks` |
108
+ | `copilot` | `skills/` | `instructions/` | `agents/` | — | `mcp-config.json` `mcpServers` | `resources/` | `hooks/` |
109
+ | `vscode` | — | `<name>.instructions.md` | `<name>.agent.md` | `<name>.prompt.md` | `User/mcp.json` `servers` | — | — |
110
+ | `codex` | — | managed block in `AGENTS.md` | `agents/<name>.toml` | — | — | — | — |
111
+ | `agents` | `skills/` | — | — | — | — | — | — |
112
+ | `generic` | verbatim | verbatim | verbatim | verbatim | verbatim | verbatim | verbatim |
113
+
114
+ Run `skillsinc profiles` for the same table. See [harness profiles](docs/guides/harness-profiles.md) for exact conversions.
115
+
116
+ ## Commands
117
+
118
+ | Command | Purpose |
119
+ | -------------------- | -------------------------------------------------- |
120
+ | `skillsinc init` | Write a starter configuration |
121
+ | `skillsinc plan` | Show every change a sync would make; write nothing |
122
+ | `skillsinc sync` | Apply the plan |
123
+ | `skillsinc profiles` | List harness profiles and what each kind becomes |
124
+
125
+ `plan` and `sync` accept `--destination NAME` (repeatable), `--adopt`, `--json`, `--verbose`, and `--config PATH`. Exit codes: `0` success, `1` a destination was blocked or failed, `2` configuration or usage error, `130` interrupted.
126
+
127
+ ## Documentation
128
+
129
+ - [Configuration reference](docs/guides/configuration.md)
130
+ - [Command-line reference](docs/guides/command-line.md)
131
+ - [Scheduling](docs/guides/scheduling.md)
132
+ - [Development guide](docs/guides/development.md)
133
+ - [Roadmap](docs/planning/roadmap.md)
134
+ - [Harness profiles](docs/guides/harness-profiles.md)
135
+ - [Philosophy and goals](docs/architecture/philosophy.md)
136
+ - [Architecture](docs/architecture/overview.md)
137
+ - [Decision: rebuild scope](docs/decisions/0001-rebuild-scope.md)
138
+ - [Decision: MCP server entries](docs/decisions/0002-mcp-server-entries.md)
139
+ - [Decision: resources and Claude imports](docs/decisions/0003-resources-and-claude-imports.md)
140
+ - [Decision: TOML entries with tomlkit](docs/decisions/0004-toml-entries-with-tomlkit.md)
141
+ - [Decision: plugins expand into kinds](docs/decisions/0005-plugins-expand-into-kinds.md)
142
+ - [Decision: entry files beside a destination root](docs/decisions/0007-files-beside-the-root.md)
143
+ - [Decision: edit VS Code's JSONC mcp.json in place](docs/decisions/0008-jsonc-edits-in-place.md)
144
+ - [Decision: one copy of each item per harness](docs/decisions/0009-one-copy-per-harness.md)
145
+ - [Decision: MCP server options and per-profile overrides](docs/decisions/0010-mcp-server-options.md)
146
+ - [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md) · [Changelog](CHANGELOG.md)
147
+
148
+ ## License
149
+
150
+ [MIT](LICENSE)
@@ -0,0 +1,124 @@
1
+ # SkillSinc
2
+
3
+ [![CI](https://github.com/mikejhill/skillsinc/actions/workflows/ci.yml/badge.svg)](https://github.com/mikejhill/skillsinc/actions/workflows/ci.yml)
4
+ [![Release](https://github.com/mikejhill/skillsinc/actions/workflows/release.yml/badge.svg)](https://github.com/mikejhill/skillsinc/actions/workflows/release.yml)
5
+ [![License](https://img.shields.io/github/license/mikejhill/skillsinc)](LICENSE)
6
+
7
+ Write your agent skills, instructions, agents, prompts, MCP servers, reference files, and hooks once. SkillSinc copies them into Claude Code, GitHub Copilot, VS Code, Codex, and the shared `~/.agents` folder, converting formats where it must and saying so when a conversion loses something.
8
+
9
+ It replaces hand-copying, symlinks, and per-tool sync scripts with one command that shows you every change before it makes it.
10
+
11
+ ## How it works
12
+
13
+ ```mermaid
14
+ graph LR
15
+ Library[Your library<br/>skills/ instructions/ agents/ prompts/] --> Plan[skillsinc plan]
16
+ Plan --> Claude[~/.claude]
17
+ Plan --> Copilot[~/.copilot]
18
+ Plan --> VSCode[VS Code prompts]
19
+ Plan --> Codex[~/.codex/AGENTS.md]
20
+ Plan --> Agents[~/.agents/skills]
21
+ ```
22
+
23
+ - **Your library is the source of truth.** A sync makes each destination match it: new items are added, changed items updated, removed items deleted.
24
+ - **SkillSinc only touches what it wrote.** It records every file it owns. An existing file it did not write blocks that destination until you review it and pass `--adopt`.
25
+ - **Nothing is written without a plan.** `skillsinc plan` lists every change; `skillsinc sync` applies the same plan.
26
+ - **Lossy conversions are opt-in.** If a harness cannot represent a field (for example, Claude ignores Copilot `tools` lists), the item is skipped until the route sets `allow_lossy = true`.
27
+ - **A broken source never deletes anything.** If a library cannot be read completely, its destinations are left untouched.
28
+
29
+ ## Install
30
+
31
+ Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
32
+
33
+ ```bash
34
+ uv tool install git+https://github.com/mikejhill/skillsinc.git
35
+ ```
36
+
37
+ ## Quick start
38
+
39
+ 1. Write a configuration. It enables a destination for every harness folder found on this machine and creates an empty library at `~/.config/skillsinc/library` (`$XDG_CONFIG_HOME/skillsinc/library`). Pass `--source DIR` to use an existing library instead:
40
+
41
+ ```bash
42
+ skillsinc init
43
+ ```
44
+
45
+ 2. Preview the changes:
46
+
47
+ ```bash
48
+ skillsinc plan
49
+ ```
50
+
51
+ 3. Apply them:
52
+
53
+ ```bash
54
+ skillsinc sync
55
+ ```
56
+
57
+ Run `skillsinc sync` again whenever the library changes, or schedule it with Task Scheduler, launchd, or a systemd timer using the [scheduling examples](docs/guides/scheduling.md). An overlapping run exits without writing.
58
+
59
+ ## Library layout
60
+
61
+ The layout matches GitHub Copilot's file conventions, so an existing Copilot library works unchanged:
62
+
63
+ ```text
64
+ my-agent-library/
65
+ ├── skills/<name>/SKILL.md # plus any supporting files
66
+ ├── instructions/<name>.instructions.md
67
+ ├── agents/<name>.agent.md
68
+ ├── prompts/<name>.prompt.md
69
+ ├── mcp/<name>.json # one MCP server definition per file
70
+ ├── resources/<name>.md # reference files, copied as written
71
+ ├── hooks/<name>.json # one Copilot CLI hook file per file
72
+ └── plugins/<plugin>/ # Claude Code plugin layout, expanded into the kinds above
73
+ ```
74
+
75
+ `INTENT.md`, `*.intent.md`, and hidden files are never distributed. A plugin's `skills/`, `agents/`, `commands/`, and `.mcp.json` are synced as skills, agents, prompts, and MCP servers; everything else in it (hooks, scripts, LSP servers) is reported as a loss. See [decision 0005](docs/decisions/0005-plugins-expand-into-kinds.md).
76
+
77
+ ## What each harness receives
78
+
79
+ | Profile | Skills | Instructions | Agents | Prompts | MCP servers | Resources | Hooks |
80
+ | --------- | --------- | ---------------------------- | -------------------- | -------------------- | ------------------------------ | ------------------------------------- | ----------------------- |
81
+ | `claude` | `skills/` | `rules/<name>.md` (`paths`) | `agents/<name>.md` | `commands/<name>.md` | `~/.claude.json` `mcpServers` | `resources/` + `CLAUDE.md` `@` import | `settings.json` `hooks` |
82
+ | `copilot` | `skills/` | `instructions/` | `agents/` | — | `mcp-config.json` `mcpServers` | `resources/` | `hooks/` |
83
+ | `vscode` | — | `<name>.instructions.md` | `<name>.agent.md` | `<name>.prompt.md` | `User/mcp.json` `servers` | — | — |
84
+ | `codex` | — | managed block in `AGENTS.md` | `agents/<name>.toml` | — | — | — | — |
85
+ | `agents` | `skills/` | — | — | — | — | — | — |
86
+ | `generic` | verbatim | verbatim | verbatim | verbatim | verbatim | verbatim | verbatim |
87
+
88
+ Run `skillsinc profiles` for the same table. See [harness profiles](docs/guides/harness-profiles.md) for exact conversions.
89
+
90
+ ## Commands
91
+
92
+ | Command | Purpose |
93
+ | -------------------- | -------------------------------------------------- |
94
+ | `skillsinc init` | Write a starter configuration |
95
+ | `skillsinc plan` | Show every change a sync would make; write nothing |
96
+ | `skillsinc sync` | Apply the plan |
97
+ | `skillsinc profiles` | List harness profiles and what each kind becomes |
98
+
99
+ `plan` and `sync` accept `--destination NAME` (repeatable), `--adopt`, `--json`, `--verbose`, and `--config PATH`. Exit codes: `0` success, `1` a destination was blocked or failed, `2` configuration or usage error, `130` interrupted.
100
+
101
+ ## Documentation
102
+
103
+ - [Configuration reference](docs/guides/configuration.md)
104
+ - [Command-line reference](docs/guides/command-line.md)
105
+ - [Scheduling](docs/guides/scheduling.md)
106
+ - [Development guide](docs/guides/development.md)
107
+ - [Roadmap](docs/planning/roadmap.md)
108
+ - [Harness profiles](docs/guides/harness-profiles.md)
109
+ - [Philosophy and goals](docs/architecture/philosophy.md)
110
+ - [Architecture](docs/architecture/overview.md)
111
+ - [Decision: rebuild scope](docs/decisions/0001-rebuild-scope.md)
112
+ - [Decision: MCP server entries](docs/decisions/0002-mcp-server-entries.md)
113
+ - [Decision: resources and Claude imports](docs/decisions/0003-resources-and-claude-imports.md)
114
+ - [Decision: TOML entries with tomlkit](docs/decisions/0004-toml-entries-with-tomlkit.md)
115
+ - [Decision: plugins expand into kinds](docs/decisions/0005-plugins-expand-into-kinds.md)
116
+ - [Decision: entry files beside a destination root](docs/decisions/0007-files-beside-the-root.md)
117
+ - [Decision: edit VS Code's JSONC mcp.json in place](docs/decisions/0008-jsonc-edits-in-place.md)
118
+ - [Decision: one copy of each item per harness](docs/decisions/0009-one-copy-per-harness.md)
119
+ - [Decision: MCP server options and per-profile overrides](docs/decisions/0010-mcp-server-options.md)
120
+ - [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md) · [Changelog](CHANGELOG.md)
121
+
122
+ ## License
123
+
124
+ [MIT](LICENSE)
@@ -0,0 +1,232 @@
1
+ [project]
2
+ name = "skillsinc"
3
+ version = "0.1.0"
4
+ description = "Sync one library of agent skills, instructions, agents, and prompts into every AI coding harness you use."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.12"
9
+ keywords = [
10
+ "agents",
11
+ "skills",
12
+ "claude-code",
13
+ "codex",
14
+ "copilot",
15
+ "sync",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Environment :: Console",
20
+ "Intended Audience :: Developers",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Topic :: Software Development",
27
+ "Typing :: Typed",
28
+ ]
29
+ dependencies = [
30
+ "pyyaml>=6.0.3",
31
+ "tomlkit>=0.13.3",
32
+ ]
33
+
34
+ [[project.authors]]
35
+ name = "Mike Hill"
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/mikejhill/skillsinc"
39
+ Issues = "https://github.com/mikejhill/skillsinc/issues"
40
+ Changelog = "https://github.com/mikejhill/skillsinc/blob/main/CHANGELOG.md"
41
+
42
+ [project.scripts]
43
+ skillsinc = "skillsinc.__main__:Application.main"
44
+
45
+ [build-system]
46
+ requires = ["uv_build>=0.11.32,<0.12.0"]
47
+ build-backend = "uv_build"
48
+
49
+ [dependency-groups]
50
+ dev = [
51
+ "hypothesis>=6.169.2",
52
+ "poethepoet>=0.48.0",
53
+ "pytest>=9.1.1",
54
+ "pytest-cov>=7.1.0",
55
+ "pytest-randomly>=5.0.0",
56
+ "ruff>=0.17.0",
57
+ "ty>=0.0.86",
58
+ "types-pyyaml>=6.0.12.20260906",
59
+ ]
60
+ mutation = ["mutmut>=3.8.0"]
61
+
62
+ [tool.ruff]
63
+ target-version = "py312"
64
+ line-length = 88
65
+ src = [
66
+ "src",
67
+ "tests",
68
+ ]
69
+
70
+ [tool.ruff.lint]
71
+ select = [
72
+ "A",
73
+ "ANN",
74
+ "ARG",
75
+ "B",
76
+ "BLE",
77
+ "C4",
78
+ "C90",
79
+ "D",
80
+ "DTZ",
81
+ "E",
82
+ "ERA",
83
+ "F",
84
+ "FA",
85
+ "FBT",
86
+ "G",
87
+ "I",
88
+ "LOG",
89
+ "N",
90
+ "PERF",
91
+ "PGH",
92
+ "PIE",
93
+ "PL",
94
+ "PT",
95
+ "PTH",
96
+ "RET",
97
+ "RSE",
98
+ "RUF",
99
+ "S",
100
+ "SIM",
101
+ "T20",
102
+ "TID",
103
+ "TRY",
104
+ "UP",
105
+ "W",
106
+ ]
107
+ ignore = [
108
+ "D107",
109
+ "TRY003",
110
+ ]
111
+
112
+ [tool.ruff.lint.per-file-ignores]
113
+ "tests/**" = [
114
+ "S101",
115
+ "PLR2004",
116
+ ]
117
+
118
+ [tool.ruff.lint.pydocstyle]
119
+ convention = "google"
120
+
121
+ [tool.ruff.lint.flake8-tidy-imports]
122
+ ban-relative-imports = "all"
123
+
124
+ [tool.ruff.lint.mccabe]
125
+ max-complexity = 10
126
+
127
+ [tool.ruff.format]
128
+ docstring-code-format = true
129
+
130
+ [tool.ty.rules]
131
+ all = "error"
132
+
133
+ [tool.pytest.ini_options]
134
+ testpaths = ["tests"]
135
+ addopts = [
136
+ "--strict-markers",
137
+ "--strict-config",
138
+ "-ra",
139
+ "--import-mode=importlib",
140
+ "-m",
141
+ "not perf",
142
+ ]
143
+ xfail_strict = true
144
+ markers = [
145
+ "unit: one module through its public API (the default layer)",
146
+ "integration: user journeys through Application.run in one process",
147
+ "e2e: the skillsinc process run against a throwaway home directory",
148
+ "perf: time budgets for planning and syncing large libraries",
149
+ ]
150
+
151
+ [tool.coverage.run]
152
+ source = ["skillsinc"]
153
+ branch = true
154
+
155
+ [tool.coverage.report]
156
+ fail_under = 98
157
+ show_missing = true
158
+ skip_covered = true
159
+ exclude_also = [
160
+ "if __name__ == .__main__.:",
161
+ 'assert_never\(',
162
+ ]
163
+
164
+ [tool.poe.tasks.format]
165
+ cmd = "ruff format ."
166
+ help = "Format code"
167
+
168
+ [tool.poe.tasks.format-check]
169
+ cmd = "ruff format --check ."
170
+ help = "Check formatting"
171
+
172
+ [tool.poe.tasks.lint]
173
+ cmd = "ruff check ."
174
+ help = "Lint code"
175
+
176
+ [tool.poe.tasks.lint-fix]
177
+ cmd = "ruff check . --fix"
178
+ help = "Lint and auto-fix"
179
+
180
+ [tool.poe.tasks.typecheck]
181
+ cmd = "ty check"
182
+ help = "Type check (strict)"
183
+
184
+ [tool.poe.tasks.test]
185
+ cmd = "pytest --cov"
186
+ help = "Run unit, property, integration, and e2e tests with coverage"
187
+
188
+ [tool.poe.tasks.e2e]
189
+ cmd = "pytest -m e2e"
190
+ help = "Run the skillsinc process against a throwaway home"
191
+
192
+ [tool.poe.tasks.perf]
193
+ cmd = "pytest -m perf --durations=0 -p no:randomly"
194
+ help = "Run the performance budgets"
195
+
196
+ [tool.poe.tasks.mutate]
197
+ shell = "uv run --group mutation mutmut run && uv run --group mutation mutmut results --all true > mutation-results.txt && uv run python scripts/mutation_report.py mutation-results.txt"
198
+ help = "Mutation testing (POSIX only; slow)"
199
+
200
+ [tool.poe.tasks.docs-lint]
201
+ cmd = "npx --yes markdownlint-cli2"
202
+ help = "Lint Markdown documentation"
203
+
204
+ [tool.poe.tasks.fix]
205
+ sequence = [
206
+ "format",
207
+ "lint-fix",
208
+ ]
209
+ help = "Auto-fix formatting and lint"
210
+
211
+ [tool.poe.tasks.check]
212
+ sequence = [
213
+ "format-check",
214
+ "lint",
215
+ "typecheck",
216
+ "test",
217
+ ]
218
+ help = "Run every Python quality gate"
219
+
220
+ [tool.mutmut]
221
+ source_paths = ["src/skillsinc/"]
222
+ pytest_add_cli_args_test_selection = ["tests/"]
223
+ pytest_add_cli_args = [
224
+ "-p",
225
+ "no:randomly",
226
+ "-p",
227
+ "no:cacheprovider",
228
+ "-m",
229
+ "not e2e and not perf",
230
+ ]
231
+ mutate_only_covered_lines = true
232
+ also_copy = ["examples/"]
@@ -0,0 +1,140 @@
1
+ [project]
2
+ name = "skillsinc"
3
+ version = "0.1.0"
4
+ description = "Sync one library of agent skills, instructions, agents, and prompts into every AI coding harness you use."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Mike Hill" }]
9
+ requires-python = ">=3.12"
10
+ keywords = ["agents", "skills", "claude-code", "codex", "copilot", "sync"]
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Environment :: Console",
14
+ "Intended Audience :: Developers",
15
+ "Operating System :: OS Independent",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Programming Language :: Python :: 3.14",
20
+ "Topic :: Software Development",
21
+ "Typing :: Typed",
22
+ ]
23
+ dependencies = [
24
+ "pyyaml>=6.0.3",
25
+ "tomlkit>=0.13.3",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/mikejhill/skillsinc"
30
+ Issues = "https://github.com/mikejhill/skillsinc/issues"
31
+ Changelog = "https://github.com/mikejhill/skillsinc/blob/main/CHANGELOG.md"
32
+
33
+ [project.scripts]
34
+ skillsinc = "skillsinc.__main__:Application.main"
35
+
36
+ [build-system]
37
+ requires = ["uv_build>=0.11.32,<0.12.0"]
38
+ build-backend = "uv_build"
39
+
40
+ [dependency-groups]
41
+ dev = [
42
+ "hypothesis>=6.169.2",
43
+ "poethepoet>=0.48.0",
44
+ "pytest>=9.1.1",
45
+ "pytest-cov>=7.1.0",
46
+ "pytest-randomly>=5.0.0",
47
+ "ruff>=0.17.0",
48
+ "ty>=0.0.86",
49
+ "types-pyyaml>=6.0.12.20260906",
50
+ ]
51
+ mutation = [
52
+ "mutmut>=3.8.0",
53
+ ]
54
+
55
+ [tool.ruff]
56
+ target-version = "py312"
57
+ line-length = 88
58
+ src = ["src", "tests"]
59
+
60
+ [tool.ruff.lint]
61
+ select = [
62
+ "A", "ANN", "ARG", "B", "BLE", "C4", "C90", "D", "DTZ", "E", "ERA", "F",
63
+ "FA", "FBT", "G", "I", "LOG", "N", "PERF", "PGH", "PIE", "PL", "PT", "PTH",
64
+ "RET", "RSE", "RUF", "S", "SIM", "T20", "TID", "TRY", "UP", "W",
65
+ ]
66
+ ignore = [
67
+ "D107", # __init__ docstring: the class docstring covers it
68
+ "TRY003", # long messages in raise: context-rich messages are required here
69
+ ]
70
+
71
+ [tool.ruff.lint.per-file-ignores]
72
+ "tests/**" = [
73
+ "S101", # assert is how pytest works
74
+ "PLR2004", # literal expected values are clearer in tests
75
+ ]
76
+
77
+ [tool.ruff.lint.pydocstyle]
78
+ convention = "google"
79
+
80
+ [tool.ruff.lint.flake8-tidy-imports]
81
+ ban-relative-imports = "all"
82
+
83
+ [tool.ruff.lint.mccabe]
84
+ max-complexity = 10
85
+
86
+ [tool.ruff.format]
87
+ docstring-code-format = true
88
+
89
+ [tool.ty.rules]
90
+ all = "error"
91
+
92
+ [tool.pytest.ini_options]
93
+ testpaths = ["tests"]
94
+ addopts = [
95
+ "--strict-markers", "--strict-config", "-ra", "--import-mode=importlib",
96
+ # Performance budgets run in their own job: `poe perf`
97
+ "-m", "not perf",
98
+ ]
99
+ xfail_strict = true
100
+ markers = [
101
+ "unit: one module through its public API (the default layer)",
102
+ "integration: user journeys through Application.run in one process",
103
+ "e2e: the skillsinc process run against a throwaway home directory",
104
+ "perf: time budgets for planning and syncing large libraries",
105
+ ]
106
+
107
+ [tool.coverage.run]
108
+ source = ["skillsinc"]
109
+ branch = true
110
+
111
+ [tool.coverage.report]
112
+ fail_under = 98
113
+ show_missing = true
114
+ skip_covered = true
115
+ exclude_also = ['if __name__ == .__main__.:', 'assert_never\(']
116
+
117
+ [tool.poe.tasks]
118
+ format = { cmd = "ruff format .", help = "Format code" }
119
+ format-check = { cmd = "ruff format --check .", help = "Check formatting" }
120
+ lint = { cmd = "ruff check .", help = "Lint code" }
121
+ lint-fix = { cmd = "ruff check . --fix", help = "Lint and auto-fix" }
122
+ typecheck = { cmd = "ty check", help = "Type check (strict)" }
123
+ test = { cmd = "pytest --cov", help = "Run unit, property, integration, and e2e tests with coverage" }
124
+ e2e = { cmd = "pytest -m e2e", help = "Run the skillsinc process against a throwaway home" }
125
+ perf = { cmd = "pytest -m perf --durations=0 -p no:randomly", help = "Run the performance budgets" }
126
+ mutate = { shell = "uv run --group mutation mutmut run && uv run --group mutation mutmut results --all true > mutation-results.txt && uv run python scripts/mutation_report.py mutation-results.txt", help = "Mutation testing (POSIX only; slow)" }
127
+ docs-lint = { cmd = "npx --yes markdownlint-cli2", help = "Lint Markdown documentation" }
128
+ fix = { sequence = ["format", "lint-fix"], help = "Auto-fix formatting and lint" }
129
+ check = { sequence = ["format-check", "lint", "typecheck", "test"], help = "Run every Python quality gate" }
130
+
131
+ [tool.mutmut]
132
+ # Mutation testing: change the code in small ways and check a test fails.
133
+ # POSIX only (it forks); run it on Linux, macOS, or WSL with `uv run poe mutate`.
134
+ source_paths = ["src/skillsinc/"]
135
+ pytest_add_cli_args_test_selection = ["tests/"]
136
+ # Process tests and timing budgets run the installed code, not the mutant
137
+ pytest_add_cli_args = ["-p", "no:randomly", "-p", "no:cacheprovider", "-m", "not e2e and not perf"]
138
+ mutate_only_covered_lines = true
139
+ # Files tests read beside the code
140
+ also_copy = ["examples/"]
@@ -0,0 +1,3 @@
1
+ """SkillSinc: sync one library of agent customizations into every AI harness."""
2
+
3
+ from __future__ import annotations