mkforge 0.1.0__tar.gz → 0.2.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 (119) hide show
  1. mkforge-0.2.0/.github/workflows/ci.yml +35 -0
  2. mkforge-0.2.0/.gitlab-ci.yml +41 -0
  3. mkforge-0.2.0/AGENTS.md +196 -0
  4. mkforge-0.2.0/CLAUDE.md +195 -0
  5. mkforge-0.2.0/Makefile +45 -0
  6. {mkforge-0.1.0 → mkforge-0.2.0}/PKG-INFO +21 -6
  7. {mkforge-0.1.0 → mkforge-0.2.0}/README.md +20 -5
  8. {mkforge-0.1.0 → mkforge-0.2.0}/docs/API_REFERENCE.md +804 -55
  9. mkforge-0.2.0/docs/USER_GUIDE.md +1270 -0
  10. {mkforge-0.1.0 → mkforge-0.2.0}/pyproject.toml +8 -13
  11. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/__init__.py +4 -0
  12. mkforge-0.2.0/src/mkforge/slugify.py +44 -0
  13. mkforge-0.2.0/tests/__init__.py +1 -0
  14. mkforge-0.2.0/tests/conftest.py +1 -0
  15. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_markdown_validation.py +10 -2
  16. mkforge-0.2.0/tests/test_slugify.py +71 -0
  17. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_validation.py +6 -2
  18. {mkforge-0.1.0 → mkforge-0.2.0}/uv.lock +212 -80
  19. mkforge-0.2.0/work/.gitkeep +0 -0
  20. mkforge-0.1.0/.github/workflows/ci.yml +0 -26
  21. mkforge-0.1.0/.gitlab-ci.yml +0 -55
  22. mkforge-0.1.0/AGENTS.md +0 -120
  23. mkforge-0.1.0/CLAUDE.md +0 -121
  24. mkforge-0.1.0/Makefile +0 -57
  25. mkforge-0.1.0/docs/USER_GUIDE.md +0 -1053
  26. mkforge-0.1.0/scripts/__init__.py +0 -1
  27. mkforge-0.1.0/scripts/check.sh +0 -120
  28. mkforge-0.1.0/scripts/check_docstrings.py +0 -129
  29. mkforge-0.1.0/scripts/code_metrics.py +0 -397
  30. mkforge-0.1.0/scripts/publish.sh +0 -31
  31. mkforge-0.1.0/scripts/security_deps.sh +0 -13
  32. mkforge-0.1.0/tests/__init__.py +0 -1
  33. mkforge-0.1.0/work/.gitkeep +0 -1
  34. {mkforge-0.1.0 → mkforge-0.2.0}/.github/workflows/publish.yml +0 -0
  35. {mkforge-0.1.0 → mkforge-0.2.0}/.gitignore +0 -0
  36. {mkforge-0.1.0 → mkforge-0.2.0}/.mkforge +0 -0
  37. {mkforge-0.1.0 → mkforge-0.2.0}/.python-version +0 -0
  38. {mkforge-0.1.0 → mkforge-0.2.0}/LICENSE +0 -0
  39. {mkforge-0.1.0 → mkforge-0.2.0}/demo_report.py +0 -0
  40. {mkforge-0.1.0 → mkforge-0.2.0}/demo_validation.py +0 -0
  41. {mkforge-0.1.0 → mkforge-0.2.0}/demo_verif.py +0 -0
  42. {mkforge-0.1.0 → mkforge-0.2.0}/doc/adr-001-markdown-conformance-verifier.md +0 -0
  43. {mkforge-0.1.0 → mkforge-0.2.0}/docs/MARKDOWN_RULES.md +0 -0
  44. {mkforge-0.1.0 → mkforge-0.2.0}/docs/SDD.md +0 -0
  45. {mkforge-0.1.0 → mkforge-0.2.0}/docs/SRS.md +0 -0
  46. {mkforge-0.1.0 → mkforge-0.2.0}/docs/adr/ADR-001-asset-management.md +0 -0
  47. {mkforge-0.1.0 → mkforge-0.2.0}/docs/adr/ADR-002-markdown-validation-contracts.md +0 -0
  48. {mkforge-0.1.0 → mkforge-0.2.0}/docs/pypi-publication.md +0 -0
  49. {mkforge-0.1.0 → mkforge-0.2.0}/main.py +0 -0
  50. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/_metadata.py +0 -0
  51. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/assets.py +0 -0
  52. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/__init__.py +0 -0
  53. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/_base.py +0 -0
  54. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/code.py +0 -0
  55. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/image.py +0 -0
  56. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/lists.py +0 -0
  57. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/misc.py +0 -0
  58. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/paragraph.py +0 -0
  59. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/table.py +0 -0
  60. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/content/text.py +0 -0
  61. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/document.py +0 -0
  62. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/errors.py +0 -0
  63. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/input_checks.py +0 -0
  64. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/py.typed +0 -0
  65. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/rendering.py +0 -0
  66. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/validation/__init__.py +0 -0
  67. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/validation/markdown_contracts.py +0 -0
  68. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/__init__.py +0 -0
  69. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/api.py +0 -0
  70. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/diagnostic_pattern.py +0 -0
  71. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/policy.py +0 -0
  72. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/registry.py +0 -0
  73. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/__init__.py +0 -0
  74. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/gfm/__init__.py +0 -0
  75. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/gfm/gfm001_table_delimiter.py +0 -0
  76. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/gfm/gfm002_table_column_count.py +0 -0
  77. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/gfm/gfm003_task_list_marker.py +0 -0
  78. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/__init__.py +0 -0
  79. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/_shared.py +0 -0
  80. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/markdownlint_remaining.py +0 -0
  81. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md001_heading_increment.py +0 -0
  82. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md002_first_heading_level.py +0 -0
  83. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md003_heading_style.py +0 -0
  84. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md004_unordered_list_style.py +0 -0
  85. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md005_md006_md007_list_indentation.py +0 -0
  86. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md009_trailing_spaces.py +0 -0
  87. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md010_hard_tabs.py +0 -0
  88. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md011_reversed_link_syntax.py +0 -0
  89. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md012_multiple_blank_lines.py +0 -0
  90. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md013_line_length.py +0 -0
  91. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md014_command_prompt.py +0 -0
  92. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md018_atx_heading_space.py +0 -0
  93. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md019_md021_atx_closed_spaces.py +0 -0
  94. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md020_closed_atx_heading_space.py +0 -0
  95. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md022_md023_heading_blanks.py +0 -0
  96. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md024_md025_duplicate_headings.py +0 -0
  97. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md026_heading_punctuation.py +0 -0
  98. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md027_md028_blockquote.py +0 -0
  99. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md029_md030_list_prefix.py +0 -0
  100. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md031_md032_fence_list_blanks.py +0 -0
  101. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md033_inline_html.py +0 -0
  102. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md034_bare_url.py +0 -0
  103. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md035_horizontal_rule.py +0 -0
  104. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md036_emphasis_heading.py +0 -0
  105. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md037_emphasis_marker_space.py +0 -0
  106. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md038_code_span_space.py +0 -0
  107. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md039_link_text_space.py +0 -0
  108. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/md040_md041_md046_md047_blocks.py +0 -0
  109. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/rules/markdown/mkf001_local_resource_exists.py +0 -0
  110. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/settings.py +0 -0
  111. {mkforge-0.1.0 → mkforge-0.2.0}/src/mkforge/verification/source_scan.py +0 -0
  112. {mkforge-0.1.0 → mkforge-0.2.0}/tests/expectations.py +0 -0
  113. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_assets.py +0 -0
  114. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_e2e.py +0 -0
  115. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_e2e_verification.py +0 -0
  116. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_helpers.py +0 -0
  117. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_markdown_verification.py +0 -0
  118. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_metadata.py +0 -0
  119. {mkforge-0.1.0 → mkforge-0.2.0}/tests/test_report_generation.py +0 -0
@@ -0,0 +1,35 @@
1
+ # Generated by yggtools — do not remove this line.
2
+ name: CI
3
+
4
+ on:
5
+ push:
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ quality:
14
+ name: Quality (Python ${{ matrix.python-version }})
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ python-version: ["3.12", "3.13"]
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: astral-sh/setup-uv@v5
23
+ with:
24
+ enable-cache: true
25
+ - run: uv python install ${{ matrix.python-version }}
26
+ - run: uv sync --python ${{ matrix.python-version }}
27
+ - name: Quality pipeline
28
+ run: PYTHONPATH=src uv run python -m yggtools.cli pipeline
29
+ - name: Upload quality reports
30
+ if: always()
31
+ uses: actions/upload-artifact@v4
32
+ with:
33
+ name: quality-py${{ matrix.python-version }}
34
+ path: work/reports/
35
+ if-no-files-found: ignore
@@ -0,0 +1,41 @@
1
+ # Generated by yggtools — do not remove this line.
2
+ variables:
3
+ UV_CACHE_DIR: "$CI_PROJECT_DIR/.uv-cache"
4
+
5
+ cache:
6
+ key: "$CI_COMMIT_REF_SLUG"
7
+ paths:
8
+ - .uv-cache/
9
+ - .venv/
10
+
11
+ stages:
12
+ - quality
13
+
14
+ .base:
15
+ before_script:
16
+ - pip install uv --quiet
17
+ - uv sync
18
+
19
+ "quality:3.12":
20
+ extends: .base
21
+ stage: quality
22
+ image: python:3.12-slim
23
+ script:
24
+ - PYTHONPATH=src uv run python -m yggtools.cli pipeline
25
+ artifacts:
26
+ when: always
27
+ paths:
28
+ - work/reports/
29
+ expire_in: 7 days
30
+
31
+ "quality:3.13":
32
+ extends: .base
33
+ stage: quality
34
+ image: python:3.13-slim
35
+ script:
36
+ - PYTHONPATH=src uv run python -m yggtools.cli pipeline
37
+ artifacts:
38
+ when: always
39
+ paths:
40
+ - work/reports/
41
+ expire_in: 7 days
@@ -0,0 +1,196 @@
1
+ # AI Agent Instructions
2
+
3
+ These instructions apply to all AI coding agents (ChatGPT, GitHub Copilot,
4
+ and other LLM-based tools) working on this repository.
5
+
6
+ ## Coding Standards
7
+
8
+ - Strictly follow Python PEP rules and the Google Python Style Guide for all
9
+ Python code.
10
+ - Keep each function's cyclomatic complexity at or below 10.
11
+ - Keep Python modules below 500 lines unless an ADR explicitly justifies a
12
+ larger module.
13
+ - Do not split a module purely to reduce its line count or cyclomatic
14
+ complexity. A split is justified only when the resulting modules have
15
+ genuinely independent reasons to change.
16
+ - Write Google-style docstrings for every function and class, including private
17
+ functions and classes.
18
+ - Write clean, auditable code with simple control flow.
19
+ - Favor clarity over cleverness.
20
+ - Use precise names for modules, classes, functions, variables, and tests.
21
+ - Keep comments rare and useful.
22
+ - Apply SOLID principles strictly:
23
+ - Single Responsibility: each module, class, and function must have one
24
+ clear reason to change.
25
+ - Open/Closed: add behavior through new focused implementations, rules,
26
+ strategies, or registries instead of editing large conditional blocks.
27
+ - Liskov Substitution: implementations of a public protocol must remain
28
+ interchangeable.
29
+ - Interface Segregation: depend on narrow protocols or callables rather
30
+ than broad objects with unrelated responsibilities.
31
+ - Dependency Inversion: high-level workflows depend on stable interfaces,
32
+ not concrete low-level details.
33
+
34
+ ## Dependencies
35
+
36
+ - Minimize external dependencies.
37
+ - Prefer Python standard library packages.
38
+ - Do not add third-party dependencies unless there is a clear technical need
39
+ that cannot reasonably be met with the standard library.
40
+ - Explain the reason for any new dependency before adding it.
41
+
42
+ ## Implementation Guidance
43
+
44
+ - Start substantial feature work and architecture changes with an Architecture
45
+ Decision Record in `doc/` before implementing code.
46
+ - Keep changes focused on the requested behavior.
47
+ - Keep public interfaces small.
48
+ - Name modules, classes, functions, variables, and tests with business/domain
49
+ vocabulary first.
50
+ - Avoid global mutable state unless there is a clear reason.
51
+ - Prefer deterministic behavior and explicit inputs.
52
+ - Use design patterns deliberately:
53
+ - Strategy when behavior varies by profile, format, rule, or policy.
54
+ - Registry when behavior must be extended without modifying the engine.
55
+ - Adapter when exposing a simple callable or external API.
56
+ - Factory functions when object creation has validation or multiple variants.
57
+ - Write tests for new behavior.
58
+ - Maintain 100% test coverage.
59
+ - Test function docstrings must state the requirement being verified using the
60
+ prefix `Requirement:`.
61
+ - Every module, function, class, method, and test must include a strict
62
+ Google-style docstring, including private functions and classes.
63
+ - Function and method docstrings must include:
64
+ - a precise summary that explains the domain behavior;
65
+ - `Args:` for every parameter except `self` and `cls`;
66
+ - `Returns:` for every non-`None` return value;
67
+ - `Raises:` for every intentionally raised exception.
68
+ - Class docstrings must include `Attributes:` when instances expose public
69
+ attributes.
70
+
71
+ ## Project Structure
72
+
73
+ - Source code lives in `src/mkforge/`.
74
+ - Tests live in `tests/`.
75
+ - Temporary outputs (coverage, caches, build artifacts) go into `work/`.
76
+
77
+ ## Quality Checks
78
+
79
+ Before finishing code changes, run:
80
+
81
+ ```bash
82
+ make check
83
+ ```
84
+
85
+ Use `make ci` for non-mutating verification.
86
+
87
+ ---
88
+
89
+ ## Mode Architecte
90
+
91
+ Activate this mode by saying: "mode architecte".
92
+
93
+ ### Posture
94
+
95
+ - **Challenge first.** Before accepting any feature request, ask: Is this
96
+ feature necessary? What problem does it solve? Can an existing mechanism
97
+ handle it? If the request is vague, ask one targeted clarifying question
98
+ before doing anything else.
99
+ - **Incremental ADRs.** Propose one focused ADR per decision. Never bundle
100
+ unrelated decisions in one document.
101
+ - **Simplicity over cleverness.** Prefer fewer abstractions. A flat list of
102
+ steps beats a plugin framework when there are three plugins.
103
+ - **Injection over inheritance.** Pass dependencies explicitly. Never use
104
+ base-class coupling or hidden global state.
105
+ - **Design patterns deliberately.** Use Strategy when behavior varies by
106
+ policy. Use Registry when behavior must be extended without editing the
107
+ engine. Use Adapter to isolate I/O. Use Pipeline for ordered, independently
108
+ testable steps. Do not introduce a pattern for decoration.
109
+
110
+ ### Deliverables
111
+
112
+ When asked to design a feature, produce documents in this order:
113
+
114
+ 1. **SRS fragment** — list only the requirements that are new or changed. Use
115
+ `REQ-<CATEGORY>-<NN>` identifiers. Each requirement gets one sentence with
116
+ SHALL / SHOULD / MAY. Include acceptance criteria.
117
+ 2. **ADR** — one decision, one document. Sections: Context, Decision,
118
+ Consequences, Alternatives rejected. Store in `doc/ADR-NNN-slug.md`.
119
+ 3. **SDD section** — update the relevant section of `doc/SDD.md` to reflect
120
+ the design. Include: affected modules, public interfaces changed, data
121
+ flow, error handling, test strategy.
122
+
123
+ ### Constraints
124
+
125
+ - SOLID principles strictly applied.
126
+ - Each module, class, and function has one clear reason to change.
127
+ - High-level workflows depend on stable interfaces, not concrete low-level
128
+ details.
129
+ - No module exceeds 500 lines unless an ADR explicitly justifies it.
130
+ - No function has cyclomatic complexity above 10.
131
+ - Public interfaces are small and named with business/domain vocabulary.
132
+ - No global mutable state.
133
+
134
+ ---
135
+
136
+ ## Mode Codeur
137
+
138
+ Activate this mode by saying: "mode codeur".
139
+
140
+ ### Posture
141
+
142
+ - **Clarity over cleverness.** Write code a junior can read without
143
+ explanation.
144
+ - **PEP-compliant always.** Follow PEP 8, PEP 257 (Google style), PEP 484,
145
+ PEP 526. Run `make check` before declaring done.
146
+ - **100% check coverage.** Every code change must leave `make check` passing.
147
+ Fix ruff, flake8, mypy, bandit, and pytest failures before closing the task.
148
+ - **Defensive programming at boundaries only.** Validate at entry points (CLI
149
+ args, external API responses, file I/O). Trust internal code and framework
150
+ guarantees. Do not add redundant guards inside a function that already
151
+ received a validated value.
152
+ - **Exceptions with intent.** Raise only when the caller genuinely cannot
153
+ continue. Name exceptions with domain vocabulary. Never use bare `except:`.
154
+ Never swallow exceptions silently.
155
+ - **Prefer stdlib, then well-known packages.** Use `pathlib`, `dataclasses`,
156
+ `typing`, `importlib.resources`. Do not add a dependency that the stdlib can
157
+ handle.
158
+ - **Injection over inheritance.** Pass dependencies as arguments. Avoid global
159
+ state.
160
+
161
+ ### Coding Standards (Codeur)
162
+
163
+ - Google-style docstrings on every function, method, class — including private
164
+ ones.
165
+ - Function docstrings: summary + `Args:` + `Returns:` + `Raises:`.
166
+ - Class docstrings: summary + `Attributes:` when public attributes exist.
167
+ - Test docstrings use `Requirement:` prefix to state what is being verified.
168
+ - Names use business/domain vocabulary.
169
+ - Cyclomatic complexity <= 10 per function.
170
+ - Module size <= 500 lines (justified by ADR if exceeded).
171
+
172
+ ### Testing Strategy
173
+
174
+ For every code change, write:
175
+
176
+ 1. **Unit tests** — mock all I/O and subprocess calls. Test one function in
177
+ isolation. Cover the pass path, the fail path, and each `Raises:` clause.
178
+ 2. **Integration / end-to-end tests** — at least one test that exercises the
179
+ full workflow without mocking internal modules (only external calls like
180
+ `subprocess`).
181
+
182
+ Test naming: `test_<what>_<condition>`.
183
+
184
+ ### Quality Gate
185
+
186
+ Before reporting done, run:
187
+
188
+ ```bash
189
+ make check
190
+ ```
191
+
192
+ When fixing linter/type errors:
193
+ - `ruff` errors — fix the code, not `# noqa`.
194
+ - `mypy` errors — add proper type annotations; never use `# type: ignore`.
195
+ - `bandit` B404/B603/B607 on subprocess — use `# nosec BXXX` on the offending
196
+ line.
@@ -0,0 +1,195 @@
1
+ # Claude Code Instructions
2
+
3
+ These instructions apply to the whole repository.
4
+
5
+ ## Coding Standards
6
+
7
+ - Strictly follow Python PEP rules and the Google Python Style Guide for all
8
+ Python code.
9
+ - Keep each function's cyclomatic complexity at or below 10.
10
+ - Keep Python modules below 500 lines unless an ADR explicitly justifies a
11
+ larger module.
12
+ - Do not split a module purely to reduce its line count or cyclomatic
13
+ complexity. A split is justified only when the resulting modules have
14
+ genuinely independent reasons to change.
15
+ - Write Google-style docstrings for every function and class, including private
16
+ functions and classes.
17
+ - Write clean, auditable code with simple control flow.
18
+ - Favor clarity over cleverness.
19
+ - Use precise names for modules, classes, functions, variables, and tests.
20
+ - Keep comments rare and useful.
21
+ - Apply SOLID principles strictly:
22
+ - Single Responsibility: each module, class, and function must have one
23
+ clear reason to change.
24
+ - Open/Closed: add behavior through new focused implementations, rules,
25
+ strategies, or registries instead of editing large conditional blocks.
26
+ - Liskov Substitution: implementations of a public protocol must remain
27
+ interchangeable.
28
+ - Interface Segregation: depend on narrow protocols or callables rather
29
+ than broad objects with unrelated responsibilities.
30
+ - Dependency Inversion: high-level workflows depend on stable interfaces,
31
+ not concrete low-level details.
32
+
33
+ ## Dependencies
34
+
35
+ - Minimize external dependencies.
36
+ - Prefer Python standard library packages.
37
+ - Do not add third-party dependencies unless there is a clear technical need
38
+ that cannot reasonably be met with the standard library.
39
+ - Explain the reason for any new dependency before adding it.
40
+
41
+ ## Implementation Guidance
42
+
43
+ - Start substantial feature work and architecture changes with an Architecture
44
+ Decision Record in `doc/` before implementing code.
45
+ - Keep changes focused on the requested behavior.
46
+ - Keep public interfaces small.
47
+ - Name modules, classes, functions, variables, and tests with business/domain
48
+ vocabulary first.
49
+ - Avoid global mutable state unless there is a clear reason.
50
+ - Prefer deterministic behavior and explicit inputs.
51
+ - Use design patterns deliberately:
52
+ - Strategy when behavior varies by profile, format, rule, or policy.
53
+ - Registry when behavior must be extended without modifying the engine.
54
+ - Adapter when exposing a simple callable or external API.
55
+ - Factory functions when object creation has validation or multiple variants.
56
+ - Write tests for new behavior.
57
+ - Maintain 100% test coverage.
58
+ - Test function docstrings must state the requirement being verified using the
59
+ prefix `Requirement:`.
60
+ - Every module, function, class, method, and test must include a strict
61
+ Google-style docstring, including private functions and classes.
62
+ - Function and method docstrings must include:
63
+ - a precise summary that explains the domain behavior;
64
+ - `Args:` for every parameter except `self` and `cls`;
65
+ - `Returns:` for every non-`None` return value;
66
+ - `Raises:` for every intentionally raised exception.
67
+ - Class docstrings must include `Attributes:` when instances expose public
68
+ attributes.
69
+
70
+ ## Project Structure
71
+
72
+ - Source code lives in `src/mkforge/`.
73
+ - Tests live in `tests/`.
74
+ - Temporary outputs (coverage, caches, build artifacts) go into `work/`.
75
+
76
+ ## Quality Checks
77
+
78
+ Before finishing code changes, run:
79
+
80
+ ```bash
81
+ make check
82
+ ```
83
+
84
+ Use `make ci` for non-mutating verification.
85
+
86
+ ---
87
+
88
+ ## Mode Architecte
89
+
90
+ Activate this mode by saying: "mode architecte".
91
+
92
+ ### Posture
93
+
94
+ - **Challenge first.** Before accepting any feature request, ask: Is this
95
+ feature necessary? What problem does it solve? Can an existing mechanism
96
+ handle it? If the request is vague, ask one targeted clarifying question
97
+ before doing anything else.
98
+ - **Incremental ADRs.** Propose one focused ADR per decision. Never bundle
99
+ unrelated decisions in one document.
100
+ - **Simplicity over cleverness.** Prefer fewer abstractions. A flat list of
101
+ steps beats a plugin framework when there are three plugins.
102
+ - **Injection over inheritance.** Pass dependencies explicitly. Never use
103
+ base-class coupling or hidden global state.
104
+ - **Design patterns deliberately.** Use Strategy when behavior varies by
105
+ policy. Use Registry when behavior must be extended without editing the
106
+ engine. Use Adapter to isolate I/O. Use Pipeline for ordered, independently
107
+ testable steps. Do not introduce a pattern for decoration.
108
+
109
+ ### Deliverables
110
+
111
+ When asked to design a feature, produce documents in this order:
112
+
113
+ 1. **SRS fragment** — list only the requirements that are new or changed. Use
114
+ `REQ-<CATEGORY>-<NN>` identifiers. Each requirement gets one sentence with
115
+ SHALL / SHOULD / MAY. Include acceptance criteria.
116
+ 2. **ADR** — one decision, one document. Sections: Context, Decision,
117
+ Consequences, Alternatives rejected. Store in `doc/ADR-NNN-slug.md`.
118
+ 3. **SDD section** — update the relevant section of `doc/SDD.md` to reflect
119
+ the design. Include: affected modules, public interfaces changed, data
120
+ flow, error handling, test strategy.
121
+
122
+ ### Constraints
123
+
124
+ - SOLID principles strictly applied.
125
+ - Each module, class, and function has one clear reason to change.
126
+ - High-level workflows depend on stable interfaces, not concrete low-level
127
+ details.
128
+ - No module exceeds 500 lines unless an ADR explicitly justifies it.
129
+ - No function has cyclomatic complexity above 10.
130
+ - Public interfaces are small and named with business/domain vocabulary.
131
+ - No global mutable state.
132
+
133
+ ---
134
+
135
+ ## Mode Codeur
136
+
137
+ Activate this mode by saying: "mode codeur".
138
+
139
+ ### Posture
140
+
141
+ - **Clarity over cleverness.** Write code a junior can read without
142
+ explanation.
143
+ - **PEP-compliant always.** Follow PEP 8, PEP 257 (Google style), PEP 484,
144
+ PEP 526. Run `make check` before declaring done.
145
+ - **100% check coverage.** Every code change must leave `make check` passing.
146
+ Fix ruff, flake8, mypy, bandit, and pytest failures before closing the task.
147
+ - **Defensive programming at boundaries only.** Validate at entry points (CLI
148
+ args, external API responses, file I/O). Trust internal code and framework
149
+ guarantees. Do not add redundant guards inside a function that already
150
+ received a validated value.
151
+ - **Exceptions with intent.** Raise only when the caller genuinely cannot
152
+ continue. Name exceptions with domain vocabulary. Never use bare `except:`.
153
+ Never swallow exceptions silently.
154
+ - **Prefer stdlib, then well-known packages.** Use `pathlib`, `dataclasses`,
155
+ `typing`, `importlib.resources`. Do not add a dependency that the stdlib can
156
+ handle.
157
+ - **Injection over inheritance.** Pass dependencies as arguments. Avoid global
158
+ state.
159
+
160
+ ### Coding Standards (Codeur)
161
+
162
+ - Google-style docstrings on every function, method, class — including private
163
+ ones.
164
+ - Function docstrings: summary + `Args:` + `Returns:` + `Raises:`.
165
+ - Class docstrings: summary + `Attributes:` when public attributes exist.
166
+ - Test docstrings use `Requirement:` prefix to state what is being verified.
167
+ - Names use business/domain vocabulary.
168
+ - Cyclomatic complexity <= 10 per function.
169
+ - Module size <= 500 lines (justified by ADR if exceeded).
170
+
171
+ ### Testing Strategy
172
+
173
+ For every code change, write:
174
+
175
+ 1. **Unit tests** — mock all I/O and subprocess calls. Test one function in
176
+ isolation. Cover the pass path, the fail path, and each `Raises:` clause.
177
+ 2. **Integration / end-to-end tests** — at least one test that exercises the
178
+ full workflow without mocking internal modules (only external calls like
179
+ `subprocess`).
180
+
181
+ Test naming: `test_<what>_<condition>`.
182
+
183
+ ### Quality Gate
184
+
185
+ Before reporting done, run:
186
+
187
+ ```bash
188
+ make check
189
+ ```
190
+
191
+ When fixing linter/type errors:
192
+ - `ruff` errors — fix the code, not `# noqa`.
193
+ - `mypy` errors — add proper type annotations; never use `# type: ignore`.
194
+ - `bandit` B404/B603/B607 on subprocess — use `# nosec BXXX` on the offending
195
+ line.
mkforge-0.2.0/Makefile ADDED
@@ -0,0 +1,45 @@
1
+ # Generated by yggtools — do not remove this line.
2
+
3
+ .PHONY: check ci test format lint typecheck metrics security build check-dist publish-test publish clean
4
+
5
+ clean:
6
+ mkdir -p work
7
+ find work -mindepth 1 ! -name .gitkeep -exec rm -rf {} +
8
+
9
+ format:
10
+ uv run ruff format src tests
11
+
12
+ check: clean
13
+ PYTHONPATH=src uv run python -m yggtools.cli pipeline
14
+
15
+ ci: check
16
+
17
+ test: clean
18
+ uv run pytest
19
+
20
+ lint: clean
21
+ uv run ruff check src tests
22
+
23
+ typecheck: clean
24
+ uv run mypy src tests
25
+
26
+ metrics: clean
27
+ PYTHONPATH=src uv run python -m yggtools.cli run metrics
28
+
29
+ security: clean
30
+ PYTHONPATH=src uv run python -m yggtools.cli run security-code
31
+ PYTHONPATH=src uv run python -m yggtools.cli run security-deps
32
+
33
+ build: clean
34
+ rm -rf dist
35
+ uv build --out-dir dist/
36
+
37
+ check-dist: clean
38
+ uv build --out-dir work/dist
39
+ uv run twine check work/dist/*
40
+
41
+ publish-test: check-dist
42
+ uv run twine upload --repository testpypi work/dist/*
43
+
44
+ publish: check-dist
45
+ uv run twine upload work/dist/*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkforge
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Programmatic Markdown report generation for Python.
5
5
  Project-URL: Homepage, https://github.com/antoinebarre/mkforge
6
6
  Project-URL: Repository, https://github.com/antoinebarre/mkforge
@@ -73,9 +73,9 @@ For package validation before publishing:
73
73
  make check-dist
74
74
  ```
75
75
 
76
- Temporary outputs are created under `work/` and removed at the end of each
77
- quality or packaging execution. The directory is kept in the repository with
78
- `work/.gitkeep`.
76
+ Temporary quality reports are written under `work/reports/`. Packaging checks
77
+ build distributions under `work/dist/`. The `work/` directory is kept in the
78
+ repository with `work/.gitkeep`.
79
79
 
80
80
  ## Example
81
81
 
@@ -146,13 +146,28 @@ uv run python demo_verif.py
146
146
  uv run python demo_validation.py
147
147
  ```
148
148
 
149
+ ## Heading Slugification
150
+
151
+ ```python
152
+ from mkforge import slugify_heading
153
+
154
+ slugify_heading("Analyse des Risques") # "analyse-des-risques"
155
+ slugify_heading("`code` inline") # "code-inline"
156
+ ```
157
+
158
+ `slugify_heading` converts a raw heading title into a GitHub-style anchor
159
+ slug: lowercase, inline Markdown markers removed, non-alphanumeric runs
160
+ collapsed to a single hyphen, leading/trailing hyphens trimmed. Unicode
161
+ letters are preserved (case-folded, not transliterated), which keeps slugs
162
+ consistent with the anchors GitHub generates for the same heading.
163
+
149
164
  ## Relationship With Scribpy
150
165
 
151
166
  MkForge is intended to be independent from Scribpy.
152
167
 
153
168
  - `mkforge` generates Markdown reports from Python data.
154
169
  - `scribpy` assembles and builds Markdown documentation projects.
155
- - `uvforge` initializes and runs quality gates for Python packages using `uv`.
170
+ - `yggtools` initializes and runs quality gates for Python packages using `uv`.
156
171
 
157
- Scribpy and uvforge may depend on MkForge for generated reports, but MkForge
172
+ Scribpy and yggtools may depend on MkForge for generated reports, but MkForge
158
173
  should not depend on either of them.
@@ -58,9 +58,9 @@ For package validation before publishing:
58
58
  make check-dist
59
59
  ```
60
60
 
61
- Temporary outputs are created under `work/` and removed at the end of each
62
- quality or packaging execution. The directory is kept in the repository with
63
- `work/.gitkeep`.
61
+ Temporary quality reports are written under `work/reports/`. Packaging checks
62
+ build distributions under `work/dist/`. The `work/` directory is kept in the
63
+ repository with `work/.gitkeep`.
64
64
 
65
65
  ## Example
66
66
 
@@ -131,13 +131,28 @@ uv run python demo_verif.py
131
131
  uv run python demo_validation.py
132
132
  ```
133
133
 
134
+ ## Heading Slugification
135
+
136
+ ```python
137
+ from mkforge import slugify_heading
138
+
139
+ slugify_heading("Analyse des Risques") # "analyse-des-risques"
140
+ slugify_heading("`code` inline") # "code-inline"
141
+ ```
142
+
143
+ `slugify_heading` converts a raw heading title into a GitHub-style anchor
144
+ slug: lowercase, inline Markdown markers removed, non-alphanumeric runs
145
+ collapsed to a single hyphen, leading/trailing hyphens trimmed. Unicode
146
+ letters are preserved (case-folded, not transliterated), which keeps slugs
147
+ consistent with the anchors GitHub generates for the same heading.
148
+
134
149
  ## Relationship With Scribpy
135
150
 
136
151
  MkForge is intended to be independent from Scribpy.
137
152
 
138
153
  - `mkforge` generates Markdown reports from Python data.
139
154
  - `scribpy` assembles and builds Markdown documentation projects.
140
- - `uvforge` initializes and runs quality gates for Python packages using `uv`.
155
+ - `yggtools` initializes and runs quality gates for Python packages using `uv`.
141
156
 
142
- Scribpy and uvforge may depend on MkForge for generated reports, but MkForge
157
+ Scribpy and yggtools may depend on MkForge for generated reports, but MkForge
143
158
  should not depend on either of them.