anma 0.5.5__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.
- anma-0.5.5/.claude/hooks/anma_pretooluse.py +18 -0
- anma-0.5.5/.claude/rules/boundaries.md +12 -0
- anma-0.5.5/.claude/settings.json +12 -0
- anma-0.5.5/.github/CODEOWNERS +3 -0
- anma-0.5.5/.github/workflows/anma.yml +13 -0
- anma-0.5.5/.github/workflows/ci.yml +38 -0
- anma-0.5.5/.github/workflows/release.yml +45 -0
- anma-0.5.5/.gitignore +28 -0
- anma-0.5.5/.pre-commit-config.yaml +9 -0
- anma-0.5.5/CHANGELOG.md +123 -0
- anma-0.5.5/CLAUDE.md +61 -0
- anma-0.5.5/CONTRIBUTING.md +58 -0
- anma-0.5.5/DECISIONS.md +8 -0
- anma-0.5.5/LICENSE +200 -0
- anma-0.5.5/PKG-INFO +132 -0
- anma-0.5.5/README.md +113 -0
- anma-0.5.5/RELEASE.md +103 -0
- anma-0.5.5/SECURITY.md +34 -0
- anma-0.5.5/anma/CLAUDE.md +21 -0
- anma-0.5.5/anma/__init__.py +2 -0
- anma-0.5.5/anma/anma.yaml +15 -0
- anma-0.5.5/anma/cli.py +130 -0
- anma-0.5.5/anma/compile.py +185 -0
- anma-0.5.5/anma/contracts.py +167 -0
- anma-0.5.5/anma/engine.py +158 -0
- anma-0.5.5/anma/hook.py +105 -0
- anma-0.5.5/anma/scaffold.py +68 -0
- anma-0.5.5/anma/templates.py +127 -0
- anma-0.5.5/anma.yaml +8 -0
- anma-0.5.5/benchmarks/README.md +74 -0
- anma-0.5.5/benchmarks/bench/__init__.py +0 -0
- anma-0.5.5/benchmarks/bench/report.py +87 -0
- anma-0.5.5/benchmarks/bench/run.py +78 -0
- anma-0.5.5/benchmarks/bench/runner.py +117 -0
- anma-0.5.5/benchmarks/bench/scorer.py +80 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/.claude/hooks/anma_pretooluse.py +18 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/.claude/rules/boundaries.md +12 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/.claude/settings.json +12 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/.github/workflows/anma.yml +13 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/.pre-commit-config.yaml +9 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/CLAUDE.md +22 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/DECISIONS.md +8 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/anma.yaml +3 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/accounts/CLAUDE.md +17 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/accounts/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/accounts/anma.yaml +9 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/accounts/service.py +9 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/billing/CLAUDE.md +15 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/billing/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/billing/anma.yaml +5 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/src/domains/billing/service.py +5 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/anma/tach.toml +15 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/boundaries.yaml +10 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/control/README.md +2 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/control/src/domains/accounts/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/control/src/domains/accounts/service.py +9 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/control/src/domains/billing/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/control/src/domains/billing/service.py +5 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/replay/anma/src/domains/accounts/service.py +13 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/replay/control/src/domains/accounts/service.py +13 -0
- anma-0.5.5/benchmarks/scenarios/cross-session-persistence/task.md +6 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/.claude/hooks/anma_pretooluse.py +18 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/.claude/rules/boundaries.md +12 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/.claude/settings.json +12 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/.github/workflows/anma.yml +13 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/.pre-commit-config.yaml +9 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/CLAUDE.md +22 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/DECISIONS.md +8 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/anma.yaml +3 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/inventory/CLAUDE.md +15 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/inventory/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/inventory/anma.yaml +5 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/inventory/service.py +6 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/orders/CLAUDE.md +15 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/orders/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/orders/anma.yaml +7 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/src/domains/orders/service.py +4 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/anma/tach.toml +15 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/boundaries.yaml +11 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/control/README.md +4 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/control/src/domains/inventory/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/control/src/domains/inventory/service.py +6 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/control/src/domains/orders/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/control/src/domains/orders/service.py +4 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/replay/anma/src/domains/orders/service.py +9 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/replay/control/src/domains/orders/service.py +6 -0
- anma-0.5.5/benchmarks/scenarios/orders-inventory/task.md +4 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/.claude/hooks/anma_pretooluse.py +18 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/.claude/rules/boundaries.md +12 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/.claude/settings.json +12 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/.github/workflows/anma.yml +13 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/.pre-commit-config.yaml +9 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/CLAUDE.md +22 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/DECISIONS.md +8 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/anma.yaml +3 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/accounts/CLAUDE.md +16 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/accounts/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/accounts/anma.yaml +8 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/accounts/service.py +4 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/billing/CLAUDE.md +16 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/billing/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/billing/anma.yaml +6 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/src/domains/billing/service.py +9 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/anma/tach.toml +15 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/boundaries.yaml +10 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/control/README.md +4 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/control/src/domains/accounts/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/control/src/domains/accounts/service.py +4 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/control/src/domains/billing/__init__.py +0 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/control/src/domains/billing/service.py +9 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/replay/anma/src/domains/accounts/service.py +9 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/replay/control/src/domains/accounts/service.py +9 -0
- anma-0.5.5/benchmarks/scenarios/payments-boundary/task.md +4 -0
- anma-0.5.5/benchmarks/tests/test_harness.py +130 -0
- anma-0.5.5/docs/BENCHMARKS.md +137 -0
- anma-0.5.5/docs/CONCEPTS.md +96 -0
- anma-0.5.5/docs/QUICKSTART.md +95 -0
- anma-0.5.5/pyproject.toml +31 -0
- anma-0.5.5/tach.toml +8 -0
- anma-0.5.5/tests/test_core.py +260 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""ANMA PreToolUse hook (generated). Exit code 2 blocks the tool call.
|
|
3
|
+
|
|
4
|
+
Thin shim: the real logic lives in `anma.hook`, so it is tested and upgradable
|
|
5
|
+
via `pip install -U anma` without re-running `anma sync`. Fails OPEN (allows the
|
|
6
|
+
edit) with a warning if anma is not importable, so a missing install never blocks
|
|
7
|
+
your work — CI and pre-commit remain the hard gate.
|
|
8
|
+
"""
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from anma.hook import run_hook
|
|
13
|
+
except Exception:
|
|
14
|
+
sys.stderr.write("ANMA hook: `anma` not importable in this environment; "
|
|
15
|
+
"skipping in-session check (CI/pre-commit still enforce).\n")
|
|
16
|
+
sys.exit(0)
|
|
17
|
+
|
|
18
|
+
sys.exit(run_hook(sys.stdin.read()))
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!-- Generated by `anma sync`. -->
|
|
2
|
+
# Module boundaries (ANMA)
|
|
3
|
+
|
|
4
|
+
IMPORTANT: This repo enforces module boundaries. Before adding any import
|
|
5
|
+
between modules, confirm it is allowed in the source module's `anma.yaml`
|
|
6
|
+
(`depends_on`). Cross-module access must go through the target module's public
|
|
7
|
+
interface — never its internals.
|
|
8
|
+
|
|
9
|
+
To change a boundary: edit the module's `anma.yaml`, run `anma sync`, and add a
|
|
10
|
+
one-line entry to `DECISIONS.md`. Do not work around the boundary in code.
|
|
11
|
+
|
|
12
|
+
Verify with: `anma check`
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Generated by `anma sync`.
|
|
2
|
+
name: anma
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
jobs:
|
|
5
|
+
boundaries:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
steps:
|
|
8
|
+
- uses: actions/checkout@v4
|
|
9
|
+
- uses: actions/setup-python@v5
|
|
10
|
+
with: { python-version: "3.10" }
|
|
11
|
+
- run: pip install anma[tach]
|
|
12
|
+
- run: anma sync --check # fail if generated docs/config drifted from contracts
|
|
13
|
+
- run: anma check # enforce module boundaries
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
on: [push, pull_request]
|
|
3
|
+
|
|
4
|
+
jobs:
|
|
5
|
+
test:
|
|
6
|
+
runs-on: ubuntu-latest
|
|
7
|
+
strategy:
|
|
8
|
+
matrix:
|
|
9
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: actions/setup-python@v5
|
|
13
|
+
with:
|
|
14
|
+
python-version: ${{ matrix.python-version }}
|
|
15
|
+
- run: pip install -e .[dev]
|
|
16
|
+
- run: python -m pytest tests/ -q
|
|
17
|
+
|
|
18
|
+
audit:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.12"
|
|
25
|
+
- run: python -m pip install --upgrade pip
|
|
26
|
+
- run: pip install -e .[dev]
|
|
27
|
+
- run: pip-audit --skip-editable
|
|
28
|
+
|
|
29
|
+
dogfood:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
- uses: actions/setup-python@v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: "3.12"
|
|
36
|
+
- run: pip install -e .
|
|
37
|
+
- run: anma sync --check .
|
|
38
|
+
- run: anma check .
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: write # attach SBOM to the release
|
|
8
|
+
id-token: write # OIDC for PyPI Trusted Publishing + attestations
|
|
9
|
+
attestations: write # build provenance
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build-and-publish:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
environment: pypi
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
|
|
21
|
+
- name: Build distributions
|
|
22
|
+
run: |
|
|
23
|
+
pip install build
|
|
24
|
+
python -m build
|
|
25
|
+
|
|
26
|
+
- name: Generate CycloneDX SBOM
|
|
27
|
+
run: |
|
|
28
|
+
pip install cyclonedx-bom
|
|
29
|
+
cyclonedx-py environment --output-format JSON --output-file sbom.json
|
|
30
|
+
|
|
31
|
+
- name: Attest build provenance
|
|
32
|
+
uses: actions/attest-build-provenance@v1
|
|
33
|
+
with:
|
|
34
|
+
subject-path: "dist/*"
|
|
35
|
+
|
|
36
|
+
- name: Attach SBOM to the GitHub release
|
|
37
|
+
uses: softprops/action-gh-release@v2
|
|
38
|
+
with:
|
|
39
|
+
files: sbom.json
|
|
40
|
+
|
|
41
|
+
# No API token: OIDC Trusted Publishing. Configure the publisher on PyPI.
|
|
42
|
+
- name: Publish to PyPI
|
|
43
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
44
|
+
with:
|
|
45
|
+
packages-dir: dist/
|
anma-0.5.5/.gitignore
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
|
|
11
|
+
# Test / tooling caches
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.mypy_cache/
|
|
14
|
+
.tox/
|
|
15
|
+
.coverage
|
|
16
|
+
htmlcov/
|
|
17
|
+
|
|
18
|
+
# ANMA benchmark outputs (generated by `python -m bench.run`)
|
|
19
|
+
benchmarks/results/
|
|
20
|
+
|
|
21
|
+
# Local Claude Code project memory (never commit)
|
|
22
|
+
CLAUDE.local.md
|
|
23
|
+
|
|
24
|
+
# OS / editor
|
|
25
|
+
.DS_Store
|
|
26
|
+
*.swp
|
|
27
|
+
.idea/
|
|
28
|
+
.vscode/
|
anma-0.5.5/CHANGELOG.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to ANMA are documented here. Format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/); the **contract schema**
|
|
5
|
+
(`schema_version`) is versioned independently of the tool — see
|
|
6
|
+
[docs/CONCEPTS.md](docs/CONCEPTS.md#stability).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.5.5] — 2026-06-06
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- The generated CI workflow (`.github/workflows/anma.yml`) is now **seed-once and
|
|
14
|
+
not drift-checked**, like `settings.json` and `.pre-commit-config.yaml`. It is a
|
|
15
|
+
starting point users customize (e.g. the install path), so regenerating and
|
|
16
|
+
drift-checking it was wrong — a hand-edited CI file no longer fails
|
|
17
|
+
`anma sync --check`.
|
|
18
|
+
|
|
19
|
+
## [0.5.4] — 2026-06-06
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Documentation rewritten around the first hardened result (Claude Haiku 4.5,
|
|
23
|
+
`payments-boundary`, n=20: control 13/19 violations vs ANMA 0/20,
|
|
24
|
+
Fisher `p < 0.0001`). README, QUICKSTART, CONCEPTS, and BENCHMARKS now lead with
|
|
25
|
+
the evidence-backed, two-tier positioning — ANMA as insurance for cheaper agents
|
|
26
|
+
plus a CI/governance guarantee — and explicitly separate the benchmarked
|
|
27
|
+
*guidance* win from the separately-verified *enforcement* hook. The frontier
|
|
28
|
+
(Opus 4.8) null result is published rather than hidden.
|
|
29
|
+
|
|
30
|
+
## [0.5.3] — 2026-06-06
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- `--scenario NAME` filter on the benchmark runner (repeatable) so a focused run
|
|
34
|
+
(e.g. 20 trials on one scenario) doesn't spend tokens on the whole suite.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- `docs/BENCHMARKS.md` rewritten around the first real results: a two-tier
|
|
38
|
+
finding (frontier models respect documented architecture unaided; cheaper
|
|
39
|
+
models violate routinely and ANMA drives that to zero), with the enforcement
|
|
40
|
+
layer verified by a direct hook test. Positions ANMA as insurance for cheaper
|
|
41
|
+
agents plus a CI/governance guarantee, and publishes the frontier null result.
|
|
42
|
+
|
|
43
|
+
## [0.5.2] — 2026-06-06
|
|
44
|
+
|
|
45
|
+
Follow-ups from the second live run (which showed the harness mis-attributing a
|
|
46
|
+
control-arm permission denial as an ANMA hook block, and both arms tying at 0
|
|
47
|
+
violations because a strong model passed the easy scenarios).
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
- Harness attributes hook blocks to ANMA **only when the ANMA hook is installed**
|
|
51
|
+
in that arm; the control arm now reports `—` for hook blocks instead of a
|
|
52
|
+
misleading count.
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
- `orders-inventory` adversarial scenario: the easy implementation crosses the
|
|
56
|
+
forbidden `orders → inventory` boundary and the correct path (caller-injected
|
|
57
|
+
callback) is non-obvious — designed so a capable model tends to slip in the
|
|
58
|
+
control arm, giving ANMA something to prevent.
|
|
59
|
+
|
|
60
|
+
## [0.5.1] — 2026-06-06
|
|
61
|
+
|
|
62
|
+
Fixes from the first live `claude-code` benchmark run, which surfaced two real
|
|
63
|
+
enforcement bugs and a harness that mis-scored blocked runs.
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
- **Hook now judges the proposed edit, not the project's current state.** The
|
|
67
|
+
PreToolUse hook reconstructs the post-edit content and blocks (exit 2) only
|
|
68
|
+
when *that edit* introduces a new disallowed import. This fixes a deadlock
|
|
69
|
+
(a project red for any reason blocked every edit, including the fix) and makes
|
|
70
|
+
the headline claim true (a violating edit is blocked as it is made, not on the
|
|
71
|
+
next edit). Hook logic moved into the package (`anma.hook`) so it is tested and
|
|
72
|
+
upgradable via `pip install -U`; the generated hook is a thin shim that fails
|
|
73
|
+
open with a warning if `anma` isn't importable.
|
|
74
|
+
- **`anma sync` now qualifies `public` interface paths** to the module's import
|
|
75
|
+
path in `tach.toml` (e.g. `accounts.service.get_user` →
|
|
76
|
+
`domains.accounts.service.get_user`). Previously these were emitted verbatim,
|
|
77
|
+
so `tach check` failed out of the box for any module nested under a source
|
|
78
|
+
root. (The single-module-at-root dogfood had masked this.)
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
- Benchmark harness parses `claude --output-format json`: real `num_turns`, hook
|
|
82
|
+
blocks counted from `permission_denials`, and a per-trial `status`
|
|
83
|
+
(`ok`/`no_change`/`error`). Runs that changed no code or errored are flagged
|
|
84
|
+
and excluded from violation scoring, so an incomplete run can no longer be read
|
|
85
|
+
as a clean pass.
|
|
86
|
+
|
|
87
|
+
## [0.5.0] — 2026-06-05
|
|
88
|
+
|
|
89
|
+
Ground-up rewrite around a single goal: *with ANMA, Claude Code makes fewer
|
|
90
|
+
architectural mistakes, preserves architecture across sessions, respects module
|
|
91
|
+
boundaries, and coordinates parallel work better than a normal repo.* The
|
|
92
|
+
previous "7 principles / 24 linter checks" framing is gone; ANMA is now a thin
|
|
93
|
+
layer over Claude Code's native memory + hooks plus a real boundary engine.
|
|
94
|
+
|
|
95
|
+
### Added
|
|
96
|
+
- `anma sync --check` — drift detection; fails if generated artifacts no longer
|
|
97
|
+
match the contracts (for CI).
|
|
98
|
+
- `anma check --warn` and per-module `deprecated_deps` — incremental adoption
|
|
99
|
+
without a red build on day one.
|
|
100
|
+
- `anma check --json` — machine-readable output, with documented exit codes.
|
|
101
|
+
- Monorepo support via `source_roots:` (multiple roots).
|
|
102
|
+
- `schema_version` with a SemVer stability promise; contracts newer than the
|
|
103
|
+
tool are rejected rather than misread.
|
|
104
|
+
- `owners:` per module → generated `.github/CODEOWNERS`.
|
|
105
|
+
- `exclude:` in project config plus a default-ignore set (`node_modules`,
|
|
106
|
+
`.venv`, build dirs, …) so discovery skips non-source trees.
|
|
107
|
+
- Security model + disclosure policy (`SECURITY.md`), a signed-release pipeline
|
|
108
|
+
(PyPI Trusted Publishing + build-provenance attestations + CycloneDX SBOM),
|
|
109
|
+
and `pip-audit` in CI.
|
|
110
|
+
- A reproducible benchmark harness (`benchmarks/`) with an independent violation
|
|
111
|
+
scorer and a deterministic replay mode; scenarios for the boundary and
|
|
112
|
+
cross-session-persistence goals.
|
|
113
|
+
- ANMA dogfoods itself: the repo carries its own contracts, enforced in CI.
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
- Single source of truth: contracts compile to `CLAUDE.md`, nested `CLAUDE.md`,
|
|
117
|
+
rules, the PreToolUse hook, `tach.toml`, and CI.
|
|
118
|
+
- Boundary engine is swappable: `tach` (default, interface-aware) with a
|
|
119
|
+
zero-dependency builtin `ast` fallback.
|
|
120
|
+
- Apache-2.0; the published wheel ships only the `anma` package.
|
|
121
|
+
|
|
122
|
+
### Removed
|
|
123
|
+
- The "7 architectural principles" and the legacy multi-check linter.
|
anma-0.5.5/CLAUDE.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# anma
|
|
2
|
+
|
|
3
|
+
ANMA turns per-module `anma.yaml` contracts into the artifacts that keep Claude
|
|
4
|
+
Code inside module boundaries: a generated architecture map, nested `CLAUDE.md`
|
|
5
|
+
files, a PreToolUse hook, and a boundary-check engine. Contracts are the single
|
|
6
|
+
source of truth — never hand-edit generated files.
|
|
7
|
+
|
|
8
|
+
## Commands
|
|
9
|
+
- `pip install -e .[dev]` — install with pytest
|
|
10
|
+
- `python -m pytest tests/ -q` — run tests (keep them green before commits)
|
|
11
|
+
- `anma sync .` — regenerate all artifacts after editing any `anma.yaml`
|
|
12
|
+
- `anma check .` — enforce boundaries (also runs in CI and the pre-commit hook)
|
|
13
|
+
|
|
14
|
+
## Internal architecture
|
|
15
|
+
This package is intentionally small (~650 LOC). The internal dependency
|
|
16
|
+
direction is strict — lower layers must NOT import higher ones:
|
|
17
|
+
|
|
18
|
+
contracts.py leaf: load + validate contracts (no internal imports)
|
|
19
|
+
templates.py leaf: generated-artifact strings (no internal imports)
|
|
20
|
+
scaffold.py leaf: `anma init` example (no internal imports)
|
|
21
|
+
engine.py depends on: contracts (tach adapter + builtin checker)
|
|
22
|
+
compile.py depends on: contracts, templates (renders all artifacts)
|
|
23
|
+
cli.py depends on: all of the above (orchestrator / entry point)
|
|
24
|
+
|
|
25
|
+
INVARIANT: core (`contracts`, `engine`, `compile`, `templates`, `scaffold`)
|
|
26
|
+
must never import `cli`. `cli` is the only place argparse and I/O wiring live.
|
|
27
|
+
|
|
28
|
+
INVARIANT: `tach` is optional. `engine.py` must keep working with zero extra
|
|
29
|
+
dependencies via the builtin `ast` checker. Never make tach a hard import.
|
|
30
|
+
|
|
31
|
+
## What not to edit by hand (generated by `anma sync`)
|
|
32
|
+
- the `ANMA:MAP` block below
|
|
33
|
+
- `anma/CLAUDE.md`, `.claude/rules/`, `.claude/hooks/`, `tach.toml`,
|
|
34
|
+
`.github/workflows/anma.yml`
|
|
35
|
+
To change behavior, edit a contract or `anma/templates.py`, then re-sync.
|
|
36
|
+
|
|
37
|
+
## Dogfooding note (known limitation)
|
|
38
|
+
ANMA currently models a "module" as a *directory* with an `anma.yaml`. This
|
|
39
|
+
package is a single flat module, so `anma check` enforces the *workflow* here
|
|
40
|
+
(generated CLAUDE.md + green CI) but cannot yet enforce the internal layering
|
|
41
|
+
above — that needs file/layer-level modules. Tracked as the next core feature;
|
|
42
|
+
it also matters for enterprise layered-monolith packages.
|
|
43
|
+
|
|
44
|
+
<!-- ANMA:MAP:START -->
|
|
45
|
+
## Architecture map (generated by `anma sync` — do not edit by hand)
|
|
46
|
+
|
|
47
|
+
This project uses ANMA contracts. **Respect these module boundaries.** A module
|
|
48
|
+
may only import from modules listed under "uses". Going outside that is blocked
|
|
49
|
+
by a pre-commit hook and CI.
|
|
50
|
+
|
|
51
|
+
- **anma** — The ANMA tool itself — contracts compile to CLAUDE.md, hooks, and a boundary engine.
|
|
52
|
+
uses: (nothing)
|
|
53
|
+
|
|
54
|
+
**Rules**
|
|
55
|
+
- Import other modules only through their public interface (listed in each
|
|
56
|
+
module's own `CLAUDE.md`). Do not reach into a module's internals.
|
|
57
|
+
- If you need a dependency that isn't allowed, do not add the import. Update the
|
|
58
|
+
source module's `anma.yaml` (`depends_on`), run `anma sync`, and record why in
|
|
59
|
+
`DECISIONS.md` — then the boundary is real and persists to the next session.
|
|
60
|
+
- Run `anma check` before committing. It also runs in CI.
|
|
61
|
+
<!-- ANMA:MAP:END -->
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
ANMA is deliberately small (~780 lines). The bar for new code is high: prefer
|
|
4
|
+
making the existing primitives sharper over adding surface area. If a change
|
|
5
|
+
grows the tool a lot, it probably belongs in a plugin or a separate scenario, not
|
|
6
|
+
the core.
|
|
7
|
+
|
|
8
|
+
## Dev setup
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
git clone https://github.com/anma-labs/anma
|
|
12
|
+
cd anma
|
|
13
|
+
pip install -e .[dev] # pytest + pip-audit; add [tach] for the tach engine
|
|
14
|
+
python -m pytest tests/ -q
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## ANMA dogfoods itself
|
|
18
|
+
|
|
19
|
+
The repo carries its own contracts, so the same checks you ship run here:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
anma sync --check . # generated docs/config are current with the contracts
|
|
23
|
+
anma check . # internal boundaries respected
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Both must pass before a PR merges (CI enforces them in the `dogfood` job).
|
|
27
|
+
|
|
28
|
+
## PR checklist
|
|
29
|
+
|
|
30
|
+
- [ ] `python -m pytest tests/ -q` green (and `benchmarks/` tests if you touched the harness)
|
|
31
|
+
- [ ] `anma sync --check .` and `anma check .` clean — if you changed a contract or a template, re-run `anma sync .` and commit the regenerated files
|
|
32
|
+
- [ ] `pip-audit` clean
|
|
33
|
+
- [ ] New behavior has a test; new contract fields are documented in `docs/CONCEPTS.md`
|
|
34
|
+
- [ ] `CHANGELOG.md` updated under "Unreleased"
|
|
35
|
+
|
|
36
|
+
## The schema-stability rule (read before touching contracts)
|
|
37
|
+
|
|
38
|
+
The contract schema is ANMA's real public API — users commit to it. Treat it like
|
|
39
|
+
one:
|
|
40
|
+
|
|
41
|
+
- Adding an **optional** field with a safe default is a minor change.
|
|
42
|
+
- Removing or renaming a field, changing a field's meaning, or making a field
|
|
43
|
+
required is a **breaking** change: bump `SUPPORTED_SCHEMA` in
|
|
44
|
+
`anma/contracts.py`, bump the tool's major version, and ship a migration path.
|
|
45
|
+
- Never make the tool silently reinterpret existing contracts.
|
|
46
|
+
|
|
47
|
+
## Code shape
|
|
48
|
+
|
|
49
|
+
- Keep `cli.py` as the only place argparse/IO wiring lives; core modules
|
|
50
|
+
(`contracts`, `engine`, `compile`, `templates`, `scaffold`) must not import it.
|
|
51
|
+
- `tach` stays optional — `engine.py` must keep working via the builtin checker
|
|
52
|
+
with zero extra dependencies.
|
|
53
|
+
- Generated artifacts are produced by pure `render_*` functions in `compile.py`
|
|
54
|
+
so `anma sync` and `anma sync --check` share one code path. Keep them pure.
|
|
55
|
+
|
|
56
|
+
## Reporting security issues
|
|
57
|
+
|
|
58
|
+
See [SECURITY.md](SECURITY.md) — do not open public issues for vulnerabilities.
|
anma-0.5.5/DECISIONS.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Architecture decisions (ANMA)
|
|
2
|
+
|
|
3
|
+
Append-only. Each entry explains *why* a boundary is the way it is, so neither
|
|
4
|
+
you nor Claude relitigates it next session. Newest on top.
|
|
5
|
+
|
|
6
|
+
## 2026-06-05 — Adopted ANMA contracts
|
|
7
|
+
Module boundaries are now declared in per-module `anma.yaml` files and enforced
|
|
8
|
+
by `anma check` (pre-commit + CI + Claude Code PreToolUse hook).
|
anma-0.5.5/LICENSE
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to the Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding any notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. Please also get an approval
|
|
186
|
+
for your intended use before applyting the License.
|
|
187
|
+
|
|
188
|
+
Copyright 2026 ANMA Labs LLC
|
|
189
|
+
|
|
190
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
191
|
+
you may not use this file except in compliance with the License.
|
|
192
|
+
You may obtain a copy of the License at
|
|
193
|
+
|
|
194
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
195
|
+
|
|
196
|
+
Unless required by applicable law or agreed to in writing, software
|
|
197
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
198
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
199
|
+
See the License for the specific language governing permissions and
|
|
200
|
+
limitations under the License.
|