mdcompose 0.1.3__tar.gz → 0.2.1__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 (111) hide show
  1. mdcompose-0.2.1/.github/FUNDING.yml +1 -0
  2. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/ci.yml +25 -24
  3. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/supply-chain.yml +1 -1
  4. {mdcompose-0.1.3 → mdcompose-0.2.1}/CHANGELOG.md +12 -0
  5. {mdcompose-0.1.3 → mdcompose-0.2.1}/PKG-INFO +10 -10
  6. {mdcompose-0.1.3 → mdcompose-0.2.1}/README.md +9 -9
  7. {mdcompose-0.1.3 → mdcompose-0.2.1}/TODO.md +111 -219
  8. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/concepts.md +27 -6
  9. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/core-contract.md +68 -3
  10. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/cli.py +2 -0
  11. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/init_cmd.py +67 -0
  12. mdcompose-0.2.1/mdcompose/commands/skill_cmd.py +313 -0
  13. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/config.py +33 -1
  14. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/init_ops.py +218 -19
  15. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/managed_block.py +3 -0
  16. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/manifest.py +76 -4
  17. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/platform.py +2 -3
  18. mdcompose-0.2.1/mdcompose/core/skill_composition.py +81 -0
  19. mdcompose-0.2.1/mdcompose/core/skill_library_ops.py +180 -0
  20. mdcompose-0.2.1/mdcompose/core/skills.py +290 -0
  21. {mdcompose-0.1.3 → mdcompose-0.2.1}/pyproject.toml +1 -1
  22. mdcompose-0.2.1/tests/fixtures/mdcompose.lock.schema1.json +28 -0
  23. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_config.py +33 -0
  24. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_config_cmd.py +25 -0
  25. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_init.py +129 -0
  26. mdcompose-0.2.1/tests/test_init_ops.py +673 -0
  27. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_managed_block.py +21 -0
  28. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_manifest.py +147 -0
  29. mdcompose-0.2.1/tests/test_skill_commands.py +483 -0
  30. mdcompose-0.2.1/tests/test_skill_composition.py +85 -0
  31. mdcompose-0.2.1/tests/test_skills.py +242 -0
  32. {mdcompose-0.1.3 → mdcompose-0.2.1}/uv.lock +258 -258
  33. mdcompose-0.1.3/tests/test_init_ops.py +0 -299
  34. {mdcompose-0.1.3 → mdcompose-0.2.1}/.gitattributes +0 -0
  35. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  36. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  37. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  38. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  39. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/bump.yml +0 -0
  40. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/codeql.yml +0 -0
  41. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/dependency-review.yml +0 -0
  42. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/mutation.yml +0 -0
  43. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/python-eol.yml +0 -0
  44. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/release.yml +0 -0
  45. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/workflows/scorecard.yml +0 -0
  46. {mdcompose-0.1.3 → mdcompose-0.2.1}/.github/zizmor.yml +0 -0
  47. {mdcompose-0.1.3 → mdcompose-0.2.1}/.gitignore +0 -0
  48. {mdcompose-0.1.3 → mdcompose-0.2.1}/.pre-commit-config.yaml +0 -0
  49. {mdcompose-0.1.3 → mdcompose-0.2.1}/CODE_OF_CONDUCT.md +0 -0
  50. {mdcompose-0.1.3 → mdcompose-0.2.1}/CONTRIBUTING.md +0 -0
  51. {mdcompose-0.1.3 → mdcompose-0.2.1}/LICENSE +0 -0
  52. {mdcompose-0.1.3 → mdcompose-0.2.1}/SECURITY.md +0 -0
  53. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/benchmarks.md +0 -0
  54. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/commit-and-release-tooling.md +0 -0
  55. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/hardening-review.md +0 -0
  56. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/optional-tooling.md +0 -0
  57. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/publishing.md +0 -0
  58. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/scorecard.md +0 -0
  59. {mdcompose-0.1.3 → mdcompose-0.2.1}/docs/versioning-explained.md +0 -0
  60. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/__init__.py +0 -0
  61. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/__init__.py +0 -0
  62. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/config_cmd.py +0 -0
  63. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/convert_cmd.py +0 -0
  64. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/eject_cmd.py +0 -0
  65. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/import_cmd.py +0 -0
  66. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/snippet_cmd.py +0 -0
  67. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/commands/target_cmd.py +0 -0
  68. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/__init__.py +0 -0
  69. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/composition.py +0 -0
  70. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/convert_ops.py +0 -0
  71. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/eject.py +0 -0
  72. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/exit_codes.py +0 -0
  73. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/files.py +0 -0
  74. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/import_ops.py +0 -0
  75. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/library_ops.py +0 -0
  76. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/output.py +0 -0
  77. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/report.py +0 -0
  78. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/sections.py +0 -0
  79. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/snippets.py +0 -0
  80. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/core/targets.py +0 -0
  81. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/prompts.py +0 -0
  82. {mdcompose-0.1.3 → mdcompose-0.2.1}/mdcompose/version.py +0 -0
  83. {mdcompose-0.1.3 → mdcompose-0.2.1}/renovate.json +0 -0
  84. {mdcompose-0.1.3 → mdcompose-0.2.1}/scripts/check_ascii.py +0 -0
  85. {mdcompose-0.1.3 → mdcompose-0.2.1}/scripts/check_licenses.py +0 -0
  86. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/benchmarks/conftest.py +0 -0
  87. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/benchmarks/test_core_ops.py +0 -0
  88. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/conftest.py +0 -0
  89. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/fixtures/plain.bom.md +0 -0
  90. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/fixtures/plain.crlf.md +0 -0
  91. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/fixtures/plain.lf.md +0 -0
  92. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/fixtures/prose.cp1252.md +0 -0
  93. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_cli.py +0 -0
  94. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_convert.py +0 -0
  95. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_doctor_drift.py +0 -0
  96. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_e2e_import_convert.py +0 -0
  97. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_eject.py +0 -0
  98. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_files.py +0 -0
  99. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_fuzz.py +0 -0
  100. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_import_cmd.py +0 -0
  101. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_import_ops.py +0 -0
  102. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_layering.py +0 -0
  103. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_onedrive.py +0 -0
  104. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_output.py +0 -0
  105. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_platform.py +0 -0
  106. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_prompts.py +0 -0
  107. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_report.py +0 -0
  108. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_sections.py +0 -0
  109. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_snippet_commands.py +0 -0
  110. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_snippets.py +0 -0
  111. {mdcompose-0.1.3 → mdcompose-0.2.1}/tests/test_targets.py +0 -0
@@ -0,0 +1 @@
1
+ ko_fi: rovetown
@@ -292,27 +292,28 @@ jobs:
292
292
  esac
293
293
  done
294
294
 
295
- # DORMANT, repo-gated. The suite (tests/benchmarks) and the `benchmark`
296
- # dependency group both exist; what is missing is a CodSpeed project, which
297
- # needs the GitHub repo. CodSpeed runs the benchmarks instrumented rather than
298
- # wall-clock, so the numbers are stable across runners, and it posts the delta
299
- # as a pull request check rather than failing hard. Free for open source. To
300
- # enable: connect the repo at codspeed.io, uncomment this job, and leave it
301
- # out of the all-green needs list (benchmarks never block a merge).
302
- #
303
- # benchmarks:
304
- # name: benchmarks
305
- # runs-on: ubuntu-latest
306
- # timeout-minutes: 20
307
- # steps:
308
- # - uses: actions/checkout@v4
309
- # with:
310
- # persist-credentials: false
311
- # - uses: astral-sh/setup-uv@v5
312
- # with:
313
- # enable-cache: true
314
- # cache-dependency-glob: uv.lock
315
- # - run: uv sync --locked --group benchmark
316
- # - uses: CodSpeedHQ/action@v3
317
- # with:
318
- # run: uv run --no-sync pytest tests/benchmarks --codspeed
295
+ # CodSpeed runs the benchmarks instrumented rather than wall-clock, so the
296
+ # numbers are stable across runners, and it posts the delta as a pull request
297
+ # check rather than failing hard. Free for open source. Not in the all-green
298
+ # needs list: benchmarks never block a merge. Needs the repo connected at
299
+ # codspeed.io once before its first run.
300
+ benchmarks:
301
+ name: benchmarks
302
+ runs-on: ubuntu-latest
303
+ timeout-minutes: 20
304
+ permissions:
305
+ contents: read
306
+ id-token: write # OpenID Connect authentication with CodSpeed
307
+ steps:
308
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
309
+ with:
310
+ persist-credentials: false
311
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
312
+ with:
313
+ enable-cache: true
314
+ cache-dependency-glob: uv.lock
315
+ - run: uv sync --locked --group benchmark
316
+ - uses: CodSpeedHQ/action@373d6868929f444bc08d901fd0eb0ad52a8875ea # v5.2.1
317
+ with:
318
+ run: uv run --no-sync pytest tests/benchmarks --codspeed
319
+ mode: "simulation"
@@ -85,7 +85,7 @@ jobs:
85
85
  with:
86
86
  persist-credentials: false
87
87
 
88
- - uses: google/osv-scanner-action/osv-scanner-action@6e4298ebc4db23e847df9b2e2de2939d6f066c67 # v2.5.1
88
+ - uses: google/osv-scanner-action/osv-scanner-action@a345acffa64b0eaede81a3d9aae6141214d9c8fc # v2.6.0
89
89
  with:
90
90
  scan-args: >-
91
91
  --lockfile=uv.lock
@@ -3,6 +3,18 @@
3
3
  All notable changes to mdcompose are recorded here.
4
4
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
5
 
6
+ ## v0.2.1 (2026-09-14)
7
+
8
+ ### Added
9
+
10
+ - add mdcompose skill command group
11
+
12
+ ## v0.2.0 (2026-09-14)
13
+
14
+ ### Added
15
+
16
+ - compose agent skills alongside AGENTS.md and CLAUDE.md
17
+
6
18
  ## v0.1.3 (2026-09-11)
7
19
 
8
20
  ## v0.1.2 (2026-09-11)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: mdcompose
3
- Version: 0.1.3
3
+ Version: 0.2.1
4
4
  Summary: Keep CLAUDE.md and AGENTS.md in sync and composed from a personal snippet library, without hand-editing every project
5
5
  Project-URL: Homepage, https://github.com/Rovetown/mdcompose
6
6
  Project-URL: Repository, https://github.com/Rovetown/mdcompose
@@ -40,15 +40,14 @@ Description-Content-Type: text/markdown
40
40
 
41
41
  <div align="center">
42
42
 
43
- [![PyPI](https://img.shields.io/pypi/v/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![Python](https://img.shields.io/pypi/pyversions/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![CI](https://img.shields.io/github/actions/workflow/status/Rovetown/mdcompose/ci.yml?branch=main&style=for-the-badge&label=CI)](https://github.com/Rovetown/mdcompose/actions/workflows/ci.yml) [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/Rovetown/mdcompose?style=for-the-badge&label=scorecard)](https://scorecard.dev/viewer/?uri=github.com/Rovetown/mdcompose) [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](https://github.com/Rovetown/mdcompose/blob/main/LICENSE) [![Downloads](https://img.shields.io/pypi/dm/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/)
43
+ [![PyPI](https://img.shields.io/pypi/v/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![Python](https://img.shields.io/pypi/pyversions/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![CI](https://img.shields.io/github/actions/workflow/status/Rovetown/mdcompose/ci.yml?branch=main&style=for-the-badge&label=CI)](https://github.com/Rovetown/mdcompose/actions/workflows/ci.yml) [![CodSpeed Badge](https://img.shields.io/endpoint?url=https://app.codspeed.io//badge.json&style=for-the-badge)](https://app.codspeed.io//Rovetown/mdcompose?utm_source=badge) [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/Rovetown/mdcompose?style=for-the-badge&label=scorecard)](https://scorecard.dev/viewer/?uri=github.com/Rovetown/mdcompose) [![OpenSSF Best Practices](https://img.shields.io/cii/summary/14614?style=for-the-badge&label=best%20practices)](https://www.bestpractices.dev/projects/14614) [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](https://github.com/Rovetown/mdcompose/blob/main/LICENSE) [![Downloads](https://img.shields.io/pypi/dm/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Y8Y31VUCGT)
44
44
 
45
45
  </div>
46
46
 
47
47
  Most repositories need the same handful of instructions for AI coding agents: how commits are written, which test command to run, which files not to touch.
48
48
  mdcompose keeps those as small snippets in one place and builds each project's `AGENTS.md` and `CLAUDE.md` from the ones you pick, so you stop copying the same paragraphs between repositories.
49
49
 
50
- > `mdcompose` composes Markdown.
51
- > It is unrelated to Docker Compose; the shared `-compose` suffix is a coincidence.
50
+ > `mdcompose` composes Markdown. It is unrelated to Docker Compose.
52
51
 
53
52
  ## Highlights
54
53
 
@@ -59,8 +58,7 @@ mdcompose keeps those as small snippets in one place and builds each project's `
59
58
  - **A committed lockfile.** `mdcompose.lock` embeds each snippet's content, so a clone or fork reproduces the same files with an empty library.
60
59
  - **Correct paths on Windows, WSL, and Linux**, including a warning when a managed file sits inside a OneDrive-synced folder.
61
60
  - **No install required.** `uvx mdcompose doctor` or `pipx run mdcompose doctor` run the real thing in a throwaway environment -- try it, or use it in a one-off script, without adding anything to your machine.
62
- - **Skills cost tokens too, and that's next (planned).** Every skill an agent does not need loaded for a project is context spent before it has done any work.
63
- A skill file -- frontmatter, a body, sometimes a script -- is already snippet-shaped, so curating which skills a project loads, the same way AGENTS.md and CLAUDE.md are curated today, is the natural next composition target: real token savings, not just tidiness.
61
+ - **Skills cost tokens too, so they're composed the same way.** A second, independent library curates which Claude Code Skills a project loads into `.claude/skills/`, so an agent stops paying context for skills a given project never needed.
64
62
  See [docs/concepts.md](https://github.com/Rovetown/mdcompose/blob/main/docs/concepts.md).
65
63
 
66
64
  It makes no network requests and collects no telemetry.
@@ -89,11 +87,9 @@ uvx mdcompose doctor
89
87
 
90
88
  The whole flow, start to finish:
91
89
 
92
- <!-- demo GIF: docs/assets/mdcompose-demo.gif -- not yet recorded, see TODO.md. Restore the <img> below once it exists. -->
93
-
94
90
  <div align="center">
95
91
 
96
- *(a short demo recording of `init` and `doctor` goes here -- not yet recorded)*
92
+ <img src="https://raw.githubusercontent.com/Rovetown/mdcompose/main/docs/assets/mdcompose-demo.gif" alt="mdcompose demo: init's interactive picker composing AGENTS.md and CLAUDE.md from selected snippets, then doctor confirming both are clean" width="700">
97
93
 
98
94
  </div>
99
95
 
@@ -149,6 +145,10 @@ mdcompose snippet list the snippets in your library
149
145
  mdcompose snippet edit <id> open one in your editor
150
146
  mdcompose snippet remove <id> delete one
151
147
  mdcompose snippet adopt save a project's embedded snippets to your library
148
+ mdcompose skill list the skills in your skill library
149
+ mdcompose skill edit <id> open one in your editor
150
+ mdcompose skill remove <id> delete one
151
+ mdcompose skill adopt save a project's embedded skills to your skill library
152
152
  mdcompose import <file> pull sections out of an existing CLAUDE.md or AGENTS.md
153
153
  mdcompose convert <src> <dst> move content between this project's AGENTS.md and CLAUDE.md
154
154
  mdcompose eject stop managing a directory: remove markers, delete the lock
@@ -220,7 +220,7 @@ A few projects cover the same idea of a personal snippet library composed per pr
220
220
  What mdcompose does that they do not: import-versus-copy tied to Claude Code's real `@import`; drift detection by hashing one owned block; a committed lock with embedded content so a fork works without the author's library; and real Windows, WSL, and mounted-drive path correctness.
221
221
  It deliberately does no format translation: a target receives Markdown, not Cursor rules or Copilot instructions.
222
222
 
223
- **None of them go past agent instructions -- mdcompose plans to.** A skill file is markdown plus optional scripts, same as a snippet; composing a curated skill selection per project the way AGENTS.md and CLAUDE.md are composed today means an agent stops paying context for skills a given project never needed loaded in the first place.
223
+ **None of them go past agent instructions -- mdcompose does.** A skill file is markdown plus frontmatter, same as a snippet; a curated skill selection is composed per project into `.claude/skills/` the same way AGENTS.md and CLAUDE.md are, so an agent stops paying context for skills a given project never needed loaded in the first place.
224
224
 
225
225
  See [docs/concepts.md](https://github.com/Rovetown/mdcompose/blob/main/docs/concepts.md) for the fuller case for each point.
226
226
 
@@ -10,15 +10,14 @@
10
10
 
11
11
  <div align="center">
12
12
 
13
- [![PyPI](https://img.shields.io/pypi/v/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![Python](https://img.shields.io/pypi/pyversions/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![CI](https://img.shields.io/github/actions/workflow/status/Rovetown/mdcompose/ci.yml?branch=main&style=for-the-badge&label=CI)](https://github.com/Rovetown/mdcompose/actions/workflows/ci.yml) [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/Rovetown/mdcompose?style=for-the-badge&label=scorecard)](https://scorecard.dev/viewer/?uri=github.com/Rovetown/mdcompose) [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](https://github.com/Rovetown/mdcompose/blob/main/LICENSE) [![Downloads](https://img.shields.io/pypi/dm/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/)
13
+ [![PyPI](https://img.shields.io/pypi/v/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![Python](https://img.shields.io/pypi/pyversions/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![CI](https://img.shields.io/github/actions/workflow/status/Rovetown/mdcompose/ci.yml?branch=main&style=for-the-badge&label=CI)](https://github.com/Rovetown/mdcompose/actions/workflows/ci.yml) [![CodSpeed Badge](https://img.shields.io/endpoint?url=https://app.codspeed.io//badge.json&style=for-the-badge)](https://app.codspeed.io//Rovetown/mdcompose?utm_source=badge) [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/Rovetown/mdcompose?style=for-the-badge&label=scorecard)](https://scorecard.dev/viewer/?uri=github.com/Rovetown/mdcompose) [![OpenSSF Best Practices](https://img.shields.io/cii/summary/14614?style=for-the-badge&label=best%20practices)](https://www.bestpractices.dev/projects/14614) [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](https://github.com/Rovetown/mdcompose/blob/main/LICENSE) [![Downloads](https://img.shields.io/pypi/dm/mdcompose?style=for-the-badge)](https://pypi.org/project/mdcompose/) [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Y8Y31VUCGT)
14
14
 
15
15
  </div>
16
16
 
17
17
  Most repositories need the same handful of instructions for AI coding agents: how commits are written, which test command to run, which files not to touch.
18
18
  mdcompose keeps those as small snippets in one place and builds each project's `AGENTS.md` and `CLAUDE.md` from the ones you pick, so you stop copying the same paragraphs between repositories.
19
19
 
20
- > `mdcompose` composes Markdown.
21
- > It is unrelated to Docker Compose; the shared `-compose` suffix is a coincidence.
20
+ > `mdcompose` composes Markdown. It is unrelated to Docker Compose.
22
21
 
23
22
  ## Highlights
24
23
 
@@ -29,8 +28,7 @@ mdcompose keeps those as small snippets in one place and builds each project's `
29
28
  - **A committed lockfile.** `mdcompose.lock` embeds each snippet's content, so a clone or fork reproduces the same files with an empty library.
30
29
  - **Correct paths on Windows, WSL, and Linux**, including a warning when a managed file sits inside a OneDrive-synced folder.
31
30
  - **No install required.** `uvx mdcompose doctor` or `pipx run mdcompose doctor` run the real thing in a throwaway environment -- try it, or use it in a one-off script, without adding anything to your machine.
32
- - **Skills cost tokens too, and that's next (planned).** Every skill an agent does not need loaded for a project is context spent before it has done any work.
33
- A skill file -- frontmatter, a body, sometimes a script -- is already snippet-shaped, so curating which skills a project loads, the same way AGENTS.md and CLAUDE.md are curated today, is the natural next composition target: real token savings, not just tidiness.
31
+ - **Skills cost tokens too, so they're composed the same way.** A second, independent library curates which Claude Code Skills a project loads into `.claude/skills/`, so an agent stops paying context for skills a given project never needed.
34
32
  See [docs/concepts.md](https://github.com/Rovetown/mdcompose/blob/main/docs/concepts.md).
35
33
 
36
34
  It makes no network requests and collects no telemetry.
@@ -59,11 +57,9 @@ uvx mdcompose doctor
59
57
 
60
58
  The whole flow, start to finish:
61
59
 
62
- <!-- demo GIF: docs/assets/mdcompose-demo.gif -- not yet recorded, see TODO.md. Restore the <img> below once it exists. -->
63
-
64
60
  <div align="center">
65
61
 
66
- *(a short demo recording of `init` and `doctor` goes here -- not yet recorded)*
62
+ <img src="https://raw.githubusercontent.com/Rovetown/mdcompose/main/docs/assets/mdcompose-demo.gif" alt="mdcompose demo: init's interactive picker composing AGENTS.md and CLAUDE.md from selected snippets, then doctor confirming both are clean" width="700">
67
63
 
68
64
  </div>
69
65
 
@@ -119,6 +115,10 @@ mdcompose snippet list the snippets in your library
119
115
  mdcompose snippet edit <id> open one in your editor
120
116
  mdcompose snippet remove <id> delete one
121
117
  mdcompose snippet adopt save a project's embedded snippets to your library
118
+ mdcompose skill list the skills in your skill library
119
+ mdcompose skill edit <id> open one in your editor
120
+ mdcompose skill remove <id> delete one
121
+ mdcompose skill adopt save a project's embedded skills to your skill library
122
122
  mdcompose import <file> pull sections out of an existing CLAUDE.md or AGENTS.md
123
123
  mdcompose convert <src> <dst> move content between this project's AGENTS.md and CLAUDE.md
124
124
  mdcompose eject stop managing a directory: remove markers, delete the lock
@@ -190,7 +190,7 @@ A few projects cover the same idea of a personal snippet library composed per pr
190
190
  What mdcompose does that they do not: import-versus-copy tied to Claude Code's real `@import`; drift detection by hashing one owned block; a committed lock with embedded content so a fork works without the author's library; and real Windows, WSL, and mounted-drive path correctness.
191
191
  It deliberately does no format translation: a target receives Markdown, not Cursor rules or Copilot instructions.
192
192
 
193
- **None of them go past agent instructions -- mdcompose plans to.** A skill file is markdown plus optional scripts, same as a snippet; composing a curated skill selection per project the way AGENTS.md and CLAUDE.md are composed today means an agent stops paying context for skills a given project never needed loaded in the first place.
193
+ **None of them go past agent instructions -- mdcompose does.** A skill file is markdown plus frontmatter, same as a snippet; a curated skill selection is composed per project into `.claude/skills/` the same way AGENTS.md and CLAUDE.md are, so an agent stops paying context for skills a given project never needed loaded in the first place.
194
194
 
195
195
  See [docs/concepts.md](https://github.com/Rovetown/mdcompose/blob/main/docs/concepts.md) for the fuller case for each point.
196
196