agent-readable 0.1.2__tar.gz → 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.
- agent_readable-0.1.2/.github/workflows/test.yml → agent_readable-0.2.1/.github/workflows/ci.yml +7 -5
- {agent_readable-0.1.2 → agent_readable-0.2.1}/.github/workflows/publish.yml +5 -5
- {agent_readable-0.1.2 → agent_readable-0.2.1}/CHANGELOG.md +21 -1
- agent_readable-0.2.1/PKG-INFO +96 -0
- agent_readable-0.2.1/README.md +69 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/docs/agent_help_vs_help.gif +0 -0
- agent_readable-0.2.1/docs/authoring.md +79 -0
- agent_readable-0.2.1/docs/examples.md +253 -0
- agent_readable-0.2.1/docs/faq.md +50 -0
- agent_readable-0.2.1/docs/getting-started.md +148 -0
- agent_readable-0.2.1/docs/why.md +49 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/pyproject.toml +1 -1
- agent_readable-0.1.2/PKG-INFO +0 -633
- agent_readable-0.1.2/README.md +0 -606
- agent_readable-0.1.2/skills/agent-readable/SKILL.md +0 -183
- {agent_readable-0.1.2 → agent_readable-0.2.1}/.gitignore +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/LICENSE +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/examples/any_class.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/examples/duck_type.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/examples/modules_and_functions.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/examples/sqlite_connection.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/examples/temperature.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/src/agent_readable/__init__.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/src/agent_readable/__main__.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/src/agent_readable/_model.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/src/agent_readable/_protocol.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/src/agent_readable/_render.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/src/agent_readable/py.typed +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/tests/__init__.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/tests/test_cli.py +0 -0
- {agent_readable-0.1.2 → agent_readable-0.2.1}/tests/test_protocol.py +0 -0
agent_readable-0.1.2/.github/workflows/test.yml → agent_readable-0.2.1/.github/workflows/ci.yml
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: CI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
@@ -10,10 +10,10 @@ jobs:
|
|
|
10
10
|
lint:
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
13
|
+
- uses: actions/checkout@v6
|
|
14
14
|
|
|
15
15
|
- name: Install uv
|
|
16
|
-
uses: astral-sh/setup-uv@
|
|
16
|
+
uses: astral-sh/setup-uv@v8.2.0
|
|
17
17
|
|
|
18
18
|
- name: Install dev deps
|
|
19
19
|
run: uv sync --group dev
|
|
@@ -32,10 +32,12 @@ jobs:
|
|
|
32
32
|
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
33
33
|
|
|
34
34
|
steps:
|
|
35
|
-
- uses: actions/checkout@
|
|
35
|
+
- uses: actions/checkout@v6
|
|
36
36
|
|
|
37
37
|
- name: Install uv
|
|
38
|
-
uses: astral-sh/setup-uv@
|
|
38
|
+
uses: astral-sh/setup-uv@v8.2.0
|
|
39
|
+
with:
|
|
40
|
+
cache-suffix: py${{ matrix.python-version }}
|
|
39
41
|
|
|
40
42
|
- name: Set up Python ${{ matrix.python-version }}
|
|
41
43
|
run: uv python install ${{ matrix.python-version }}
|
|
@@ -9,16 +9,16 @@ jobs:
|
|
|
9
9
|
build:
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
11
|
steps:
|
|
12
|
-
- uses: actions/checkout@
|
|
12
|
+
- uses: actions/checkout@v6
|
|
13
13
|
|
|
14
14
|
- name: Install uv
|
|
15
|
-
uses: astral-sh/setup-uv@
|
|
15
|
+
uses: astral-sh/setup-uv@v8.2.0
|
|
16
16
|
|
|
17
17
|
- name: Build sdist + wheel
|
|
18
18
|
run: uv build
|
|
19
19
|
|
|
20
20
|
- name: Upload artifacts
|
|
21
|
-
uses: actions/upload-artifact@
|
|
21
|
+
uses: actions/upload-artifact@v7
|
|
22
22
|
with:
|
|
23
23
|
name: dist
|
|
24
24
|
path: dist/
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
id-token: write
|
|
34
34
|
steps:
|
|
35
35
|
- name: Download artifacts
|
|
36
|
-
uses: actions/download-artifact@
|
|
36
|
+
uses: actions/download-artifact@v8
|
|
37
37
|
with:
|
|
38
38
|
name: dist
|
|
39
39
|
path: dist/
|
|
@@ -48,7 +48,7 @@ jobs:
|
|
|
48
48
|
contents: write
|
|
49
49
|
steps:
|
|
50
50
|
- name: Download artifacts
|
|
51
|
-
uses: actions/download-artifact@
|
|
51
|
+
uses: actions/download-artifact@v8
|
|
52
52
|
with:
|
|
53
53
|
name: dist
|
|
54
54
|
path: dist/
|
|
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] - 2026-07-04
|
|
11
|
+
|
|
12
|
+
### Documentation
|
|
13
|
+
|
|
14
|
+
- Restructured the README into a concise overview and moved detailed guidance
|
|
15
|
+
into focused docs for getting started, examples, authoring, rationale, and
|
|
16
|
+
FAQ.
|
|
17
|
+
- Added CI and PyPI badges to the README.
|
|
18
|
+
- Added `uv add`, `uvx`, `uv tool run`, and `pipx run` installation and
|
|
19
|
+
one-off execution examples.
|
|
20
|
+
- Added the TypeScript implementation under "Other Languages".
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Renamed the GitHub Actions test workflow file to `ci.yml` and its display
|
|
25
|
+
name to `CI`.
|
|
26
|
+
- Updated GitHub Actions versions to Node 24-compatible releases.
|
|
27
|
+
- Made the uv cache key unique for each Python version in the CI matrix.
|
|
28
|
+
|
|
10
29
|
## [0.1.2] - 2026-05-30
|
|
11
30
|
|
|
12
31
|
### Added
|
|
@@ -67,7 +86,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
67
86
|
`AgentReadableMixin`, `__agent_notes__` accumulation across the MRO, module
|
|
68
87
|
support, and the `python -m agent_readable` CLI.
|
|
69
88
|
|
|
70
|
-
[Unreleased]: https://github.com/zydo/agent-readable/compare/v0.1
|
|
89
|
+
[Unreleased]: https://github.com/zydo/agent-readable/compare/v0.2.1...HEAD
|
|
90
|
+
[0.2.1]: https://github.com/zydo/agent-readable/compare/v0.2.0...v0.2.1
|
|
71
91
|
[0.1.2]: https://github.com/zydo/agent-readable/compare/v0.1.1...v0.1.2
|
|
72
92
|
[0.1.1]: https://github.com/zydo/agent-readable/compare/v0.1.0...v0.1.1
|
|
73
93
|
[0.1.0]: https://github.com/zydo/agent-readable/releases/tag/v0.1.0
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-readable
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: A lightweight Python protocol for agent-oriented documentation
|
|
5
|
+
Project-URL: Repository, https://github.com/zydo/agent-readable
|
|
6
|
+
Project-URL: Issues, https://github.com/zydo/agent-readable/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/zydo/agent-readable/blob/main/CHANGELOG.md
|
|
8
|
+
Author: zydo and agent-readable contributors
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent,agent-help,ai,ai-agent,coding-agent,context-engineering,docstring,documentation,llm,mixin,prompt-engineering,protocol,vibe-coding
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
22
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# agent-readable
|
|
29
|
+
|
|
30
|
+
[](https://github.com/zydo/agent-readable/actions/workflows/ci.yml) [](https://pypi.org/project/agent-readable/)
|
|
31
|
+
|
|
32
|
+
Stop coding agents from hallucinating Python APIs. `agent_help(target)` reads the live public API surface from any Python class, module, function, or method and renders compact, agent-oriented Markdown with current signatures and docstring summaries. When a library opts in, it can also return class-level usage rules such as lifecycle order, preconditions, and anti-patterns.
|
|
33
|
+
|
|
34
|
+
To let your coding agent automatically call `agent_help()` before using an unfamiliar API, install the companion skill:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx skills add zydo/skills --skill agent-readable
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
<!-- markdownlint-disable MD033 -->
|
|
41
|
+
<p align="center">
|
|
42
|
+
<strong><code>logging.Logger</code> compared with <code>agent_help()</code> and <code>help()</code></strong><br>
|
|
43
|
+
<img src="docs/agent_help_vs_help.gif" alt="agent_help vs help">
|
|
44
|
+
</p>
|
|
45
|
+
<!-- markdownlint-enable MD033 -->
|
|
46
|
+
|
|
47
|
+
## Quickstart
|
|
48
|
+
|
|
49
|
+
See [Getting started](docs/getting-started.md) for installation, one-off CLI usage with `uvx`, `uv tool run`, or `pipx`, and full CLI examples.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from agent_readable import agent_help
|
|
53
|
+
import logging
|
|
54
|
+
|
|
55
|
+
print(agent_help(logging.Logger))
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`agent_help()` works on plain Python objects with no setup required. It returns a curated public API list from runtime introspection, so agents see what exists in the installed version instead of guessing from stale training data.
|
|
59
|
+
|
|
60
|
+
Library authors can optionally add usage rules next to the code:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
class Sensor:
|
|
64
|
+
"""Reads a value from a hardware sensor."""
|
|
65
|
+
|
|
66
|
+
def read(self) -> float:
|
|
67
|
+
"""Read the current sensor value."""
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def __agent_notes__(cls) -> str:
|
|
71
|
+
return """
|
|
72
|
+
## Do
|
|
73
|
+
|
|
74
|
+
- Call `calibrate()` once during setup, before `read()`.
|
|
75
|
+
|
|
76
|
+
## Do not
|
|
77
|
+
|
|
78
|
+
- Do not call `read()` before calibration on first use.
|
|
79
|
+
"""
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Docs
|
|
83
|
+
|
|
84
|
+
- [Getting started](docs/getting-started.md): installation, quickstart, CLI usage, and other language implementations.
|
|
85
|
+
- [Why it matters](docs/why.md): the API hallucination problem, token efficiency, and how this compares to other agent-doc patterns.
|
|
86
|
+
- [Examples](docs/examples.md): wrapping existing classes, inherited notes, duck typing, plain classes, modules, functions, and methods.
|
|
87
|
+
- [Authoring guide](docs/authoring.md): `__agent_help__`, `__agent_notes__`, class docstring hints, freshness guidance, and API reference.
|
|
88
|
+
- [FAQ](docs/faq.md): common questions about agent skills, docstrings, `AGENTS.md`, third-party libraries, and constrained decoding.
|
|
89
|
+
|
|
90
|
+
## Other Languages
|
|
91
|
+
|
|
92
|
+
- TypeScript: [`agent-readable-ts`](https://github.com/zydo/agent-readable-ts)
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# agent-readable
|
|
2
|
+
|
|
3
|
+
[](https://github.com/zydo/agent-readable/actions/workflows/ci.yml) [](https://pypi.org/project/agent-readable/)
|
|
4
|
+
|
|
5
|
+
Stop coding agents from hallucinating Python APIs. `agent_help(target)` reads the live public API surface from any Python class, module, function, or method and renders compact, agent-oriented Markdown with current signatures and docstring summaries. When a library opts in, it can also return class-level usage rules such as lifecycle order, preconditions, and anti-patterns.
|
|
6
|
+
|
|
7
|
+
To let your coding agent automatically call `agent_help()` before using an unfamiliar API, install the companion skill:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx skills add zydo/skills --skill agent-readable
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
<!-- markdownlint-disable MD033 -->
|
|
14
|
+
<p align="center">
|
|
15
|
+
<strong><code>logging.Logger</code> compared with <code>agent_help()</code> and <code>help()</code></strong><br>
|
|
16
|
+
<img src="docs/agent_help_vs_help.gif" alt="agent_help vs help">
|
|
17
|
+
</p>
|
|
18
|
+
<!-- markdownlint-enable MD033 -->
|
|
19
|
+
|
|
20
|
+
## Quickstart
|
|
21
|
+
|
|
22
|
+
See [Getting started](docs/getting-started.md) for installation, one-off CLI usage with `uvx`, `uv tool run`, or `pipx`, and full CLI examples.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from agent_readable import agent_help
|
|
26
|
+
import logging
|
|
27
|
+
|
|
28
|
+
print(agent_help(logging.Logger))
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`agent_help()` works on plain Python objects with no setup required. It returns a curated public API list from runtime introspection, so agents see what exists in the installed version instead of guessing from stale training data.
|
|
32
|
+
|
|
33
|
+
Library authors can optionally add usage rules next to the code:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
class Sensor:
|
|
37
|
+
"""Reads a value from a hardware sensor."""
|
|
38
|
+
|
|
39
|
+
def read(self) -> float:
|
|
40
|
+
"""Read the current sensor value."""
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def __agent_notes__(cls) -> str:
|
|
44
|
+
return """
|
|
45
|
+
## Do
|
|
46
|
+
|
|
47
|
+
- Call `calibrate()` once during setup, before `read()`.
|
|
48
|
+
|
|
49
|
+
## Do not
|
|
50
|
+
|
|
51
|
+
- Do not call `read()` before calibration on first use.
|
|
52
|
+
"""
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Docs
|
|
56
|
+
|
|
57
|
+
- [Getting started](docs/getting-started.md): installation, quickstart, CLI usage, and other language implementations.
|
|
58
|
+
- [Why it matters](docs/why.md): the API hallucination problem, token efficiency, and how this compares to other agent-doc patterns.
|
|
59
|
+
- [Examples](docs/examples.md): wrapping existing classes, inherited notes, duck typing, plain classes, modules, functions, and methods.
|
|
60
|
+
- [Authoring guide](docs/authoring.md): `__agent_help__`, `__agent_notes__`, class docstring hints, freshness guidance, and API reference.
|
|
61
|
+
- [FAQ](docs/faq.md): common questions about agent skills, docstrings, `AGENTS.md`, third-party libraries, and constrained decoding.
|
|
62
|
+
|
|
63
|
+
## Other Languages
|
|
64
|
+
|
|
65
|
+
- TypeScript: [`agent-readable-ts`](https://github.com/zydo/agent-readable-ts)
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
[MIT](LICENSE)
|
|
Binary file
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Authoring guide
|
|
2
|
+
|
|
3
|
+
## Keeping agent docs up to date
|
|
4
|
+
|
|
5
|
+
Agent docs can go stale when classes change: new methods, changed behavior, or removed APIs. Install the companion skill to teach your agent to run `agent_help()` before modifying a class, prefer docstrings over `__agent_notes__()` for API summaries, and verify that the output stays accurate after changes.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx skills add zydo/skills --skill agent-readable
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## The `__agent_help__` protocol
|
|
12
|
+
|
|
13
|
+
`__agent_help__()` is a dunder protocol for tool-specific documentation, similar in spirit to:
|
|
14
|
+
|
|
15
|
+
- `__doc__`: read by Python `help()`, Sphinx, IDEs, and REPLs.
|
|
16
|
+
- `__rich_repr__`: read by Rich when it renders an object.
|
|
17
|
+
- `__html__`: read by Django, Jinja2, and MarkupSafe when rendering HTML.
|
|
18
|
+
|
|
19
|
+
Unlike `__str__` or `__fspath__`, these dunders do not change Python runtime behavior. They are metadata slots a specific tool reads when it wants a representation. `__agent_help__` follows the same pattern for agent documentation.
|
|
20
|
+
|
|
21
|
+
Classes that define a `@classmethod` named `__agent_help__` returning a `str` are considered agent-readable. Modules can define a top-level `__agent_help__` attribute, either callable or string. Call the top-level `agent_help(obj)` function to get the docs, just like `str()` calls `__str__()`.
|
|
22
|
+
|
|
23
|
+
The `AgentReadable` `typing.Protocol` and `AgentReadableMixin` are provided for convenience and type-checking, but neither is required.
|
|
24
|
+
|
|
25
|
+
## `__agent_help__` vs `__agent_notes__`
|
|
26
|
+
|
|
27
|
+
The two dunders intentionally encode different composition rules:
|
|
28
|
+
|
|
29
|
+
| Aspect | `__agent_help__()` | `__agent_notes__()` |
|
|
30
|
+
| --------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
31
|
+
| Semantics | Replacement: returned string is the output | Additive: appended to auto-generated docs |
|
|
32
|
+
| Composition | Single class wins, closest in MRO | Accumulated across the MRO; leaf class wins on conflict |
|
|
33
|
+
| When to use | Total control over rendered text | Auto-doc plus extra do/don't rules |
|
|
34
|
+
| Skipped when | Always called if defined | Silently dropped, with `UserWarning`, when custom `__agent_help__` is present |
|
|
35
|
+
| Mixin required? | No | No |
|
|
36
|
+
|
|
37
|
+
When a class defines both `__agent_help__()` and `__agent_notes__()`, the notes are silently dropped because `__agent_help__()` owns the output and the auto-doc plus notes path never runs. A `UserWarning` is emitted, but warnings are easy to miss in agent shells, CI logs, and notebooks. Treat "both defined" as a review error. Fix it by folding the notes into `__agent_help__()`, or by dropping custom `__agent_help__()` and letting the auto-doc plus notes path run.
|
|
38
|
+
|
|
39
|
+
## Class docstring hints
|
|
40
|
+
|
|
41
|
+
For classes that inherit `AgentReadableMixin`, add a short hint in the class docstring:
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
class ResourcePool(AgentReadableMixin):
|
|
45
|
+
"""
|
|
46
|
+
Rotates interchangeable resources such as API keys.
|
|
47
|
+
|
|
48
|
+
Agent usage:
|
|
49
|
+
Run ``agent_help(ResourcePool)`` before using this class in generated code.
|
|
50
|
+
"""
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This way, even agents that only see the source or call `help()` are reminded to check `agent_help()`.
|
|
54
|
+
|
|
55
|
+
## API reference
|
|
56
|
+
|
|
57
|
+
### `agent_help(target)`
|
|
58
|
+
|
|
59
|
+
Render agent-oriented Markdown for a class, module, function, or method.
|
|
60
|
+
|
|
61
|
+
For classes, the output includes purpose, constructor, public API, default usage rules, and accumulated `__agent_notes__()` sections when present. For modules, it includes purpose, public functions, and public classes. For functions and methods, it includes signature, docstring, and default usage rules.
|
|
62
|
+
|
|
63
|
+
For classes and instances, if `__agent_help__()` is defined through the mixin or duck typing, it is called and its return value is used verbatim. Duck-typed implementations are responsible for their own formatting, and notes are not auto-appended. If such a class also defines `__agent_notes__()`, a `UserWarning` is emitted because those notes are silently dropped. Fold them into `__agent_help__()`, or drop the custom `__agent_help__()` to use the auto-doc path. If `__agent_help__()` raises, `agent_help()` falls back to the auto-generated path, which does include notes.
|
|
64
|
+
|
|
65
|
+
For modules, if the module defines a `__agent_help__` attribute, either callable or string, it is used. Otherwise, auto-generated docs are produced from the module docstring and its public functions and classes. When the module defines `__all__`, that list is the authoritative public API, so re-exported symbols are included. Otherwise public members are discovered by introspection, skipping private names and anything defined outside the module.
|
|
66
|
+
|
|
67
|
+
For functions and methods, if the routine defines a `__agent_help__` attribute, either callable or string, it is used. Otherwise, auto-generated docs render the signature, full docstring, and usage rules. A bound method's signature drops `self`, and a classmethod's signature drops `cls`. If a callable `__agent_help__` raises, `agent_help()` falls back to the auto-generated path.
|
|
68
|
+
|
|
69
|
+
### `AgentReadable`
|
|
70
|
+
|
|
71
|
+
A runtime-checkable `typing.Protocol` that requires `__agent_help__() -> str`.
|
|
72
|
+
|
|
73
|
+
### `AgentReadableMixin`
|
|
74
|
+
|
|
75
|
+
A mixin class for classes that provides a default `__agent_help__()` implementation using introspection. The mixin is convenience only: defining `__agent_notes__()` directly on any class also works, and notes are collected automatically regardless of inheritance from the mixin.
|
|
76
|
+
|
|
77
|
+
The mixin does not apply to modules; modules are supported directly by `agent_help()`.
|
|
78
|
+
|
|
79
|
+
If a class inherits from `AgentReadableMixin`, coding agents should call `agent_help(TheClass)` before generating code that uses it.
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
These examples demonstrate five ways to use `agent_help()`: three with library-author opt-in and two on plain classes or modules with no setup.
|
|
4
|
+
|
|
5
|
+
## Example 1: Wrapping an existing class
|
|
6
|
+
|
|
7
|
+
Add agent-readable docs to any class, including ones you do not own. Full example: [`examples/sqlite_connection.py`](../examples/sqlite_connection.py).
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import sqlite3
|
|
11
|
+
from agent_readable import AgentReadableMixin, agent_help
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Connection(sqlite3.Connection, AgentReadableMixin):
|
|
15
|
+
"""An agent-friendly wrapper around sqlite3.Connection."""
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def __agent_notes__(cls) -> str:
|
|
19
|
+
return (
|
|
20
|
+
"Additional notes about using Connection here. "
|
|
21
|
+
"For example, common pitfalls, best practices, etc."
|
|
22
|
+
)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Override `__agent_notes__()` to add extra guidance, or leave it out for auto-generated docs only.
|
|
26
|
+
|
|
27
|
+
`agent_help(Connection)` output excerpt:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
# Connection
|
|
31
|
+
|
|
32
|
+
## Purpose
|
|
33
|
+
|
|
34
|
+
An agent-friendly wrapper around sqlite3.Connection.
|
|
35
|
+
|
|
36
|
+
## Public API
|
|
37
|
+
|
|
38
|
+
- `backup(target, *, pages=-1, progress=None, name='main', sleep=0.25)` method: Makes a backup of the database.
|
|
39
|
+
- `close()` method: Close the database connection.
|
|
40
|
+
- `commit()` method: Commit any pending transaction to the database.
|
|
41
|
+
- `execute(...)` method: Executes an SQL statement.
|
|
42
|
+
- `rollback()` method: Roll back to the start of any pending transaction.
|
|
43
|
+
|
|
44
|
+
## Agent usage rules
|
|
45
|
+
|
|
46
|
+
- Prefer the public API listed above.
|
|
47
|
+
- Do not use private methods or attributes starting with `_`.
|
|
48
|
+
- Do not invent unsupported behavior.
|
|
49
|
+
- If usage is ambiguous, prefer the simplest documented usage pattern.
|
|
50
|
+
|
|
51
|
+
## Notes from class Connection
|
|
52
|
+
|
|
53
|
+
Additional notes about using Connection here. For example, common pitfalls, best practices, etc.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Example 2: Inheritance with accumulated notes
|
|
57
|
+
|
|
58
|
+
Override `__agent_notes__()` to add usage guidance. Notes accumulate through inheritance automatically. Full example: [`examples/temperature.py`](../examples/temperature.py).
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from agent_readable import AgentReadableMixin, agent_help
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Sensor(AgentReadableMixin):
|
|
65
|
+
"""Reads a value from a hardware sensor."""
|
|
66
|
+
|
|
67
|
+
def __init__(self, pin: int, *, unit: str = "C"): ...
|
|
68
|
+
|
|
69
|
+
def read(self) -> float:
|
|
70
|
+
"""Read the current sensor value."""
|
|
71
|
+
|
|
72
|
+
def calibrate(self, offset: float):
|
|
73
|
+
"""Apply a calibration offset."""
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def __agent_notes__(cls) -> str:
|
|
77
|
+
return """
|
|
78
|
+
## Do
|
|
79
|
+
|
|
80
|
+
- Call `calibrate()` once during setup, before `read()`.
|
|
81
|
+
- Handle negative values -- sensors may report below zero.
|
|
82
|
+
|
|
83
|
+
## Do not
|
|
84
|
+
|
|
85
|
+
- Do not call `read()` before `calibrate()` on first use.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class CalibratedSensor(Sensor):
|
|
90
|
+
"""A sensor with factory calibration applied."""
|
|
91
|
+
|
|
92
|
+
def reset(self):
|
|
93
|
+
"""Reset to factory calibration."""
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def __agent_notes__(cls) -> str:
|
|
97
|
+
return """
|
|
98
|
+
## Do
|
|
99
|
+
|
|
100
|
+
- Call `reset()` if readings drift unexpectedly.
|
|
101
|
+
|
|
102
|
+
## Do not
|
|
103
|
+
|
|
104
|
+
- Do not call `calibrate()` -- use `reset()` instead. Factory calibration
|
|
105
|
+
is pre-applied and `calibrate()` would double-adjust.
|
|
106
|
+
"""
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`agent_help(CalibratedSensor)` includes notes from both classes. The child class's notes explicitly state they take precedence over the parent's, so the agent knows `reset()` replaces `calibrate()` for `CalibratedSensor`.
|
|
110
|
+
|
|
111
|
+
## Example 3: Duck-typed custom output
|
|
112
|
+
|
|
113
|
+
Any class that defines a `__agent_help__()` classmethod works, with no inheritance required. Full example: [`examples/duck_type.py`](../examples/duck_type.py).
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from agent_readable import agent_help
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class RateLimiter:
|
|
120
|
+
"""Token bucket rate limiter."""
|
|
121
|
+
|
|
122
|
+
def __init__(self, max_tokens: int, refill_rate: float): ...
|
|
123
|
+
|
|
124
|
+
def acquire(self, tokens: int = 1) -> bool:
|
|
125
|
+
"""Try to acquire tokens. Returns False if rate-limited."""
|
|
126
|
+
|
|
127
|
+
def wait(self, tokens: int = 1) -> None:
|
|
128
|
+
"""Block until tokens are available."""
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def __agent_help__(cls) -> str:
|
|
132
|
+
return (
|
|
133
|
+
"# RateLimiter\n"
|
|
134
|
+
"\n"
|
|
135
|
+
"## Constructor\n"
|
|
136
|
+
"\n"
|
|
137
|
+
"```python\n"
|
|
138
|
+
"RateLimiter(max_tokens: int, refill_rate: float)\n"
|
|
139
|
+
"```\n"
|
|
140
|
+
"\n"
|
|
141
|
+
"## Do\n"
|
|
142
|
+
"\n"
|
|
143
|
+
"- Use `acquire()` for non-blocking checks.\n"
|
|
144
|
+
"- Use `wait()` when you must proceed regardless of rate.\n"
|
|
145
|
+
"- Set `refill_rate` to tokens/second.\n"
|
|
146
|
+
"\n"
|
|
147
|
+
"## Do not\n"
|
|
148
|
+
"\n"
|
|
149
|
+
"- Do not call `acquire()` in a tight loop without sleeping.\n"
|
|
150
|
+
"- Do not assume `acquire()` always returns True.\n"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
print(agent_help(RateLimiter))
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Use `__agent_help__()` when you need total control over the rendered output. Use `__agent_notes__()` when you want auto-generated API docs plus your extra rules.
|
|
158
|
+
|
|
159
|
+
## Example 4: Any class, no setup required
|
|
160
|
+
|
|
161
|
+
Even without the mixin or duck typing, `agent_help()` generates structured Markdown from introspection: a curated public API list with current signatures, free of inherited dunders and MRO clutter. Full example: [`examples/any_class.py`](../examples/any_class.py).
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
import logging
|
|
165
|
+
from agent_readable import agent_help
|
|
166
|
+
|
|
167
|
+
print(agent_help(logging.Logger))
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Output excerpt:
|
|
171
|
+
|
|
172
|
+
````
|
|
173
|
+
# Logger
|
|
174
|
+
|
|
175
|
+
## Constructor
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
Logger(name, level=0)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Purpose
|
|
182
|
+
|
|
183
|
+
Instances of the Logger class represent a single logging channel. A
|
|
184
|
+
"logging channel" indicates an area of an application.
|
|
185
|
+
|
|
186
|
+
## Public API
|
|
187
|
+
|
|
188
|
+
- `addFilter(filter)` method: Add the specified filter to this handler.
|
|
189
|
+
- `addHandler(hdlr)` method: Add the specified handler to this logger.
|
|
190
|
+
- `debug(msg, *args, **kwargs)` method: Log 'msg % args' with severity 'DEBUG'.
|
|
191
|
+
- `error(msg, *args, **kwargs)` method: Log 'msg % args' with severity 'ERROR'.
|
|
192
|
+
- `info(msg, *args, **kwargs)` method: Log 'msg % args' with severity 'INFO'.
|
|
193
|
+
- `setLevel(level)` method: Set the logging level of this logger.
|
|
194
|
+
- `warning(msg, *args, **kwargs)` method: Log 'msg % args' with severity 'WARNING'.
|
|
195
|
+
````
|
|
196
|
+
|
|
197
|
+
No mixin, no duck typing: just pass any class to `agent_help()`.
|
|
198
|
+
|
|
199
|
+
## Example 5: Modules, functions, and methods
|
|
200
|
+
|
|
201
|
+
`agent_help()` also works on modules, functions, and methods. Full example: [`examples/modules_and_functions.py`](../examples/modules_and_functions.py).
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
import sys
|
|
205
|
+
from agent_readable import agent_help
|
|
206
|
+
|
|
207
|
+
print(agent_help(sys.modules[__name__]))
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Module output includes the module docstring, public functions, and classes:
|
|
211
|
+
|
|
212
|
+
````python
|
|
213
|
+
# __main__
|
|
214
|
+
|
|
215
|
+
## Purpose
|
|
216
|
+
|
|
217
|
+
Example: Using agent_help() on modules, functions, and methods.
|
|
218
|
+
|
|
219
|
+
## Public API
|
|
220
|
+
|
|
221
|
+
- `Query` class: Build and execute a query.
|
|
222
|
+
- `connect(host: str, port: int = 5432) -> str` function: Connect to a database server.
|
|
223
|
+
- `disconnect()` function: Close the connection.
|
|
224
|
+
|
|
225
|
+
## Agent usage rules
|
|
226
|
+
|
|
227
|
+
- Prefer the public API listed above.
|
|
228
|
+
- Do not use private names starting with `_`.
|
|
229
|
+
- Do not invent unsupported behavior.
|
|
230
|
+
- If usage is ambiguous, prefer the simplest documented usage pattern.
|
|
231
|
+
````
|
|
232
|
+
|
|
233
|
+
You can also pass any stdlib or third-party module:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
import pathlib
|
|
237
|
+
from agent_readable import agent_help
|
|
238
|
+
|
|
239
|
+
print(agent_help(pathlib))
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
If the module defines `__all__`, that list is honored as the authoritative public API, including symbols re-exported from other modules.
|
|
243
|
+
|
|
244
|
+
Functions and methods render their signature, full docstring, and usage rules:
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
import pathlib
|
|
248
|
+
from agent_readable import agent_help
|
|
249
|
+
|
|
250
|
+
print(agent_help(pathlib.Path.read_text))
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Modules support less customization than classes. You can override generated module output entirely by setting a module-level `__agent_help__` attribute, but this is discouraged because it replaces the auto-generated summary, signatures, purpose, and public API list. Prefer clear module, function, and class docstrings instead.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# FAQ
|
|
2
|
+
|
|
3
|
+
## How does my agent know to call `agent_help()` instead of `help()`?
|
|
4
|
+
|
|
5
|
+
Install the companion agent skill:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx skills add zydo/skills --skill agent-readable
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The skill teaches the agent to install `agent-readable`, call `agent_help(target)` before writing code against a class, module, function, or method, and add `__agent_notes__()` or improve docstrings when authoring new public APIs.
|
|
12
|
+
|
|
13
|
+
Cursor is among the adopters too, but its skill integration is manual: invoke the skill explicitly there rather than relying on description-match auto-activation.
|
|
14
|
+
|
|
15
|
+
## How is this different from `AGENTS.md`, `llms.txt`, or Cursor rules?
|
|
16
|
+
|
|
17
|
+
Different granularity, different drift profile.
|
|
18
|
+
|
|
19
|
+
`AGENTS.md`, `llms.txt`, and `.cursor/rules` are project-level: one file per repo. They are good for rules like "use pnpm," "run lint before commit," or "this codebase prefers functional style."
|
|
20
|
+
|
|
21
|
+
`agent-readable` is class- or module-level: rules live next to the API they describe. It is better for guidance like "`ResourcePool.call()` is for non-streaming requests; for streaming, use `stream()` instead."
|
|
22
|
+
|
|
23
|
+
Use both. They do not compete. The advantage of class-level docs is that they travel with the code. When someone refactors `ResourcePool` into two classes, the rules move with the relevant class in the same PR instead of sitting stale in a sidecar file.
|
|
24
|
+
|
|
25
|
+
## Why not just write better docstrings?
|
|
26
|
+
|
|
27
|
+
Docstrings answer "what does this do?" They are not designed for "when may I call this?" or "what is the wrong way to use this?"
|
|
28
|
+
|
|
29
|
+
Mixing both categories into the docstring makes the API summary noisier without helping agents reliably find usage rules. `__agent_notes__()` is for the second category, and it accumulates across the MRO automatically. Class docstrings do not compose like that.
|
|
30
|
+
|
|
31
|
+
## Does this work for libraries I do not own?
|
|
32
|
+
|
|
33
|
+
Yes. Two common options:
|
|
34
|
+
|
|
35
|
+
- Subclass the target class and add `AgentReadableMixin` or `__agent_notes__()`.
|
|
36
|
+
- Monkey-patch: `ThirdPartyClass.__agent_notes__ = classmethod(lambda cls: "...")`.
|
|
37
|
+
|
|
38
|
+
`agent_help()` collects notes from the entire MRO; the mixin is not required.
|
|
39
|
+
|
|
40
|
+
## Does it work without my class doing anything?
|
|
41
|
+
|
|
42
|
+
Yes. `agent_help()` falls back to introspection. You get a structured summary of every plain class, mixin or not. Notes are added on top if the class defines them; otherwise the auto-doc is what you see.
|
|
43
|
+
|
|
44
|
+
## Is `agent_help()` the strongest fix for API hallucination?
|
|
45
|
+
|
|
46
|
+
No. The strongest known mitigation is constrained decoding at the harness or decoder layer: masking illegal API tokens before generation, so the model cannot produce a nonexistent method at all.
|
|
47
|
+
|
|
48
|
+
`agent_help()` takes a lighter, library-side path: an authoritative usage guide injected into the agent's context, leaving the agent to read and follow it. Recent research on Python API misuse shows the in-context route leaves a meaningful slice of hallucinations on the table even when verified API references are provided.
|
|
49
|
+
|
|
50
|
+
The two approaches compose. Pick `agent_help()` when you have leverage on the library side and want a fix that works on every agent and every library today, without harness changes. Reach for constrained decoding when you control the harness or decoder. Either way, verify generated code before merging.
|