maylang-cli 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.
- maylang_cli-0.1.0/LICENSE +21 -0
- maylang_cli-0.1.0/PKG-INFO +344 -0
- maylang_cli-0.1.0/README.md +313 -0
- maylang_cli-0.1.0/maylang_cli/__init__.py +9 -0
- maylang_cli-0.1.0/maylang_cli/_version.py +15 -0
- maylang_cli-0.1.0/maylang_cli/bumper.py +66 -0
- maylang_cli-0.1.0/maylang_cli/checker.py +213 -0
- maylang_cli-0.1.0/maylang_cli/cli.py +169 -0
- maylang_cli-0.1.0/maylang_cli/parser.py +239 -0
- maylang_cli-0.1.0/maylang_cli/template.py +76 -0
- maylang_cli-0.1.0/maylang_cli.egg-info/PKG-INFO +344 -0
- maylang_cli-0.1.0/maylang_cli.egg-info/SOURCES.txt +22 -0
- maylang_cli-0.1.0/maylang_cli.egg-info/dependency_links.txt +1 -0
- maylang_cli-0.1.0/maylang_cli.egg-info/entry_points.txt +2 -0
- maylang_cli-0.1.0/maylang_cli.egg-info/requires.txt +5 -0
- maylang_cli-0.1.0/maylang_cli.egg-info/top_level.txt +1 -0
- maylang_cli-0.1.0/pyproject.toml +59 -0
- maylang_cli-0.1.0/setup.cfg +4 -0
- maylang_cli-0.1.0/tests/test_check_required.py +156 -0
- maylang_cli-0.1.0/tests/test_enforce_diff.py +113 -0
- maylang_cli-0.1.0/tests/test_frontmatter.py +184 -0
- maylang_cli-0.1.0/tests/test_headings_order.py +115 -0
- maylang_cli-0.1.0/tests/test_verification.py +111 -0
- maylang_cli-0.1.0/tests/test_version_bump.py +106 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MayLang Contributors
|
|
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,344 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: maylang-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MayLang – Explainable Change Standard CLI for reducing AI tech debt.
|
|
5
|
+
Author: MayLang Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mayankkatulkar/maylang-cli
|
|
8
|
+
Project-URL: Repository, https://github.com/mayankkatulkar/maylang-cli
|
|
9
|
+
Project-URL: Issues, https://github.com/mayankkatulkar/maylang-cli/issues
|
|
10
|
+
Keywords: maylang,change-management,explainability,ai-tech-debt,cli
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: PyYAML>=6.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
29
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# MayLang CLI
|
|
33
|
+
|
|
34
|
+
**Explainable Change Standard** — a minimal, universal spec that reduces AI tech debt across ANY language or repo.
|
|
35
|
+
|
|
36
|
+
MayLang is a lightweight convention: every meaningful change ships with a **Change Package** (`.may.md` file) that documents *intent*, *contract*, *invariants*, *patch*, *verification*, and *debug map* in a single, machine-readable Markdown file with YAML frontmatter.
|
|
37
|
+
|
|
38
|
+
`maylang-cli` is the tiny Python CLI that creates and validates these packages.
|
|
39
|
+
|
|
40
|
+
> **Import note:** The Python package is `maylang_cli` (underscore) to avoid namespace conflicts. The PyPI name is `maylang-cli`. The CLI command is `may`.
|
|
41
|
+
|
|
42
|
+
[](https://github.com/mayankkatulkar/maylang-cli/actions)
|
|
43
|
+
[](https://pypi.org/project/maylang-cli/)
|
|
44
|
+
[](LICENSE)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## What Is a MayLang Change Package?
|
|
49
|
+
|
|
50
|
+
A `.may.md` file lives at `maylang/MC-<id>-<slug>.may.md` and contains:
|
|
51
|
+
|
|
52
|
+
```markdown
|
|
53
|
+
---
|
|
54
|
+
id: "MC-0001"
|
|
55
|
+
type: change
|
|
56
|
+
scope: fullstack
|
|
57
|
+
risk: low
|
|
58
|
+
owner: "team-alpha"
|
|
59
|
+
rollback: revert_commit
|
|
60
|
+
ai_used: false
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
# Intent
|
|
64
|
+
|
|
65
|
+
Add session caching to reduce auth latency by 40%.
|
|
66
|
+
|
|
67
|
+
# Contract
|
|
68
|
+
|
|
69
|
+
- Input: session token (JWT)
|
|
70
|
+
- Output: cached session object
|
|
71
|
+
- Side-effects: writes to Redis
|
|
72
|
+
|
|
73
|
+
# Invariants
|
|
74
|
+
|
|
75
|
+
1. Tokens are never stored in plain text.
|
|
76
|
+
2. Cache TTL ≤ session expiry.
|
|
77
|
+
|
|
78
|
+
# Patch
|
|
79
|
+
|
|
80
|
+
```diff
|
|
81
|
+
--- a/auth/sessions.py
|
|
82
|
+
+++ b/auth/sessions.py
|
|
83
|
+
@@ -12,6 +12,9 @@
|
|
84
|
+
def get_session(token: str) -> Session:
|
|
85
|
+
- return db.query(Session).filter_by(token=token).first()
|
|
86
|
+
+ cached = redis.get(f"sess:{token}")
|
|
87
|
+
+ if cached:
|
|
88
|
+
+ return Session.from_cache(cached)
|
|
89
|
+
+ session = db.query(Session).filter_by(token=token).first()
|
|
90
|
+
+ redis.setex(f"sess:{token}", session.ttl, session.to_cache())
|
|
91
|
+
+ return session
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
# Verification
|
|
95
|
+
|
|
96
|
+
- `pytest tests/test_sessions.py`
|
|
97
|
+
- `curl -H "Authorization: Bearer $TOKEN" localhost:8000/me`
|
|
98
|
+
|
|
99
|
+
# Debug Map
|
|
100
|
+
|
|
101
|
+
| Symptom | Likely cause | First file to check |
|
|
102
|
+
|---------|-------------|---------------------|
|
|
103
|
+
| 401 after deploy | Cache not warmed | auth/sessions.py |
|
|
104
|
+
| Stale session data | TTL mismatch | config/redis.yml |
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Required Frontmatter Keys
|
|
108
|
+
|
|
109
|
+
`id`, `type`, `scope`, `risk`, `owner`, `rollback`, `ai_used`
|
|
110
|
+
|
|
111
|
+
### Required Headings (in order)
|
|
112
|
+
|
|
113
|
+
1. `# Intent`
|
|
114
|
+
2. `# Contract`
|
|
115
|
+
3. `# Invariants`
|
|
116
|
+
4. `# Patch`
|
|
117
|
+
5. `# Verification` — must contain at least one runnable command
|
|
118
|
+
6. `# Debug Map`
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Installation
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Recommended (isolated install)
|
|
126
|
+
pipx install maylang-cli
|
|
127
|
+
|
|
128
|
+
# Or with pip
|
|
129
|
+
pip install maylang-cli
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
For development:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
git clone https://github.com/mayankkatulkar/maylang-cli.git
|
|
136
|
+
cd maylang-cli
|
|
137
|
+
pip install -e ".[dev]"
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Usage
|
|
143
|
+
|
|
144
|
+
### Create a New Change Package
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
may new \
|
|
148
|
+
--id MC-0001 \
|
|
149
|
+
--slug auth-sessions \
|
|
150
|
+
--scope fullstack \
|
|
151
|
+
--risk low \
|
|
152
|
+
--owner "team-alpha" \
|
|
153
|
+
--rollback revert_commit
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This creates `maylang/MC-0001-auth-sessions.may.md` from the built-in template.
|
|
157
|
+
|
|
158
|
+
### Validate Change Packages
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Always require at least one .may.md
|
|
162
|
+
may check
|
|
163
|
+
|
|
164
|
+
# Same as above (explicit)
|
|
165
|
+
may check --require always
|
|
166
|
+
|
|
167
|
+
# Only require when files in specific paths changed
|
|
168
|
+
may check --require changed --base origin/main --paths auth/,payments/,db/migrations/
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Exit Codes
|
|
172
|
+
|
|
173
|
+
| Code | Meaning |
|
|
174
|
+
|------|---------|
|
|
175
|
+
| `0` | All checks passed |
|
|
176
|
+
| `2` | Missing required MayLang file |
|
|
177
|
+
| `3` | Validation error (bad frontmatter, wrong headings, etc.) |
|
|
178
|
+
|
|
179
|
+
#### Enforce Diff Block
|
|
180
|
+
|
|
181
|
+
By default, the Patch section is not strictly validated for a `diff` block. To require one:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
may check --enforce-diff
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Bump Version
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Bump patch version (0.1.0 → 0.1.1)
|
|
191
|
+
may version --bump patch
|
|
192
|
+
|
|
193
|
+
# Bump minor version (0.1.0 → 0.2.0)
|
|
194
|
+
may version --bump minor
|
|
195
|
+
|
|
196
|
+
# Bump major version (0.1.0 → 1.0.0)
|
|
197
|
+
may version --bump major
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
This updates the `version` field in your `pyproject.toml`.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Project Structure
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
maylang-cli/
|
|
208
|
+
├── maylang_cli/
|
|
209
|
+
│ ├── __init__.py # Package marker
|
|
210
|
+
│ ├── _version.py # Version via importlib.metadata
|
|
211
|
+
│ ├── bumper.py # Version bump helper
|
|
212
|
+
│ ├── cli.py # Argparse CLI (entrypoint: may)
|
|
213
|
+
│ ├── checker.py # High-level check orchestration
|
|
214
|
+
│ ├── parser.py # .may.md parsing & validation
|
|
215
|
+
│ └── template.py # Built-in template for `may new`
|
|
216
|
+
├── tests/
|
|
217
|
+
│ ├── test_check_required.py
|
|
218
|
+
│ ├── test_frontmatter.py
|
|
219
|
+
│ ├── test_headings_order.py
|
|
220
|
+
│ ├── test_verification.py
|
|
221
|
+
│ ├── test_enforce_diff.py
|
|
222
|
+
│ └── test_version_bump.py
|
|
223
|
+
├── .github/workflows/ci.yml
|
|
224
|
+
├── .gitignore
|
|
225
|
+
├── LICENSE
|
|
226
|
+
├── README.md
|
|
227
|
+
└── pyproject.toml
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Company Adoption Guide
|
|
233
|
+
|
|
234
|
+
### Why Adopt MayLang?
|
|
235
|
+
|
|
236
|
+
- **AI Accountability** — Every AI-assisted change has a human-readable spec.
|
|
237
|
+
- **Cross-team Clarity** — Backend, frontend, and infra teams share one format.
|
|
238
|
+
- **Audit Trail** — Change packages live in git; they're versioned and reviewable.
|
|
239
|
+
- **CI-enforceable** — Block PRs that lack proper documentation.
|
|
240
|
+
|
|
241
|
+
### Step-by-Step
|
|
242
|
+
|
|
243
|
+
1. **Install:** `pip install maylang-cli` in your CI environment.
|
|
244
|
+
2. **Create a change package** for every meaningful PR:
|
|
245
|
+
```bash
|
|
246
|
+
may new --id MC-0001 --slug add-rate-limiter --scope backend --risk medium --owner "platform-team"
|
|
247
|
+
```
|
|
248
|
+
3. **Fill in the template** — document intent, contract, invariants, patch, verification steps, and debug map.
|
|
249
|
+
4. **Add CI enforcement** (see below).
|
|
250
|
+
5. **Review `.may.md` files in PR reviews** just like code.
|
|
251
|
+
|
|
252
|
+
### Suggested Team Conventions
|
|
253
|
+
|
|
254
|
+
| Decision | Recommendation |
|
|
255
|
+
|----------|---------------|
|
|
256
|
+
| When to require | Use `--require changed --paths` for gradual adoption |
|
|
257
|
+
| ID format | `MC-NNNN` (monotonically increasing) |
|
|
258
|
+
| Who writes it | The PR author, reviewed by the team |
|
|
259
|
+
| AI changes | Set `ai_used: true` in frontmatter |
|
|
260
|
+
| Rollback | Always specify a concrete rollback strategy |
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Company Adoption: CI Snippet
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
# In your CI pipeline:
|
|
268
|
+
pipx install maylang-cli
|
|
269
|
+
may check --require changed --base origin/main --paths auth/,payments/,db/migrations/
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Or as a GitHub Actions step:
|
|
273
|
+
|
|
274
|
+
```yaml
|
|
275
|
+
name: MayLang Check
|
|
276
|
+
|
|
277
|
+
on:
|
|
278
|
+
pull_request:
|
|
279
|
+
branches: [main]
|
|
280
|
+
|
|
281
|
+
jobs:
|
|
282
|
+
maylang:
|
|
283
|
+
runs-on: ubuntu-latest
|
|
284
|
+
steps:
|
|
285
|
+
- uses: actions/checkout@v4
|
|
286
|
+
with:
|
|
287
|
+
fetch-depth: 0
|
|
288
|
+
|
|
289
|
+
- uses: actions/setup-python@v5
|
|
290
|
+
with:
|
|
291
|
+
python-version: "3.12"
|
|
292
|
+
|
|
293
|
+
- run: pip install maylang-cli
|
|
294
|
+
|
|
295
|
+
- name: Validate MayLang Change Packages
|
|
296
|
+
run: may check --require changed --base origin/main --paths auth/,payments/,db/migrations/
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
For repos that want to enforce MayLang on **every** PR:
|
|
300
|
+
|
|
301
|
+
```yaml
|
|
302
|
+
- run: may check --require always
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
To also enforce diff blocks in the Patch section:
|
|
306
|
+
|
|
307
|
+
```yaml
|
|
308
|
+
- run: may check --require always --enforce-diff
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Manual PyPI Release (Option A)
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
# 1. Install build tools
|
|
317
|
+
python -m pip install -U build twine
|
|
318
|
+
|
|
319
|
+
# 2. Build wheel + sdist
|
|
320
|
+
python -m build
|
|
321
|
+
|
|
322
|
+
# 3. Upload to TestPyPI first
|
|
323
|
+
python -m twine upload --repository testpypi dist/*
|
|
324
|
+
|
|
325
|
+
# 4. Verify in a fresh venv
|
|
326
|
+
python -m venv /tmp/test-maylang && . /tmp/test-maylang/bin/activate
|
|
327
|
+
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ maylang-cli
|
|
328
|
+
may --version
|
|
329
|
+
deactivate && rm -rf /tmp/test-maylang
|
|
330
|
+
|
|
331
|
+
# 5. Upload to production PyPI
|
|
332
|
+
python -m twine upload dist/*
|
|
333
|
+
|
|
334
|
+
# 6. Install from PyPI
|
|
335
|
+
pipx install maylang-cli
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
See [docs/RELEASING.md](docs/RELEASING.md) for the full release checklist.
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## License
|
|
343
|
+
|
|
344
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# MayLang CLI
|
|
2
|
+
|
|
3
|
+
**Explainable Change Standard** — a minimal, universal spec that reduces AI tech debt across ANY language or repo.
|
|
4
|
+
|
|
5
|
+
MayLang is a lightweight convention: every meaningful change ships with a **Change Package** (`.may.md` file) that documents *intent*, *contract*, *invariants*, *patch*, *verification*, and *debug map* in a single, machine-readable Markdown file with YAML frontmatter.
|
|
6
|
+
|
|
7
|
+
`maylang-cli` is the tiny Python CLI that creates and validates these packages.
|
|
8
|
+
|
|
9
|
+
> **Import note:** The Python package is `maylang_cli` (underscore) to avoid namespace conflicts. The PyPI name is `maylang-cli`. The CLI command is `may`.
|
|
10
|
+
|
|
11
|
+
[](https://github.com/mayankkatulkar/maylang-cli/actions)
|
|
12
|
+
[](https://pypi.org/project/maylang-cli/)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## What Is a MayLang Change Package?
|
|
18
|
+
|
|
19
|
+
A `.may.md` file lives at `maylang/MC-<id>-<slug>.may.md` and contains:
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
---
|
|
23
|
+
id: "MC-0001"
|
|
24
|
+
type: change
|
|
25
|
+
scope: fullstack
|
|
26
|
+
risk: low
|
|
27
|
+
owner: "team-alpha"
|
|
28
|
+
rollback: revert_commit
|
|
29
|
+
ai_used: false
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
# Intent
|
|
33
|
+
|
|
34
|
+
Add session caching to reduce auth latency by 40%.
|
|
35
|
+
|
|
36
|
+
# Contract
|
|
37
|
+
|
|
38
|
+
- Input: session token (JWT)
|
|
39
|
+
- Output: cached session object
|
|
40
|
+
- Side-effects: writes to Redis
|
|
41
|
+
|
|
42
|
+
# Invariants
|
|
43
|
+
|
|
44
|
+
1. Tokens are never stored in plain text.
|
|
45
|
+
2. Cache TTL ≤ session expiry.
|
|
46
|
+
|
|
47
|
+
# Patch
|
|
48
|
+
|
|
49
|
+
```diff
|
|
50
|
+
--- a/auth/sessions.py
|
|
51
|
+
+++ b/auth/sessions.py
|
|
52
|
+
@@ -12,6 +12,9 @@
|
|
53
|
+
def get_session(token: str) -> Session:
|
|
54
|
+
- return db.query(Session).filter_by(token=token).first()
|
|
55
|
+
+ cached = redis.get(f"sess:{token}")
|
|
56
|
+
+ if cached:
|
|
57
|
+
+ return Session.from_cache(cached)
|
|
58
|
+
+ session = db.query(Session).filter_by(token=token).first()
|
|
59
|
+
+ redis.setex(f"sess:{token}", session.ttl, session.to_cache())
|
|
60
|
+
+ return session
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
# Verification
|
|
64
|
+
|
|
65
|
+
- `pytest tests/test_sessions.py`
|
|
66
|
+
- `curl -H "Authorization: Bearer $TOKEN" localhost:8000/me`
|
|
67
|
+
|
|
68
|
+
# Debug Map
|
|
69
|
+
|
|
70
|
+
| Symptom | Likely cause | First file to check |
|
|
71
|
+
|---------|-------------|---------------------|
|
|
72
|
+
| 401 after deploy | Cache not warmed | auth/sessions.py |
|
|
73
|
+
| Stale session data | TTL mismatch | config/redis.yml |
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Required Frontmatter Keys
|
|
77
|
+
|
|
78
|
+
`id`, `type`, `scope`, `risk`, `owner`, `rollback`, `ai_used`
|
|
79
|
+
|
|
80
|
+
### Required Headings (in order)
|
|
81
|
+
|
|
82
|
+
1. `# Intent`
|
|
83
|
+
2. `# Contract`
|
|
84
|
+
3. `# Invariants`
|
|
85
|
+
4. `# Patch`
|
|
86
|
+
5. `# Verification` — must contain at least one runnable command
|
|
87
|
+
6. `# Debug Map`
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Recommended (isolated install)
|
|
95
|
+
pipx install maylang-cli
|
|
96
|
+
|
|
97
|
+
# Or with pip
|
|
98
|
+
pip install maylang-cli
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For development:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
git clone https://github.com/mayankkatulkar/maylang-cli.git
|
|
105
|
+
cd maylang-cli
|
|
106
|
+
pip install -e ".[dev]"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Usage
|
|
112
|
+
|
|
113
|
+
### Create a New Change Package
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
may new \
|
|
117
|
+
--id MC-0001 \
|
|
118
|
+
--slug auth-sessions \
|
|
119
|
+
--scope fullstack \
|
|
120
|
+
--risk low \
|
|
121
|
+
--owner "team-alpha" \
|
|
122
|
+
--rollback revert_commit
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
This creates `maylang/MC-0001-auth-sessions.may.md` from the built-in template.
|
|
126
|
+
|
|
127
|
+
### Validate Change Packages
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Always require at least one .may.md
|
|
131
|
+
may check
|
|
132
|
+
|
|
133
|
+
# Same as above (explicit)
|
|
134
|
+
may check --require always
|
|
135
|
+
|
|
136
|
+
# Only require when files in specific paths changed
|
|
137
|
+
may check --require changed --base origin/main --paths auth/,payments/,db/migrations/
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### Exit Codes
|
|
141
|
+
|
|
142
|
+
| Code | Meaning |
|
|
143
|
+
|------|---------|
|
|
144
|
+
| `0` | All checks passed |
|
|
145
|
+
| `2` | Missing required MayLang file |
|
|
146
|
+
| `3` | Validation error (bad frontmatter, wrong headings, etc.) |
|
|
147
|
+
|
|
148
|
+
#### Enforce Diff Block
|
|
149
|
+
|
|
150
|
+
By default, the Patch section is not strictly validated for a `diff` block. To require one:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
may check --enforce-diff
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Bump Version
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Bump patch version (0.1.0 → 0.1.1)
|
|
160
|
+
may version --bump patch
|
|
161
|
+
|
|
162
|
+
# Bump minor version (0.1.0 → 0.2.0)
|
|
163
|
+
may version --bump minor
|
|
164
|
+
|
|
165
|
+
# Bump major version (0.1.0 → 1.0.0)
|
|
166
|
+
may version --bump major
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This updates the `version` field in your `pyproject.toml`.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Project Structure
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
maylang-cli/
|
|
177
|
+
├── maylang_cli/
|
|
178
|
+
│ ├── __init__.py # Package marker
|
|
179
|
+
│ ├── _version.py # Version via importlib.metadata
|
|
180
|
+
│ ├── bumper.py # Version bump helper
|
|
181
|
+
│ ├── cli.py # Argparse CLI (entrypoint: may)
|
|
182
|
+
│ ├── checker.py # High-level check orchestration
|
|
183
|
+
│ ├── parser.py # .may.md parsing & validation
|
|
184
|
+
│ └── template.py # Built-in template for `may new`
|
|
185
|
+
├── tests/
|
|
186
|
+
│ ├── test_check_required.py
|
|
187
|
+
│ ├── test_frontmatter.py
|
|
188
|
+
│ ├── test_headings_order.py
|
|
189
|
+
│ ├── test_verification.py
|
|
190
|
+
│ ├── test_enforce_diff.py
|
|
191
|
+
│ └── test_version_bump.py
|
|
192
|
+
├── .github/workflows/ci.yml
|
|
193
|
+
├── .gitignore
|
|
194
|
+
├── LICENSE
|
|
195
|
+
├── README.md
|
|
196
|
+
└── pyproject.toml
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Company Adoption Guide
|
|
202
|
+
|
|
203
|
+
### Why Adopt MayLang?
|
|
204
|
+
|
|
205
|
+
- **AI Accountability** — Every AI-assisted change has a human-readable spec.
|
|
206
|
+
- **Cross-team Clarity** — Backend, frontend, and infra teams share one format.
|
|
207
|
+
- **Audit Trail** — Change packages live in git; they're versioned and reviewable.
|
|
208
|
+
- **CI-enforceable** — Block PRs that lack proper documentation.
|
|
209
|
+
|
|
210
|
+
### Step-by-Step
|
|
211
|
+
|
|
212
|
+
1. **Install:** `pip install maylang-cli` in your CI environment.
|
|
213
|
+
2. **Create a change package** for every meaningful PR:
|
|
214
|
+
```bash
|
|
215
|
+
may new --id MC-0001 --slug add-rate-limiter --scope backend --risk medium --owner "platform-team"
|
|
216
|
+
```
|
|
217
|
+
3. **Fill in the template** — document intent, contract, invariants, patch, verification steps, and debug map.
|
|
218
|
+
4. **Add CI enforcement** (see below).
|
|
219
|
+
5. **Review `.may.md` files in PR reviews** just like code.
|
|
220
|
+
|
|
221
|
+
### Suggested Team Conventions
|
|
222
|
+
|
|
223
|
+
| Decision | Recommendation |
|
|
224
|
+
|----------|---------------|
|
|
225
|
+
| When to require | Use `--require changed --paths` for gradual adoption |
|
|
226
|
+
| ID format | `MC-NNNN` (monotonically increasing) |
|
|
227
|
+
| Who writes it | The PR author, reviewed by the team |
|
|
228
|
+
| AI changes | Set `ai_used: true` in frontmatter |
|
|
229
|
+
| Rollback | Always specify a concrete rollback strategy |
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Company Adoption: CI Snippet
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# In your CI pipeline:
|
|
237
|
+
pipx install maylang-cli
|
|
238
|
+
may check --require changed --base origin/main --paths auth/,payments/,db/migrations/
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Or as a GitHub Actions step:
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
name: MayLang Check
|
|
245
|
+
|
|
246
|
+
on:
|
|
247
|
+
pull_request:
|
|
248
|
+
branches: [main]
|
|
249
|
+
|
|
250
|
+
jobs:
|
|
251
|
+
maylang:
|
|
252
|
+
runs-on: ubuntu-latest
|
|
253
|
+
steps:
|
|
254
|
+
- uses: actions/checkout@v4
|
|
255
|
+
with:
|
|
256
|
+
fetch-depth: 0
|
|
257
|
+
|
|
258
|
+
- uses: actions/setup-python@v5
|
|
259
|
+
with:
|
|
260
|
+
python-version: "3.12"
|
|
261
|
+
|
|
262
|
+
- run: pip install maylang-cli
|
|
263
|
+
|
|
264
|
+
- name: Validate MayLang Change Packages
|
|
265
|
+
run: may check --require changed --base origin/main --paths auth/,payments/,db/migrations/
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
For repos that want to enforce MayLang on **every** PR:
|
|
269
|
+
|
|
270
|
+
```yaml
|
|
271
|
+
- run: may check --require always
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
To also enforce diff blocks in the Patch section:
|
|
275
|
+
|
|
276
|
+
```yaml
|
|
277
|
+
- run: may check --require always --enforce-diff
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Manual PyPI Release (Option A)
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# 1. Install build tools
|
|
286
|
+
python -m pip install -U build twine
|
|
287
|
+
|
|
288
|
+
# 2. Build wheel + sdist
|
|
289
|
+
python -m build
|
|
290
|
+
|
|
291
|
+
# 3. Upload to TestPyPI first
|
|
292
|
+
python -m twine upload --repository testpypi dist/*
|
|
293
|
+
|
|
294
|
+
# 4. Verify in a fresh venv
|
|
295
|
+
python -m venv /tmp/test-maylang && . /tmp/test-maylang/bin/activate
|
|
296
|
+
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ maylang-cli
|
|
297
|
+
may --version
|
|
298
|
+
deactivate && rm -rf /tmp/test-maylang
|
|
299
|
+
|
|
300
|
+
# 5. Upload to production PyPI
|
|
301
|
+
python -m twine upload dist/*
|
|
302
|
+
|
|
303
|
+
# 6. Install from PyPI
|
|
304
|
+
pipx install maylang-cli
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
See [docs/RELEASING.md](docs/RELEASING.md) for the full release checklist.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""MayLang CLI – Explainable Change Standard toolkit.
|
|
2
|
+
|
|
3
|
+
Provides the ``may`` CLI plus helpers to create and validate
|
|
4
|
+
MayLang Change Packages (``*.may.md``).
|
|
5
|
+
|
|
6
|
+
The importable package is ``maylang_cli`` (underscore) to avoid
|
|
7
|
+
namespace conflicts with any other installed ``maylang`` package.
|
|
8
|
+
The PyPI distribution name remains ``maylang-cli``.
|
|
9
|
+
"""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Version helper – single source of truth via ``importlib.metadata``.
|
|
2
|
+
|
|
3
|
+
Usage::
|
|
4
|
+
|
|
5
|
+
from maylang_cli._version import __version__
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
__version__: str = version("maylang-cli")
|
|
14
|
+
except PackageNotFoundError: # pragma: no cover – editable / dev installs
|
|
15
|
+
__version__ = "0.0.0-dev"
|