labharness 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 (108) hide show
  1. labharness-0.1.0/.editorconfig +18 -0
  2. labharness-0.1.0/.gitattributes +11 -0
  3. labharness-0.1.0/.github/CODEOWNERS +2 -0
  4. labharness-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +40 -0
  5. labharness-0.1.0/.github/ISSUE_TEMPLATE/config.yml +1 -0
  6. labharness-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +19 -0
  7. labharness-0.1.0/.github/pull_request_template.md +14 -0
  8. labharness-0.1.0/.github/rulesets/main.json +37 -0
  9. labharness-0.1.0/.github/workflows/ci.yml +110 -0
  10. labharness-0.1.0/.gitignore +35 -0
  11. labharness-0.1.0/.pre-commit-config.yaml +26 -0
  12. labharness-0.1.0/.python-version +1 -0
  13. labharness-0.1.0/AGENTS.md +46 -0
  14. labharness-0.1.0/CLAUDE.md +1 -0
  15. labharness-0.1.0/CODE_OF_CONDUCT.md +13 -0
  16. labharness-0.1.0/CONTRIBUTING.md +55 -0
  17. labharness-0.1.0/LICENSE +21 -0
  18. labharness-0.1.0/PKG-INFO +269 -0
  19. labharness-0.1.0/README.md +231 -0
  20. labharness-0.1.0/SECURITY.md +17 -0
  21. labharness-0.1.0/docs/CHANGELOG.md +46 -0
  22. labharness-0.1.0/docs/ROADMAP.md +75 -0
  23. labharness-0.1.0/docs/adr/README.md +26 -0
  24. labharness-0.1.0/docs/onboarding.md +133 -0
  25. labharness-0.1.0/docs/usage.md +272 -0
  26. labharness-0.1.0/examples/demo/.gitignore +10 -0
  27. labharness-0.1.0/examples/demo/AGENTS.md +30 -0
  28. labharness-0.1.0/examples/demo/CLAUDE.md +1 -0
  29. labharness-0.1.0/examples/demo/README.md +33 -0
  30. labharness-0.1.0/examples/demo/compile.ps1 +3 -0
  31. labharness-0.1.0/examples/demo/compile.sh +4 -0
  32. labharness-0.1.0/examples/demo/data/.gitkeep +0 -0
  33. labharness-0.1.0/examples/demo/data/atenolol.smi +2 -0
  34. labharness-0.1.0/examples/demo/data/decay.csv +9 -0
  35. labharness-0.1.0/examples/demo/data/kapp.csv +4 -0
  36. labharness-0.1.0/examples/demo/figures/.gitkeep +0 -0
  37. labharness-0.1.0/examples/demo/labharness-style.tex +34 -0
  38. labharness-0.1.0/examples/demo/labharness.toml +21 -0
  39. labharness-0.1.0/examples/demo/paper.tex +87 -0
  40. labharness-0.1.0/examples/demo/references.bib +13 -0
  41. labharness-0.1.0/examples/demo/scripts/.gitkeep +0 -0
  42. labharness-0.1.0/examples/demo/scripts/atenolol.py +7 -0
  43. labharness-0.1.0/examples/demo/scripts/decay.py +13 -0
  44. labharness-0.1.0/examples/demo/scripts/kapp.py +10 -0
  45. labharness-0.1.0/examples/demo/scripts/mechanism.tex +19 -0
  46. labharness-0.1.0/pyproject.toml +78 -0
  47. labharness-0.1.0/src/labharness/__init__.py +19 -0
  48. labharness-0.1.0/src/labharness/cli/__init__.py +8 -0
  49. labharness-0.1.0/src/labharness/cli/app.py +207 -0
  50. labharness-0.1.0/src/labharness/core/__init__.py +21 -0
  51. labharness-0.1.0/src/labharness/core/atomic.py +28 -0
  52. labharness-0.1.0/src/labharness/core/errors.py +17 -0
  53. labharness-0.1.0/src/labharness/core/extras.py +18 -0
  54. labharness-0.1.0/src/labharness/core/latex.py +107 -0
  55. labharness-0.1.0/src/labharness/core/manifest.py +119 -0
  56. labharness-0.1.0/src/labharness/core/templates.py +33 -0
  57. labharness-0.1.0/src/labharness/core/workspace.py +30 -0
  58. labharness-0.1.0/src/labharness/doctor.py +145 -0
  59. labharness-0.1.0/src/labharness/modules/__init__.py +13 -0
  60. labharness-0.1.0/src/labharness/modules/chem/__init__.py +13 -0
  61. labharness-0.1.0/src/labharness/modules/chem/resolve.py +53 -0
  62. labharness-0.1.0/src/labharness/modules/chem/structures.py +103 -0
  63. labharness-0.1.0/src/labharness/modules/diagrams/__init__.py +15 -0
  64. labharness-0.1.0/src/labharness/modules/diagrams/tikz.py +69 -0
  65. labharness-0.1.0/src/labharness/modules/plots/__init__.py +32 -0
  66. labharness-0.1.0/src/labharness/modules/plots/data.py +201 -0
  67. labharness-0.1.0/src/labharness/modules/plots/figure.py +179 -0
  68. labharness-0.1.0/src/labharness/modules/plots/fits.py +244 -0
  69. labharness-0.1.0/src/labharness/py.typed +0 -0
  70. labharness-0.1.0/src/labharness/style/__init__.py +33 -0
  71. labharness-0.1.0/src/labharness/style/fonts.py +33 -0
  72. labharness-0.1.0/src/labharness/style/journals/acs.toml +50 -0
  73. labharness-0.1.0/src/labharness/style/latex.py +93 -0
  74. labharness-0.1.0/src/labharness/style/mpl.py +66 -0
  75. labharness-0.1.0/src/labharness/style/rdkit.py +27 -0
  76. labharness-0.1.0/src/labharness/style/tokens.py +94 -0
  77. labharness-0.1.0/src/labharness/watch/__init__.py +26 -0
  78. labharness-0.1.0/src/labharness/watch/latex.py +16 -0
  79. labharness-0.1.0/src/labharness/watch/runner.py +139 -0
  80. labharness-0.1.0/src/labharness/watch/session.py +88 -0
  81. labharness-0.1.0/src/labharness/watch/viewer.py +55 -0
  82. labharness-0.1.0/templates/figures/flow.tex +11 -0
  83. labharness-0.1.0/templates/figures/mechanism.tex +17 -0
  84. labharness-0.1.0/templates/figures/network.tex +13 -0
  85. labharness-0.1.0/templates/workspace/.gitignore +11 -0
  86. labharness-0.1.0/templates/workspace/AGENTS.md +30 -0
  87. labharness-0.1.0/templates/workspace/CLAUDE.md +1 -0
  88. labharness-0.1.0/templates/workspace/compile.ps1 +3 -0
  89. labharness-0.1.0/templates/workspace/compile.sh +4 -0
  90. labharness-0.1.0/templates/workspace/data/.gitkeep +0 -0
  91. labharness-0.1.0/templates/workspace/figures/.gitkeep +0 -0
  92. labharness-0.1.0/templates/workspace/journals/acs/labharness-style.tex +34 -0
  93. labharness-0.1.0/templates/workspace/journals/acs/paper.tex +54 -0
  94. labharness-0.1.0/templates/workspace/journals/acs/references.bib +1 -0
  95. labharness-0.1.0/templates/workspace/labharness.toml +8 -0
  96. labharness-0.1.0/templates/workspace/scripts/.gitkeep +0 -0
  97. labharness-0.1.0/tests/test_cli.py +138 -0
  98. labharness-0.1.0/tests/test_core.py +55 -0
  99. labharness-0.1.0/tests/test_e2e.py +101 -0
  100. labharness-0.1.0/tests/test_manifest.py +112 -0
  101. labharness-0.1.0/tests/test_mod_chem.py +113 -0
  102. labharness-0.1.0/tests/test_mod_diagrams.py +85 -0
  103. labharness-0.1.0/tests/test_mod_plots.py +191 -0
  104. labharness-0.1.0/tests/test_style.py +123 -0
  105. labharness-0.1.0/tests/test_style_rdkit.py +40 -0
  106. labharness-0.1.0/tests/test_template.py +67 -0
  107. labharness-0.1.0/tests/test_watch.py +179 -0
  108. labharness-0.1.0/uv.lock +2224 -0
@@ -0,0 +1,18 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.{toml,yml,yaml,json,md,tex,bib}]
12
+ indent_size = 2
13
+
14
+ [*.md]
15
+ trim_trailing_whitespace = false
16
+
17
+ [*.ps1]
18
+ end_of_line = crlf
@@ -0,0 +1,11 @@
1
+ # Normalize line endings: LF in the repository, whatever the OS.
2
+ * text=auto eol=lf
3
+
4
+ # Windows-only scripts keep CRLF.
5
+ *.ps1 text eol=crlf
6
+
7
+ # Binary files.
8
+ *.pdf binary
9
+ *.png binary
10
+ *.otf binary
11
+ *.ttf binary
@@ -0,0 +1,2 @@
1
+ # The maintainer owns everything and approves every pull request.
2
+ * @AIAYN-creator
@@ -0,0 +1,40 @@
1
+ name: Bug report
2
+ description: Something does not work as documented.
3
+ labels: ["bug"]
4
+ body:
5
+ - type: textarea
6
+ id: what-happened
7
+ attributes:
8
+ label: What happened?
9
+ description: What did you do, what did you expect, and what happened instead?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: reproduce
14
+ attributes:
15
+ label: Steps to reproduce
16
+ description: The smallest set of files and commands that shows the problem.
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: doctor
21
+ attributes:
22
+ label: Output of `labharness doctor`
23
+ render: text
24
+ - type: input
25
+ id: version
26
+ attributes:
27
+ label: LabHarness version
28
+ placeholder: labharness --version
29
+ validations:
30
+ required: true
31
+ - type: dropdown
32
+ id: os
33
+ attributes:
34
+ label: Operating system
35
+ options:
36
+ - Windows
37
+ - macOS
38
+ - Linux
39
+ validations:
40
+ required: true
@@ -0,0 +1 @@
1
+ blank_issues_enabled: false
@@ -0,0 +1,19 @@
1
+ name: Feature request
2
+ description: Propose a new capability or a change in behaviour.
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: What friction does this remove?
9
+ description: Describe the problem in your scientific workflow, not only the solution.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed solution
16
+ - type: textarea
17
+ id: alternatives
18
+ attributes:
19
+ label: Alternatives you considered
@@ -0,0 +1,14 @@
1
+ ## What and why
2
+
3
+ <!-- What does this change do, and why is it needed? Link the issue it closes. -->
4
+
5
+ Closes #
6
+
7
+ ## Checklist
8
+
9
+ - [ ] The title follows Conventional Commits (e.g. `feat(plots): add power-law fits`).
10
+ - [ ] Tests cover the change, and `uv run pytest` passes locally.
11
+ - [ ] Docs and `docs/CHANGELOG.md` are updated if behaviour changed.
12
+ - [ ] No fonts, sizes or colours are hard-coded (everything comes from the shared style).
13
+ - [ ] The core still imports without any extra installed.
14
+ - [ ] The change respects the accepted ADRs in `docs/adr/`.
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "main",
3
+ "target": "branch",
4
+ "enforcement": "active",
5
+ "conditions": {
6
+ "ref_name": {
7
+ "include": ["~DEFAULT_BRANCH"],
8
+ "exclude": []
9
+ }
10
+ },
11
+ "rules": [
12
+ { "type": "deletion" },
13
+ { "type": "non_fast_forward" },
14
+ {
15
+ "type": "pull_request",
16
+ "parameters": {
17
+ "required_approving_review_count": 1,
18
+ "dismiss_stale_reviews_on_push": true,
19
+ "require_code_owner_review": true,
20
+ "require_last_push_approval": false,
21
+ "required_review_thread_resolution": true,
22
+ "allowed_merge_methods": ["squash"]
23
+ }
24
+ },
25
+ {
26
+ "type": "required_status_checks",
27
+ "parameters": {
28
+ "strict_required_status_checks_policy": true,
29
+ "do_not_enforce_on_create": false,
30
+ "required_status_checks": [{ "context": "ci-pass" }]
31
+ }
32
+ }
33
+ ],
34
+ "bypass_actors": [
35
+ { "actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always" }
36
+ ]
37
+ }
@@ -0,0 +1,110 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: ci-${{ github.ref }}
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ lint:
17
+ name: lint
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/setup-uv@v5
22
+ with:
23
+ enable-cache: true
24
+ - run: uv sync --all-extras
25
+ - run: uv run ruff check .
26
+ - run: uv run ruff format --check .
27
+ - run: uv run mypy
28
+
29
+ test:
30
+ name: test (${{ matrix.os }}, ${{ matrix.python }})
31
+ runs-on: ${{ matrix.os }}
32
+ strategy:
33
+ fail-fast: false
34
+ matrix:
35
+ include:
36
+ - { os: ubuntu-latest, python: "3.11" }
37
+ - { os: ubuntu-latest, python: "3.12" }
38
+ - { os: ubuntu-latest, python: "3.13" }
39
+ # Windows is the platform LabHarness is developed and demoed on.
40
+ - { os: windows-latest, python: "3.12" }
41
+ steps:
42
+ - uses: actions/checkout@v4
43
+ - uses: astral-sh/setup-uv@v5
44
+ with:
45
+ enable-cache: true
46
+ python-version: ${{ matrix.python }}
47
+ - run: uv sync --all-extras
48
+ - run: uv run pytest -m "not latex"
49
+
50
+ latex:
51
+ name: latex
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - uses: astral-sh/setup-uv@v5
56
+ with:
57
+ enable-cache: true
58
+ # Third-party actions are blocked for this repository, so TeX Live comes from apt
59
+ # instead of setup-texlive-action.
60
+ - name: Install TeX Live
61
+ run: |
62
+ sudo apt-get update
63
+ sudo apt-get install -y --no-install-recommends lmodern texlive-latex-recommended texlive-latex-extra texlive-science texlive-fonts-recommended
64
+ pdflatex --version | head -1
65
+ - run: uv sync --all-extras
66
+ - run: uv run pytest -m latex
67
+
68
+ # LaTeX on the platform the demo runs on. Slower than the Ubuntu job, so it only guards
69
+ # the document and diagram paths, which are the ones a Windows LaTeX install can break.
70
+ latex-windows:
71
+ name: latex-windows
72
+ runs-on: windows-latest
73
+ steps:
74
+ - uses: actions/checkout@v4
75
+ - uses: astral-sh/setup-uv@v5
76
+ with:
77
+ enable-cache: true
78
+ - name: Install MiKTeX and Perl
79
+ shell: pwsh
80
+ run: |
81
+ choco install miktex --no-progress -y
82
+ choco install strawberryperl --no-progress -y
83
+ $env:PATH = "C:\Program Files\MiKTeX\miktex\bin\x64;C:\Strawberry\perl\bin;$env:PATH"
84
+ echo "C:\Program Files\MiKTeX\miktex\bin\x64" >> $env:GITHUB_PATH
85
+ echo "C:\Strawberry\perl\bin" >> $env:GITHUB_PATH
86
+ initexmf --set-config-value "[MPM]AutoInstall=1"
87
+ - name: Report the environment
88
+ shell: pwsh
89
+ run: |
90
+ pdflatex --version | Select-Object -First 1
91
+ latexmk -v
92
+ - run: uv sync --all-extras
93
+ - run: uv run pytest -m latex
94
+
95
+ # Single required check: the ruleset references this name, so it stays stable
96
+ # however the matrix above changes.
97
+ ci-pass:
98
+ name: ci-pass
99
+ if: always()
100
+ needs: [lint, test, latex, latex-windows]
101
+ runs-on: ubuntu-latest
102
+ steps:
103
+ - name: Fail if any job did not succeed
104
+ run: |
105
+ echo "lint=${{ needs.lint.result }} test=${{ needs.test.result }}"
106
+ echo "latex=${{ needs.latex.result }} latex-windows=${{ needs.latex-windows.result }}"
107
+ [ "${{ needs.lint.result }}" = "success" ] || exit 1
108
+ [ "${{ needs.test.result }}" = "success" ] || exit 1
109
+ [ "${{ needs.latex.result }}" = "success" ] || exit 1
110
+ [ "${{ needs.latex-windows.result }}" = "success" ] || exit 1
@@ -0,0 +1,35 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .venv/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+
14
+ # LaTeX build artifacts
15
+ *.aux
16
+ *.bbl
17
+ *.blg
18
+ *.fdb_latexmk
19
+ *.fls
20
+ *.log
21
+ *.out
22
+ *.synctex.gz
23
+ *.toc
24
+
25
+ # Generated outputs of the example workspaces (rebuilt by `labharness build`)
26
+ examples/**/figures/*
27
+ !examples/**/figures/.gitkeep
28
+ examples/**/paper.pdf
29
+
30
+ # Editors and OS
31
+ .vscode/
32
+ .idea/
33
+ .DS_Store
34
+ Thumbs.db
35
+ acs-*.bib
@@ -0,0 +1,26 @@
1
+ # Fast checks only: the test suite runs in CI, not here.
2
+ # Install the hooks once with: uv run pre-commit install --install-hooks --hook-type commit-msg
3
+ repos:
4
+ - repo: https://github.com/pre-commit/pre-commit-hooks
5
+ rev: v6.0.0
6
+ hooks:
7
+ - id: trailing-whitespace
8
+ - id: end-of-file-fixer
9
+ - id: check-toml
10
+ - id: check-yaml
11
+ - id: check-added-large-files
12
+ - id: mixed-line-ending
13
+ args: [--fix=lf]
14
+
15
+ - repo: https://github.com/astral-sh/ruff-pre-commit
16
+ rev: v0.16.7
17
+ hooks:
18
+ - id: ruff
19
+ args: [--fix]
20
+ - id: ruff-format
21
+
22
+ - repo: https://github.com/compilerla/conventional-pre-commit
23
+ rev: v4.4.0
24
+ hooks:
25
+ - id: conventional-pre-commit
26
+ stages: [commit-msg]
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,46 @@
1
+ # Instructions for AI agents working on the LabHarness repository
2
+
3
+ LabHarness is a local-first Data-to-Paper harness: raw lab data in, publication-ready LaTeX
4
+ figures out. This file is for agents that **develop LabHarness itself**. The rules for agents
5
+ that write papers *with* LabHarness live in `templates/workspace/AGENTS.md`.
6
+
7
+ ## Non-negotiable
8
+
9
+ 1. **Never commit or push without explicit authorization from the maintainer (@AIAYN-creator),
10
+ every single time.** Prepare the change, show what would be committed, and wait.
11
+ 2. When an agent took part in a commit, add the trailer `Supervised-by: <agent name>`.
12
+ **Never** use `Co-Authored-By` for an agent.
13
+ 3. Design decisions are recorded as ADRs (`docs/adr/`). Do not contradict an accepted ADR;
14
+ if a change seems to require it, raise it with the maintainer instead.
15
+
16
+ ## Architecture rules
17
+
18
+ - `src/labharness/` holds the package: `core`, `style`, `watch`, `cli` and `modules/<domain>`.
19
+ - **The CLI and the watcher are thin consumers.** No figure logic lives in them.
20
+ - **The core must import without any extra installed.** Heavy dependencies (RDKit, SciPy,
21
+ Matplotlib, OPSIN, …) are imported lazily inside functions through `labharness.core.require`.
22
+ `tests/test_core.py` enforces it.
23
+ - Every module follows the contract described in `src/labharness/modules/__init__.py`:
24
+ - no printing and no `sys.argv` or `exit()`;
25
+ - no global state;
26
+ - atomic writes and deterministic output;
27
+ - no imports between modules, and only the public API of `core` and `style`.
28
+ - **Never hard-code fonts, sizes or colours in a module.** Everything comes from the shared
29
+ style: one typeface for the whole document.
30
+ - `templates/workspace/` is the researcher's workspace template, shipped inside the package.
31
+
32
+ ## Conventions
33
+
34
+ - Code, CLI messages and repository docs are in English.
35
+ - Commits follow Conventional Commits (`feat`, `fix`, `docs`, `refactor`, `test`, `ci`,
36
+ `chore`, `build`), optionally scoped by area, e.g. `feat(chem): …`.
37
+ - Paths with spaces and Windows are first-class: the maintainer develops on Windows.
38
+
39
+ ## Commands
40
+
41
+ ```
42
+ uv sync --all-extras
43
+ uv run pytest
44
+ ```
45
+
46
+ Linting, formatting and type checking are added with the CI setup.
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -0,0 +1,13 @@
1
+ # Code of Conduct
2
+
3
+ LabHarness adopts the [Contributor Covenant, version 3.0](https://www.contributor-covenant.org/version/3/0/code_of_conduct/)
4
+ as its code of conduct. It applies to every project space (issues, pull requests,
5
+ discussions) and to anyone representing the project.
6
+
7
+ ## Reporting
8
+
9
+ If you experience or witness behaviour that violates the code of conduct, please report it
10
+ privately to the maintainer, @AIAYN-creator, at labharness.project@gmail.com.
11
+
12
+ Reports are handled confidentially, following the Contributor Covenant's guidance on
13
+ addressing and repairing harm.
@@ -0,0 +1,55 @@
1
+ # Contributing to LabHarness
2
+
3
+ Thanks for your interest! **LabHarness is pre-alpha.** The repository is public, but external
4
+ contributions are not actively sought until the v1.0 release: issues are welcome, and pull requests
5
+ are considered case by case. This guide describes how contributions work.
6
+
7
+ ## Development setup
8
+
9
+ Requirements: Python ≥ 3.11, [uv](https://docs.astral.sh/uv/) and a LaTeX distribution
10
+ (MiKTeX or TeX Live). On Windows with MiKTeX, `latexmk` also needs Perl
11
+ (e.g. Strawberry Perl). Use a PDF viewer that does not lock files: SumatraPDF on Windows,
12
+ Skim on macOS.
13
+
14
+ ```
15
+ git clone https://github.com/AIAYN-creator/Lab-Harness.git
16
+ cd Lab-Harness
17
+ uv sync --all-extras
18
+ uv run pytest
19
+ ```
20
+
21
+ ## How changes get in
22
+
23
+ - **The maintainer** pushes to `main` directly, through the administrator bypass of the branch
24
+ ruleset.
25
+ - **Everyone else:**
26
+ 1. Open an issue first for anything beyond a small fix, so we can agree on the approach.
27
+ 2. Work on a short-lived branch and open a pull request against `main`.
28
+ 3. The pull request needs the `ci-pass` check to be green and an approval from the
29
+ maintainer (code owner). It is merged with squash.
30
+
31
+ ## Commit messages
32
+
33
+ We use [Conventional Commits](https://www.conventionalcommits.org/):
34
+
35
+ ```
36
+ feat(plots): add power-law fits
37
+ fix(watch): debounce double saves from VS Code on Windows
38
+ docs: explain the manifest format
39
+ ```
40
+
41
+ Types: `feat`, `fix`, `docs`, `refactor`, `test`, `ci`, `chore`, `build`.
42
+
43
+ ## Design rules
44
+
45
+ Please read [`AGENTS.md`](AGENTS.md). It applies to humans too. In short:
46
+
47
+ - modules are plain functions with no terminal I/O;
48
+ - the core imports without any extra;
49
+ - no hard-coded fonts, sizes or colours;
50
+ - larger design decisions are recorded as ADRs in [`docs/adr/`](docs/adr/).
51
+
52
+ ## Code of conduct
53
+
54
+ This project follows its [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you agree to
55
+ uphold it.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AIAYN-creator
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.