ai-agent-ledger-py 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. ai_agent_ledger_py-0.2.1/.github/ISSUE_TEMPLATE/bug_report.yml +69 -0
  2. ai_agent_ledger_py-0.2.1/.github/ISSUE_TEMPLATE/config.yml +11 -0
  3. ai_agent_ledger_py-0.2.1/.github/ISSUE_TEMPLATE/feature_request.yml +61 -0
  4. ai_agent_ledger_py-0.2.1/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  5. ai_agent_ledger_py-0.2.1/.github/workflows/ci.yml +128 -0
  6. ai_agent_ledger_py-0.2.1/.github/workflows/release.yml +105 -0
  7. ai_agent_ledger_py-0.2.1/.gitignore +147 -0
  8. ai_agent_ledger_py-0.2.1/CHANGELOG.md +602 -0
  9. ai_agent_ledger_py-0.2.1/CODE_OF_CONDUCT.md +124 -0
  10. ai_agent_ledger_py-0.2.1/CONTRIBUTING.md +169 -0
  11. ai_agent_ledger_py-0.2.1/LICENSE +201 -0
  12. ai_agent_ledger_py-0.2.1/PKG-INFO +546 -0
  13. ai_agent_ledger_py-0.2.1/README.md +513 -0
  14. ai_agent_ledger_py-0.2.1/README.zh-CN.md +417 -0
  15. ai_agent_ledger_py-0.2.1/SECURITY.md +76 -0
  16. ai_agent_ledger_py-0.2.1/docs/DESIGN.md +204 -0
  17. ai_agent_ledger_py-0.2.1/pyproject.toml +107 -0
  18. ai_agent_ledger_py-0.2.1/src/agent_ledger/__init__.py +204 -0
  19. ai_agent_ledger_py-0.2.1/src/agent_ledger/__main__.py +14 -0
  20. ai_agent_ledger_py-0.2.1/src/agent_ledger/_identity.py +27 -0
  21. ai_agent_ledger_py-0.2.1/src/agent_ledger/a2a.py +1058 -0
  22. ai_agent_ledger_py-0.2.1/src/agent_ledger/adapters.py +369 -0
  23. ai_agent_ledger_py-0.2.1/src/agent_ledger/ard.py +402 -0
  24. ai_agent_ledger_py-0.2.1/src/agent_ledger/bundle.py +400 -0
  25. ai_agent_ledger_py-0.2.1/src/agent_ledger/cli.py +780 -0
  26. ai_agent_ledger_py-0.2.1/src/agent_ledger/conform.py +745 -0
  27. ai_agent_ledger_py-0.2.1/src/agent_ledger/demo.py +634 -0
  28. ai_agent_ledger_py-0.2.1/src/agent_ledger/ledger.py +1401 -0
  29. ai_agent_ledger_py-0.2.1/src/agent_ledger/matcher.py +343 -0
  30. ai_agent_ledger_py-0.2.1/src/agent_ledger/models.py +834 -0
  31. ai_agent_ledger_py-0.2.1/src/agent_ledger/otlp.py +356 -0
  32. ai_agent_ledger_py-0.2.1/src/agent_ledger/policy.py +249 -0
  33. ai_agent_ledger_py-0.2.1/src/agent_ledger/py.typed +0 -0
  34. ai_agent_ledger_py-0.2.1/src/agent_ledger/render.py +196 -0
  35. ai_agent_ledger_py-0.2.1/src/agent_ledger/router.py +600 -0
  36. ai_agent_ledger_py-0.2.1/src/agent_ledger/signing.py +553 -0
  37. ai_agent_ledger_py-0.2.1/tests/__init__.py +5 -0
  38. ai_agent_ledger_py-0.2.1/tests/conftest.py +87 -0
  39. ai_agent_ledger_py-0.2.1/tests/test_a2a.py +545 -0
  40. ai_agent_ledger_py-0.2.1/tests/test_a2a_streaming.py +431 -0
  41. ai_agent_ledger_py-0.2.1/tests/test_adapters_and_otlp.py +499 -0
  42. ai_agent_ledger_py-0.2.1/tests/test_ard.py +295 -0
  43. ai_agent_ledger_py-0.2.1/tests/test_bundle.py +340 -0
  44. ai_agent_ledger_py-0.2.1/tests/test_cli_and_demo.py +287 -0
  45. ai_agent_ledger_py-0.2.1/tests/test_conform.py +372 -0
  46. ai_agent_ledger_py-0.2.1/tests/test_keyring.py +334 -0
  47. ai_agent_ledger_py-0.2.1/tests/test_ledger_and_grid.py +720 -0
  48. ai_agent_ledger_py-0.2.1/tests/test_ledger_backend.py +479 -0
  49. ai_agent_ledger_py-0.2.1/tests/test_ledger_integrity.py +854 -0
  50. ai_agent_ledger_py-0.2.1/tests/test_matching_and_policy.py +381 -0
  51. ai_agent_ledger_py-0.2.1/tests/test_models.py +267 -0
  52. ai_agent_ledger_py-0.2.1/tests/test_signing.py +850 -0
  53. ai_agent_ledger_py-0.2.1/tools/audit_dist.py +128 -0
  54. ai_agent_ledger_py-0.2.1/tools/check_readme.py +204 -0
@@ -0,0 +1,69 @@
1
+ name: Bug report
2
+ description: Something behaved differently from what the documentation says.
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for taking the time. Two things make a bug report far easier to act on:
9
+
10
+ 1. The output of `al demo` — it exercises the real code paths end to end.
11
+ 2. If the problem is about *routing* (the wrong agent chosen, or none chosen),
12
+ the candidate list from `grid.candidates(task)`. Every signal is kept
13
+ visible precisely so routing can be diagnosed without guesswork.
14
+
15
+ - type: textarea
16
+ id: what-happened
17
+ attributes:
18
+ label: What happened
19
+ description: What you observed, and what you expected instead.
20
+ validations:
21
+ required: true
22
+
23
+ - type: textarea
24
+ id: reproduce
25
+ attributes:
26
+ label: Steps to reproduce
27
+ description: A minimal script or command sequence. If it needs a registry, describe the response shape rather than a private URL.
28
+ placeholder: |
29
+ 1. `al demo`
30
+ 2. ...
31
+ validations:
32
+ required: true
33
+
34
+ - type: textarea
35
+ id: traceback
36
+ attributes:
37
+ label: Full traceback or output
38
+ description: Paste it verbatim. Do not trim the middle — the frame that matters is often the one that looks irrelevant.
39
+ render: shell
40
+ validations:
41
+ required: false
42
+
43
+ - type: input
44
+ id: version
45
+ attributes:
46
+ label: Version
47
+ description: Output of `al --version`.
48
+ validations:
49
+ required: true
50
+
51
+ - type: input
52
+ id: python
53
+ attributes:
54
+ label: Python and OS
55
+ placeholder: "3.12.1 on Windows 11 / 3.11.7 on Ubuntu 24.04"
56
+ validations:
57
+ required: true
58
+
59
+ - type: checkboxes
60
+ id: integrity
61
+ attributes:
62
+ label: If this is about receipts, verification or the ledger
63
+ description: |
64
+ Known and already documented — please check these before filing, so the
65
+ issue tracker stays useful. `docs/DESIGN.md` has the honest limitations
66
+ list, and `SECURITY.md` repeats it as a table of what is already known.
67
+ options:
68
+ - label: I read the Limitations section of docs/DESIGN.md and this is not one of them.
69
+ required: false
@@ -0,0 +1,11 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/yaoyuxiang-gnn/agent-ledger/security/advisories/new
5
+ about: Report privately. Do not open a public issue for anything exploitable.
6
+ - name: Question or idea
7
+ url: https://github.com/yaoyuxiang-gnn/agent-ledger/discussions
8
+ about: For "how do I…" and design discussion, which is not an issue.
9
+ - name: Known limitations
10
+ url: https://github.com/yaoyuxiang-gnn/agent-ledger/blob/main/docs/DESIGN.md
11
+ about: What each layer does and does not prove, and what is deliberately not built yet. Check here first.
@@ -0,0 +1,61 @@
1
+ name: Feature request
2
+ description: Propose a change in behaviour, an adapter, or an integration.
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Before filing, `CONTRIBUTING.md` has a "What would help most" list, and
9
+ `docs/DESIGN.md` has the honest limitations. If your idea is already on
10
+ either, a comment there is more useful than a new issue.
11
+
12
+ Two constraints shape what can be merged, and proposals that respect them
13
+ move much faster:
14
+
15
+ - **Zero runtime dependencies.** The `dependencies` list must stay empty;
16
+ a CI job fails the build if it does not. Optional extras are fine —
17
+ `[sign]` is the expected shape for anything that needs a library.
18
+ - **Denials stay data.** A refusal is a `PolicyDecision`, not an exception.
19
+
20
+ - type: textarea
21
+ id: problem
22
+ attributes:
23
+ label: What problem does this solve
24
+ description: Describe the situation you are in, not the API you want. The API is usually easier to get right once the problem is clear.
25
+ validations:
26
+ required: true
27
+
28
+ - type: textarea
29
+ id: proposal
30
+ attributes:
31
+ label: What you propose
32
+ validations:
33
+ required: true
34
+
35
+ - type: dropdown
36
+ id: area
37
+ attributes:
38
+ label: Area
39
+ multiple: true
40
+ options:
41
+ - Discovery (ARD)
42
+ - Matching and reputation
43
+ - Policy
44
+ - Delegation and receipts
45
+ - Ledger and storage
46
+ - Execution / A2A executor
47
+ - CLI
48
+ - Docs
49
+ - Other
50
+ validations:
51
+ required: true
52
+
53
+ - type: checkboxes
54
+ id: constraints
55
+ attributes:
56
+ label: Constraints
57
+ options:
58
+ - label: This can be done without adding a runtime dependency (or as an opt-in extra).
59
+ required: false
60
+ - label: I am willing to open a pull request for this.
61
+ required: false
@@ -0,0 +1,42 @@
1
+ ## What this changes
2
+
3
+ <!-- One or two sentences. If it fixes an issue, link it. -->
4
+
5
+ ## Why
6
+
7
+ <!-- The problem, not the patch. What goes wrong today? -->
8
+
9
+ ## Breaking changes
10
+
11
+ <!--
12
+ Receipt digests are deterministic on purpose. If you changed `Receipt.body()` or
13
+ the canonicalisation, existing ledgers will report as tampered. Say so here, and
14
+ add it to CHANGELOG.md under Unreleased.
15
+ -->
16
+
17
+ - [ ] No breaking change
18
+ - [ ] Breaking change, described above and in `CHANGELOG.md`
19
+
20
+ ## Checklist
21
+
22
+ - [ ] `python -m pytest` passes (no install needed — `tests/conftest.py` shims `src` onto `sys.path`)
23
+ - [ ] `python -m agent_ledger.cli demo --no-color` still runs — the demo is the README's front door
24
+ - [ ] `ruff check src tests` and `ruff format --check src tests` pass
25
+ - [ ] A test fails without this change
26
+ - [ ] `CHANGELOG.md` updated under `## [Unreleased]`
27
+
28
+ ## Constraints this project keeps
29
+
30
+ - [ ] **No runtime dependency added.** `dependencies` stays empty; a CI job fails the build if it does not. Anything needing a library ships as an opt-in extra (`[sign]` is the expected shape).
31
+ - [ ] **No network in tests.** Everything goes through the `Transport` protocol; use `StaticTransport`.
32
+ - [ ] **The demo stays offline and key-free.**
33
+ - [ ] **Denials stay data.** A refusal is a `PolicyDecision`, not an exception.
34
+ - [ ] If this touches `verify()`, `content_digest()` or `Receipt`, I added a **negative** test — tampered digest, wrong key, missing field, hostile line — not only the happy path.
35
+
36
+ ## How it was verified
37
+
38
+ <!--
39
+ Commands you ran and what they printed. If you changed the CLI, the demo
40
+ transcript, or anything the README quotes, say whether the README needed
41
+ updating — a README that describes the old behaviour is a bug.
42
+ -->
@@ -0,0 +1,128 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ test:
18
+ name: test (py${{ matrix.python }} / ${{ matrix.os }})
19
+ runs-on: ${{ matrix.os }}
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ os: [ubuntu-latest, windows-latest, macos-latest]
24
+ python: ["3.10", "3.11", "3.12", "3.13"]
25
+ exclude:
26
+ # Keep the matrix honest without spending minutes on redundant runs.
27
+ - os: windows-latest
28
+ python: "3.11"
29
+ - os: macos-latest
30
+ python: "3.11"
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+
34
+ - uses: actions/setup-python@v5
35
+ with:
36
+ python-version: ${{ matrix.python }}
37
+
38
+ - name: Install
39
+ run: |
40
+ python -m pip install --upgrade pip
41
+ python -m pip install -e ".[dev]"
42
+
43
+ - name: Test
44
+ run: python -m pytest -q
45
+
46
+ - name: Demo must run on a clean checkout
47
+ # The offline demo is the project's front door. If it breaks, the
48
+ # README breaks, so it is a CI gate rather than a smoke test.
49
+ run: python -m agent_ledger.cli demo --no-color
50
+ env:
51
+ NO_COLOR: "1"
52
+
53
+ - name: READMEs must still describe this software
54
+ # Documentation drifts in one direction: it describes the version someone
55
+ # was proud of. This checks the claims that can be checked — every
56
+ # documented command and flag exists, the quoted test count is real, the
57
+ # demo transcript still matches, and the Chinese README has not fallen
58
+ # behind the English one.
59
+ run: python tools/check_readme.py
60
+ env:
61
+ NO_COLOR: "1"
62
+
63
+ lint:
64
+ runs-on: ubuntu-latest
65
+ steps:
66
+ - uses: actions/checkout@v4
67
+ - uses: actions/setup-python@v5
68
+ with:
69
+ python-version: "3.12"
70
+ - run: python -m pip install --upgrade pip ruff
71
+ - run: ruff check src tests
72
+ - run: ruff format --check src tests
73
+
74
+ zero-dependency:
75
+ name: no runtime dependencies
76
+ runs-on: ubuntu-latest
77
+ steps:
78
+ - uses: actions/checkout@v4
79
+ - uses: actions/setup-python@v5
80
+ with:
81
+ python-version: "3.12"
82
+ - name: Assert the package declares no runtime dependencies
83
+ # Zero dependencies is a headline promise in the README. This job is
84
+ # what keeps it true.
85
+ run: |
86
+ python - <<'PY'
87
+ import pathlib, re, sys
88
+
89
+ text = pathlib.Path("pyproject.toml").read_text(encoding="utf-8")
90
+ match = re.search(r"^dependencies\s*=\s*\[(.*?)\]", text, re.S | re.M)
91
+ if match is None:
92
+ sys.exit("could not find a dependencies key in pyproject.toml")
93
+ body = match.group(1).strip()
94
+ if body:
95
+ sys.exit(f"runtime dependencies must stay empty, found: {body!r}")
96
+ print("ok: no runtime dependencies declared")
97
+ PY
98
+
99
+ build:
100
+ runs-on: ubuntu-latest
101
+ steps:
102
+ - uses: actions/checkout@v4
103
+ - uses: actions/setup-python@v5
104
+ with:
105
+ python-version: "3.12"
106
+ - run: python -m pip install --upgrade pip build twine
107
+ - run: python -m build
108
+ - name: Assert the artefacts contain only what they should
109
+ # The checks live in tools/audit_dist.py rather than inline so that this
110
+ # job and the release workflow run the *same* ones — a release that is
111
+ # stricter or laxer than CI is a release nobody checked. The audit also
112
+ # asserts what an inline snippet cannot: that the version in the wheel
113
+ # matches pyproject.toml and _identity.py, and that the console scripts
114
+ # survived whatever the distribution name is this month.
115
+ run: python tools/audit_dist.py
116
+ - name: The metadata must render on PyPI
117
+ # README.md is the PyPI long description; a malformed one is rejected at
118
+ # upload time, long after the build that could have caught it.
119
+ run: python -m twine check --strict dist/*
120
+ - name: Install the built wheel in isolation
121
+ run: |
122
+ python -m venv /tmp/clean
123
+ /tmp/clean/bin/python -m pip install dist/*.whl
124
+ /tmp/clean/bin/al demo --no-color > /dev/null
125
+ - uses: actions/upload-artifact@v4
126
+ with:
127
+ name: dist
128
+ path: dist/
@@ -0,0 +1,105 @@
1
+ name: Release
2
+
3
+ # Publishing is triggered by a *published GitHub release*, not by a tag push.
4
+ #
5
+ # A tag is a ref, and a ref can be moved; a release is a deliberate act with a
6
+ # human on the other end of it. The distinction matters here because a version
7
+ # number on PyPI can be yanked but never reused — the one mistake in this
8
+ # workflow that cannot be repaired — so the trigger is the event with the most
9
+ # intent behind it.
10
+ on:
11
+ release:
12
+ types: [published]
13
+ workflow_dispatch:
14
+ inputs:
15
+ target:
16
+ description: "Where to upload. Use testpypi to rehearse the whole path."
17
+ type: choice
18
+ options: [pypi, testpypi]
19
+ default: testpypi
20
+
21
+ permissions:
22
+ contents: read
23
+
24
+ jobs:
25
+ build:
26
+ name: build and check the artefacts
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+
31
+ - uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.12"
34
+
35
+ - name: Install build tooling
36
+ run: python -m pip install --upgrade pip build twine
37
+
38
+ - name: The tag must name the version being published
39
+ # PyPI will reject a second upload of an existing version, and the version
40
+ # number is burned either way. Catching the mismatch here — before the
41
+ # build — is the difference between a red X and a release nobody can redo.
42
+ if: github.event_name == 'release'
43
+ run: |
44
+ python - <<'PY'
45
+ import os, pathlib, re, sys
46
+
47
+ tag = os.environ["GITHUB_REF_NAME"]
48
+ text = pathlib.Path("pyproject.toml").read_text(encoding="utf-8")
49
+ version = re.search(r'^version\s*=\s*"([^"]+)"', text, re.M).group(1)
50
+ if tag.lstrip("v") != version:
51
+ sys.exit(f"tag {tag!r} does not match pyproject version {version!r}")
52
+ print(f"ok: tag {tag} == version {version}")
53
+ PY
54
+
55
+ - name: Build
56
+ run: python -m build
57
+
58
+ - name: Check the artefacts, and that the metadata renders
59
+ # The same audit CI runs, plus the twine check that only matters at
60
+ # upload time — README.md is the PyPI long description, and a malformed
61
+ # one is rejected after the build rather than during it.
62
+ run: |
63
+ python tools/audit_dist.py
64
+ python -m twine check --strict dist/*
65
+
66
+ - name: The wheel must run on its own
67
+ # Everything above inspects the artefact. This runs it — installed into a
68
+ # clean interpreter, with no `src` on the path and no source tree in
69
+ # sight, which is the only configuration a PyPI user will ever have.
70
+ run: |
71
+ python -m venv /tmp/clean
72
+ /tmp/clean/bin/python -m pip install dist/*.whl
73
+ /tmp/clean/bin/al demo --no-color > /dev/null
74
+
75
+ - uses: actions/upload-artifact@v4
76
+ with:
77
+ name: dist
78
+ path: dist/
79
+
80
+ publish:
81
+ name: publish to ${{ github.event_name == 'release' && 'PyPI' || inputs.target }}
82
+ needs: build
83
+ runs-on: ubuntu-latest
84
+
85
+ # Must match the environment named in the PyPI Trusted Publisher. It is also
86
+ # what lets you require a reviewer before a release reaches the world, which
87
+ # is the only remaining human gate in this path.
88
+ environment:
89
+ name: ${{ github.event_name == 'release' && 'pypi' || 'testpypi' }}
90
+ url: ${{ github.event_name == 'release' && 'https://pypi.org/p/ai-agent-ledger-py' || 'https://test.pypi.org/p/ai-agent-ledger-py' }}
91
+
92
+ permissions:
93
+ # The OIDC token that replaces an API token. Without this the upload cannot
94
+ # authenticate, and there is deliberately no secret to fall back on.
95
+ id-token: write
96
+
97
+ steps:
98
+ - uses: actions/download-artifact@v4
99
+ with:
100
+ name: dist
101
+ path: dist/
102
+
103
+ - uses: pypa/gh-action-pypi-publish@release/v1
104
+ with:
105
+ repository-url: ${{ github.event_name == 'release' && 'https://upload.pypi.org/legacy/' || 'https://test.pypi.org/legacy/' }}
@@ -0,0 +1,147 @@
1
+ # What may be published
2
+ #
3
+ # This file is deliberately explicit rather than exhaustive. A deny-list only
4
+ # stops the leaks somebody already thought of; the next stray file — a release
5
+ # plan, a strategy note, a scratch analysis — walks straight past it. So the
6
+ # rules below name the *few* local-only directories instead, and everything else
7
+ # here is the ordinary build and editor cruft.
8
+ #
9
+ # The rule this encodes: **anything that is not the product or its public
10
+ # documentation does not get committed.** If you are unsure whether a file is
11
+ # product, it is not.
12
+
13
+
14
+ # --------------------------------------------------------------------------- #
15
+ # Local-only working material. NEVER published.
16
+ # --------------------------------------------------------------------------- #
17
+
18
+ # Strategy, planning, launch notes, competitive analysis, anything written for
19
+ # us rather than for a reader. Kept on disk because it is useful; kept out of
20
+ # git because a repository is a publication, not a folder.
21
+ .internal/
22
+ .notes/
23
+ .planning/
24
+ private/
25
+
26
+ # Security audits and threat models. These are the one category where publishing
27
+ # is actively harmful: a document that lists weaknesses by file and line is a
28
+ # map for anyone who wants to use them, and "the issues are fixed" is not a
29
+ # reason to hand over the map.
30
+ AUDIT-*.md
31
+ THREAT-MODEL*.md
32
+ SECURITY-AUDIT*.md
33
+
34
+ # Release and launch plans. How a project intends to earn attention is not part
35
+ # of what it does, and it reads badly to the people whose attention is wanted.
36
+ RELEASE*.md
37
+ LAUNCH*.md
38
+ STRATEGY*.md
39
+ ROADMAP-INTERNAL*.md
40
+
41
+ # Scratch, drafts, and one-off analysis scripts
42
+ _scratch*.*
43
+ _dbg*.*
44
+ _tmp*.*
45
+ *.draft.md
46
+ TODO.local.md
47
+
48
+
49
+ # --------------------------------------------------------------------------- #
50
+ # Python build and cache artefacts
51
+ # --------------------------------------------------------------------------- #
52
+
53
+ __pycache__/
54
+ *.py[cod]
55
+ *$py.class
56
+ *.so
57
+ .Python
58
+
59
+ build/
60
+ dist/
61
+ *.egg-info/
62
+ .eggs/
63
+ wheels/
64
+ sdist/
65
+
66
+
67
+ # --------------------------------------------------------------------------- #
68
+ # Virtual environments
69
+ #
70
+ # `.venv-*/` is listed as well as `.venv/` because `.venv/` does NOT match
71
+ # `.venv-test/`. That distinction is not cosmetic: hatchling honours .gitignore
72
+ # when assembling an sdist, so one missing pattern once produced a 16 MB sdist
73
+ # containing an entire virtualenv, `python.exe` included. Every environment
74
+ # directory name in use must be covered here.
75
+ # --------------------------------------------------------------------------- #
76
+
77
+ .venv/
78
+ .venv-*/
79
+ venv/
80
+ venv-*/
81
+ env/
82
+ ENV/
83
+
84
+
85
+ # --------------------------------------------------------------------------- #
86
+ # Test, coverage and lint caches
87
+ # --------------------------------------------------------------------------- #
88
+
89
+ .pytest_cache/
90
+ .ruff_cache/
91
+ .mypy_cache/
92
+ .dmypy.json
93
+ .tox/
94
+ .nox/
95
+ .coverage
96
+ .coverage.*
97
+ htmlcov/
98
+ coverage.xml
99
+
100
+
101
+ # --------------------------------------------------------------------------- #
102
+ # Ledgers and key material produced by running the thing
103
+ #
104
+ # Receipts are evidence and keys are keys; neither belongs in a source
105
+ # repository. Fixtures are the exception, and are re-included explicitly.
106
+ # --------------------------------------------------------------------------- #
107
+
108
+ *.jsonl
109
+ !tests/fixtures/*.jsonl
110
+
111
+ # Trust stores and signed bundles. A keyring holds public keys, but publishing
112
+ # one is an operational decision, not a side effect of running a command.
113
+ keyring.json
114
+ *keyring*.json
115
+ *.bundle.json
116
+ secrets.json
117
+
118
+ # Never, under any circumstance
119
+ .env
120
+ .env.*
121
+ *.pem
122
+ *.key
123
+ id_rsa*
124
+ id_ed25519*
125
+ *.p12
126
+ *.pfx
127
+
128
+
129
+ # --------------------------------------------------------------------------- #
130
+ # Documentation build output
131
+ # --------------------------------------------------------------------------- #
132
+
133
+ docs/_build/
134
+ site/
135
+
136
+
137
+ # --------------------------------------------------------------------------- #
138
+ # Editors and operating systems
139
+ # --------------------------------------------------------------------------- #
140
+
141
+ .idea/
142
+ .vscode/
143
+ *.swp
144
+ *.swo
145
+ .DS_Store
146
+ Thumbs.db
147
+ desktop.ini