agent-readable 0.1.1__tar.gz → 0.1.2__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 (26) hide show
  1. {agent_readable-0.1.1 → agent_readable-0.1.2}/.github/workflows/test.yml +17 -0
  2. agent_readable-0.1.2/CHANGELOG.md +73 -0
  3. {agent_readable-0.1.1 → agent_readable-0.1.2}/PKG-INFO +41 -50
  4. {agent_readable-0.1.1 → agent_readable-0.1.2}/README.md +38 -48
  5. {agent_readable-0.1.1 → agent_readable-0.1.2}/examples/any_class.py +7 -6
  6. {agent_readable-0.1.1 → agent_readable-0.1.2}/examples/duck_type.py +2 -2
  7. {agent_readable-0.1.1 → agent_readable-0.1.2}/examples/modules_and_functions.py +1 -1
  8. {agent_readable-0.1.1 → agent_readable-0.1.2}/examples/sqlite_connection.py +2 -2
  9. {agent_readable-0.1.1 → agent_readable-0.1.2}/examples/temperature.py +2 -2
  10. {agent_readable-0.1.1 → agent_readable-0.1.2}/pyproject.toml +15 -3
  11. agent_readable-0.1.2/skills/agent-readable/SKILL.md +183 -0
  12. {agent_readable-0.1.1 → agent_readable-0.1.2}/src/agent_readable/__init__.py +1 -1
  13. agent_readable-0.1.2/src/agent_readable/_model.py +301 -0
  14. agent_readable-0.1.2/src/agent_readable/_protocol.py +194 -0
  15. agent_readable-0.1.2/src/agent_readable/_render.py +64 -0
  16. agent_readable-0.1.2/tests/__init__.py +0 -0
  17. {agent_readable-0.1.1 → agent_readable-0.1.2}/tests/test_cli.py +1 -1
  18. {agent_readable-0.1.1 → agent_readable-0.1.2}/tests/test_protocol.py +198 -4
  19. agent_readable-0.1.1/AGENT-PROMPT.md +0 -82
  20. agent_readable-0.1.1/src/agent_readable/_protocol.py +0 -417
  21. {agent_readable-0.1.1 → agent_readable-0.1.2}/.github/workflows/publish.yml +0 -0
  22. {agent_readable-0.1.1 → agent_readable-0.1.2}/.gitignore +0 -0
  23. {agent_readable-0.1.1 → agent_readable-0.1.2}/LICENSE +0 -0
  24. {agent_readable-0.1.1 → agent_readable-0.1.2}/docs/agent_help_vs_help.gif +0 -0
  25. {agent_readable-0.1.1 → agent_readable-0.1.2}/src/agent_readable/__main__.py +0 -0
  26. /agent_readable-0.1.1/tests/__init__.py → /agent_readable-0.1.2/src/agent_readable/py.typed +0 -0
@@ -7,6 +7,23 @@ on:
7
7
  workflow_dispatch:
8
8
 
9
9
  jobs:
10
+ lint:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: Install uv
16
+ uses: astral-sh/setup-uv@v3
17
+
18
+ - name: Install dev deps
19
+ run: uv sync --group dev
20
+
21
+ - name: Ruff check
22
+ run: uv run ruff check
23
+
24
+ - name: Ruff format check
25
+ run: uv run ruff format --check
26
+
10
27
  test:
11
28
  runs-on: ubuntu-latest
12
29
  strategy:
@@ -0,0 +1,73 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.2] - 2026-05-30
11
+
12
+ ### Added
13
+
14
+ - `py.typed` marker so inline type annotations are visible to downstream type
15
+ checkers (PEP 561).
16
+ - A module's `__all__` is now honored as the authoritative public API when
17
+ present, including symbols re-exported from other modules.
18
+ - `agent_help()` now emits a `UserWarning` when a class defines both a custom
19
+ `__agent_help__()` and `__agent_notes__()`, since the notes are silently
20
+ dropped in that case.
21
+ - Agent Skill at `skills/agent-readable/SKILL.md` following the
22
+ [Agent Skills open standard](https://agentskills.io). Installable via
23
+ `npx skills add zydo/agent-readable --skill agent-readable` and portable
24
+ across Claude Code, Codex CLI (OpenAI), Gemini CLI (Google), GitHub Copilot,
25
+ Cursor, JetBrains Junie, Goose, OpenCode, and 40+ other adopters. The skill
26
+ teaches the agent to call `agent_help()` before writing Python against a
27
+ library and to author new APIs with `__agent_notes__()`. Supersedes
28
+ `AGENT-PROMPT.md` as the recommended way to wire up coding agents.
29
+
30
+ ### Fixed
31
+
32
+ - Method signatures with a positional-only `self` no longer render a dangling
33
+ `/` (e.g. `backup(/, target)` now renders as `backup(target)`).
34
+
35
+ ### Documentation
36
+
37
+ - README and examples reframed around curation, not compactness. The "Why it
38
+ matters" section now leads with two failure modes — what-exists (curated
39
+ Public API list curbs hallucinated methods and stale signatures) and
40
+ how-to-use (lifecycle rules via `__agent_notes__()`) — instead of a
41
+ comparative empirical claim about which is more common. Removed the
42
+ "217 vs 56 lines" framing in favor of structure-and-rules language.
43
+ - Tagline sharpened to lead with the hallucination-stopping outcome rather
44
+ than the protocol mechanics.
45
+
46
+ ### Removed
47
+
48
+ - `AGENT-PROMPT.md` (superseded by the agent skill at
49
+ `skills/agent-readable/SKILL.md`).
50
+
51
+ ## [0.1.1] - 2026-05-11
52
+
53
+ ### Added
54
+
55
+ - `agent_help()` support for functions and methods.
56
+
57
+ ### Documentation
58
+
59
+ - Demo GIF comparing `agent_help()` and `help()`, plus additional README
60
+ examples.
61
+
62
+ ## [0.1.0] - 2026-05-10
63
+
64
+ ### Added
65
+
66
+ - Initial release: the `agent_help()` function, the `AgentReadable` protocol,
67
+ `AgentReadableMixin`, `__agent_notes__` accumulation across the MRO, module
68
+ support, and the `python -m agent_readable` CLI.
69
+
70
+ [Unreleased]: https://github.com/zydo/agent-readable/compare/v0.1.2...HEAD
71
+ [0.1.2]: https://github.com/zydo/agent-readable/compare/v0.1.1...v0.1.2
72
+ [0.1.1]: https://github.com/zydo/agent-readable/compare/v0.1.0...v0.1.1
73
+ [0.1.0]: https://github.com/zydo/agent-readable/releases/tag/v0.1.0
@@ -1,15 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-readable
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: A lightweight Python protocol for agent-oriented documentation
5
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
6
8
  Author: zydo and agent-readable contributors
7
9
  License-Expression: MIT
8
10
  License-File: LICENSE
9
11
  Keywords: agent,agent-help,ai,ai-agent,coding-agent,context-engineering,docstring,documentation,llm,mixin,prompt-engineering,protocol,vibe-coding
10
12
  Classifier: Development Status :: 3 - Alpha
11
13
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: MIT License
13
14
  Classifier: Programming Language :: Python :: 3
14
15
  Classifier: Programming Language :: Python :: 3.10
15
16
  Classifier: Programming Language :: Python :: 3.11
@@ -26,7 +27,7 @@ Description-Content-Type: text/markdown
26
27
 
27
28
  # agent-readable
28
29
 
29
- A lightweight Python protocol for exposing agent-oriented documentation from classes and modules.
30
+ Stop coding agents from hallucinating your library's API. Ship the usage rules — lifecycle order, pre-conditions, anti-patterns right next to your code.
30
31
 
31
32
  <!-- markdownlint-disable MD033 -->
32
33
  <p align="center">
@@ -39,16 +40,9 @@ A lightweight Python protocol for exposing agent-oriented documentation from cla
39
40
 
40
41
  AI coding agents recognize established libraries from their training data, but they hallucinate when APIs change, when libraries are new, or when correct usage depends on rules that aren't visible from the API surface — pre-conditions, lifecycle order, anti-patterns, *"use `call()` for non-streaming, `stream()` for streaming."*
41
42
 
42
- Today there's nowhere to put those rules where an agent will reliably find them. Docstrings document the API surface, not behavioral rules. `AGENTS.md` and `llms.txt` work at project granularity, drift fast, and don't travel with refactors. `help()` is verbose and only describes interfaces.
43
+ Today there's nowhere to put those rules where an agent will reliably find them. Docstrings document the API surface, not behavioral rules. `AGENTS.md` and `llms.txt` work at project granularity, drift fast, and don't travel with refactors. `help()` only describes interfaces — and mixes inherited dunders and MRO detail in with the methods you actually want to use.
43
44
 
44
- `agent-readable` adds two dunders — `__agent_help__` (full custom output) and `__agent_notes__` (additive guidance that accumulates across inheritance) — that live next to the code. Library authors annotate once; any agent that calls `agent_help(cls)` gets the rules.
45
-
46
- ```text
47
- help(logging.Logger) 217 lines — every inherited method, dunder, and MRO detail.
48
- agent_help(logging.Logger) 56 lines — structured sections + any author notes.
49
- ```
50
-
51
- The compactness is a side effect; the structure is the point.
45
+ `agent-readable` adds two dunders — `__agent_help__` (full custom output) and `__agent_notes__` (additive guidance that accumulates across inheritance) — that live next to the code. Library authors annotate once; any agent that calls `agent_help(cls)` gets a curated public-API list with current signatures, the class's behavioral rules attached, and no inherited-dunder or MRO noise to wade through.
52
46
 
53
47
  ## Installation
54
48
 
@@ -131,12 +125,15 @@ Reads a value from a hardware sensor.
131
125
 
132
126
  ## Why it matters
133
127
 
134
- `help()` documents the **API surface** — what each method does. But agents fail less often on *what methods exist* than on *how to use them*: lifecycle order, pre-conditions, anti-patterns, "this method is for X, that one for Y." Those rules don't fit in docstrings (which describe single methods) and don't belong in a project-level `AGENTS.md` (which describes whole repos). They're class-level, and they need to travel with refactors.
128
+ `agent_help()` covers two failure modes agents hit on real APIs:
135
129
 
136
- `agent_help()` gives them a home next to the code:
130
+ 1. **What exists.** The `## Public API` section is a curated list of current signatures pulled from runtime introspection — no hallucinated methods, no stale signatures from training data, no private members leaking in. If the agent reads this list first, it stops inventing methods that don't exist and stops calling real ones with the wrong arguments.
131
+ 2. **How to use it correctly.** Lifecycle order, pre-conditions, anti-patterns, *"this method is for X, that one for Y."* These don't fit in any single method's docstring and don't belong in a project-level `AGENTS.md` (which describes whole repos). They're class-level, and they need to travel with refactors. `__agent_notes__()` gives them a home next to the code.
132
+
133
+ A concrete contrast:
137
134
 
138
135
  ```
139
- # help(sqlite3.Connection) — 200+ lines of terminal output:
136
+ # help(sqlite3.Connection) — every inherited dunder, in source order:
140
137
  Help on class Connection in module sqlite3:
141
138
 
142
139
  class Connection(builtins.object)
@@ -150,10 +147,11 @@ class Connection(builtins.object)
150
147
  | ...
151
148
  | backup(self, target, /, *, pages=-1, progress=None, ...)
152
149
  | blobopen(self, table, column, rowid, /, *, readonly=False, ...)
153
- | ... (continues for 200+ more lines)
150
+ | ... (no curation, no behavioral rules, no signal that backup() needs an
151
+ | open target connection before being called)
154
152
  ```
155
153
 
156
- `agent_help(sqlite3.Connection)` produces a scannable summary instead — see Example 1 below. Notes from `__agent_notes__()` accumulate across inheritance. Class docs travel with the code in commits, reviews, and refactors. Drift gets caught in code review, not weeks later in a sidecar file.
154
+ `agent_help(sqlite3.Connection)` produces a curated public-API list with current signatures and any class-level rules attached — see Example 1 below. Notes from `__agent_notes__()` accumulate across inheritance. Class docs travel with the code in commits, reviews, and refactors. Drift gets caught in code review, not weeks later in a sidecar file.
157
155
 
158
156
  The examples below demonstrate four ways to use `agent_help()`.
159
157
 
@@ -190,14 +188,14 @@ An agent-friendly wrapper around sqlite3.Connection.
190
188
 
191
189
  ## Public API
192
190
 
193
- - `backup(/, target, *, pages=-1, progress=None, name='main', sleep=0.25)` method: Makes a backup of the database.
191
+ - `backup(target, *, pages=-1, progress=None, name='main', sleep=0.25)` method: Makes a backup of the database.
194
192
  - ...
195
- - `close(/)` method: Close the database connection.
196
- - `commit(/)` method: Commit any pending transaction to the database.
193
+ - `close()` method: Close the database connection.
194
+ - `commit()` method: Commit any pending transaction to the database.
197
195
  - ...
198
196
  - `execute(...)` method: Executes an SQL statement.
199
197
  - ...
200
- - `rollback(/)` method: Roll back to the start of any pending transaction.
198
+ - `rollback()` method: Roll back to the start of any pending transaction.
201
199
  - ...
202
200
 
203
201
  ## Agent usage rules
@@ -366,7 +364,7 @@ print(agent_help(RateLimiter))
366
364
 
367
365
  ## Example 4: Any class — no setup required
368
366
 
369
- Even without the mixin or duck-typing, `agent_help()` still generates compact, structured Markdown from introspection. If the class (or any class in its MRO) defines `__agent_notes__()`, those notes are auto-appended too — no mixin required. The output is still more agent-friendly than `help()`.
367
+ Even without the mixin or duck-typing, `agent_help()` still generates structured Markdown from introspection — a curated public-API list with current signatures, free of inherited dunders and MRO clutter. If the class (or any class in its MRO) defines `__agent_notes__()`, those notes are auto-appended too — no mixin required.
370
368
  Full example: [`examples/any_class.py`](examples/any_class.py).
371
369
 
372
370
  ```python
@@ -376,7 +374,7 @@ from agent_readable import agent_help
376
374
  print(agent_help(logging.Logger))
377
375
  ```
378
376
 
379
- `help(logging.Logger)` produces **217 lines** of output. `agent_help(logging.Logger)` produces a compact, scannable summary:
377
+ Compare what `agent_help(logging.Logger)` returns to what `help(logging.Logger)` does the former lists only the public methods you'd actually call, with their current signatures and docstring summaries:
380
378
 
381
379
  ````
382
380
  # Logger
@@ -429,13 +427,15 @@ Output:
429
427
 
430
428
  ## Purpose
431
429
 
432
- Example: Using agent_help() on modules.
430
+ Example: Using agent_help() on modules, functions, and methods.
433
431
 
434
- Demonstrates both shapes of module support:
432
+ Demonstrates non-class targets:
435
433
  1. A custom module (this file itself).
436
434
  2. A stdlib module (pathlib).
435
+ 3. A function (connect, defined below).
436
+ 4. A method (Query.execute, defined below).
437
437
 
438
- Run this file to see both outputs:
438
+ Run this file to see all outputs:
439
439
  python examples/modules_and_functions.py
440
440
 
441
441
  ## Public API
@@ -476,20 +476,13 @@ operating systems.
476
476
 
477
477
  ## Public API
478
478
 
479
- - `DirEntryInfo` class: Implementation of pathlib.types.PathInfo that provides status
480
479
  - `Path` class: PurePath subclass that can make system calls.
481
- - `PathInfo` class: Implementation of pathlib.types.PathInfo that provides status
482
480
  - `PosixPath` class: Path subclass for non-Windows systems.
483
481
  - `PurePath` class: Base class for manipulating paths without I/O.
484
482
  - `PurePosixPath` class: PurePath subclass for non-Windows systems.
485
483
  - `PureWindowsPath` class: PurePath subclass for Windows systems.
486
484
  - `UnsupportedOperation` class: An exception that is raised when an unsupported operation is attempted.
487
485
  - `WindowsPath` class: Path subclass for Windows systems.
488
- - `copy_info(info, target, follow_symlinks=True)` function: Copy metadata from the given PathInfo to the given local path.
489
- - `copyfileobj(source_f, target_f)` function: Copy data from file-like object source_f to file-like object target_f.
490
- - `ensure_different_files(source, target)` function: Raise OSError(EINVAL) if both paths refer to the same file.
491
- - `ensure_distinct_paths(source, target)` function: Raise OSError(EINVAL) if the other path is within this path.
492
- - `magic_open(path, mode='r', buffering=-1, encoding=None, errors=None, newline=None)` function: Open the file pointed to by this path and return a file object, as
493
486
 
494
487
  ## Agent usage rules
495
488
 
@@ -499,7 +492,7 @@ operating systems.
499
492
  - If usage is ambiguous, prefer the simplest documented usage pattern.
500
493
  ````
501
494
 
502
- Modules support less customization than classes — there is no mixin inheritance or `__agent_notes__()`. You can override the auto-generated output entirely by setting a module-level `__agent_help__` attribute (callable or string), but this is discouraged since it replaces the auto-generated summary — signatures, purpose, and public API listing are all lost. Prefer clear docstrings on the module and its functions/classes instead.
495
+ Modules support less customization than classes — there is no mixin inheritance or `__agent_notes__()`. You can override the auto-generated output entirely by setting a module-level `__agent_help__` attribute (callable or string), but this is discouraged since it replaces the auto-generated summary — signatures, purpose, and public API listing are all lost. Prefer clear docstrings on the module and its functions/classes instead. If the module defines `__all__`, that list is honored as the authoritative public API — including symbols re-exported from other modules.
503
496
 
504
497
  You can also pass a function or method directly — `agent_help()` renders the signature, full docstring, and usage rules. The output is close to `help()` for a single callable; the bigger wins are still on classes and modules.
505
498
 
@@ -543,12 +536,9 @@ Outputs agent-oriented documentation for the given class, module, function, or m
543
536
 
544
537
  ### How does my agent know to call `agent_help()` instead of `help()`?
545
538
 
546
- Today, you tell it. Either:
547
-
548
- - Paste [`AGENT-PROMPT.md`](AGENT-PROMPT.md) into your conversation, or
549
- - Add it permanently to your repo's `AGENTS.md` / `CLAUDE.md` / `.cursor/rules` / equivalent instruction file.
539
+ Install the agent **skill** that ships in this repo at [`skills/agent-readable/`](skills/agent-readable/). It follows the [Agent Skills open standard](https://agentskills.io) — adopted by Claude Code, Codex CLI (OpenAI), Gemini CLI (Google), GitHub Copilot, Cursor, JetBrains Junie, Goose, OpenCode, and 40+ other tools — so dropping the folder into your agent's skills directory (`~/.claude/skills/`, `~/.codex/skills/`, your editor's equivalent) is enough for the agent to discover it. 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.
550
540
 
551
- "You tell it" is the hard part of any new agent protocol. An MCP server (so MCP-aware clients auto-discover the tool) is on the roadmap.
541
+ The folder lives next to the source code for now; a hub-published version (so you can install it through your harness's marketplace) is the next step on the roadmap.
552
542
 
553
543
  ### How is this different from `AGENTS.md` / `llms.txt` / Cursor rules?
554
544
 
@@ -576,7 +566,7 @@ Yes — `agent_help()` falls back to introspection (Example 4). You get a struct
576
566
 
577
567
  ## Keeping agent docs up to date
578
568
 
579
- Agent docs can go stale when classes change — new methods, changed behavior, removed APIs. Copy [`AGENT-PROMPT.md`](AGENT-PROMPT.md) into your coding agent's conversation, or permanently add it to your repo's `AGENTS.md`, `CLAUDE.md`, `.cursor/rules`, `.trae/rules`, `.github/copilot-instructions.md`, or equivalent instruction file. It tells your coding agent to run `agent_help()` before modifying a class, prefer docstrings over `__agent_notes__()`, and verify that docs stay accurate after changes.
569
+ Agent docs can go stale when classes change — new methods, changed behavior, removed APIs. Install the skill at [`skills/agent-readable/`](skills/agent-readable/) into your agent (see the FAQ above for the install). It teaches your agent to run `agent_help()` before modifying a class, prefer docstrings over `__agent_notes__()`, and verify that the output stays accurate after changes.
580
570
 
581
571
  ## The `__agent_help__` protocol
582
572
 
@@ -594,13 +584,13 @@ Classes that define a `@classmethod` named `__agent_help__` returning a `str` ar
594
584
 
595
585
  The two dunders intentionally encode different composition rules:
596
586
 
597
- | Aspect | `__agent_help__()` | `__agent_notes__()` |
598
- | --------------- | ----------------------------------------------- | --------------------------------------------------------------------------- |
599
- | Semantics | **Replacement** — returned string IS the output | **Additive** — appended to auto-generated docs |
600
- | Composition | Single class wins (the one closest in MRO) | Accumulated across the MRO; leaf class wins on conflict (header marks this) |
601
- | When to use | Total control over the rendered text | "Auto-doc + my extra do/don't rules" |
602
- | Skipped when | (always called if defined) | Skipped when a duck-typed `__agent_help__` is present (it owns the output) |
603
- | Mixin required? | No — duck-typed classmethod is enough | No — defining `__agent_notes__` on any class is enough |
587
+ | Aspect | `__agent_help__()` | `__agent_notes__()` |
588
+ | --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------- |
589
+ | Semantics | **Replacement** — returned string IS the output | **Additive** — appended to auto-generated docs |
590
+ | Composition | Single class wins (the one closest in MRO) | Accumulated across the MRO; leaf class wins on conflict (header marks this) |
591
+ | When to use | Total control over the rendered text | "Auto-doc + my extra do/don't rules" |
592
+ | Skipped when | (always called if defined) | Skipped (with a `UserWarning`) when a custom `__agent_help__` is present (it owns the output) |
593
+ | Mixin required? | No — duck-typed classmethod is enough | No — defining `__agent_notes__` on any class is enough |
604
594
 
605
595
  ## Class docstring hints
606
596
 
@@ -632,10 +622,11 @@ If a class inherits from `AgentReadableMixin`, coding agents should call `agent_
632
622
 
633
623
  ### `agent_help(obj)`
634
624
 
635
- Returns a string of agent-oriented documentation for a class, instance, or module.
625
+ Returns a string of agent-oriented documentation for a class, instance, module, function, or method.
636
626
 
637
- - For classes and instances: if `__agent_help__()` is defined (via 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. Otherwise, auto-generated docs are produced from introspection, with `__agent_notes__()` from every class in the MRO appended automatically. If `__agent_help__()` raises, falls back to the auto-generated path (which does include notes).
638
- - For modules: if the module defines a `__agent_help__` attribute (callable or string), it is used. Otherwise, auto-generated docs are produced from the module docstring and its public functions and classes.
627
+ - For classes and instances: if `__agent_help__()` is defined (via 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). Otherwise, auto-generated docs are produced from introspection, with `__agent_notes__()` from every class in the MRO appended automatically. If `__agent_help__()` raises, falls back to the auto-generated path (which does include notes).
628
+ - For modules: if the module defines a `__agent_help__` attribute (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.
629
+ - For functions and methods (anything `inspect.isroutine` accepts): if the routine defines an `__agent_help__` attribute (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 drops `cls`. If a callable `__agent_help__` raises, falls back to the auto-generated path.
639
630
 
640
631
  ## License
641
632
 
@@ -1,6 +1,6 @@
1
1
  # agent-readable
2
2
 
3
- A lightweight Python protocol for exposing agent-oriented documentation from classes and modules.
3
+ Stop coding agents from hallucinating your library's API. Ship the usage rules — lifecycle order, pre-conditions, anti-patterns right next to your code.
4
4
 
5
5
  <!-- markdownlint-disable MD033 -->
6
6
  <p align="center">
@@ -13,16 +13,9 @@ A lightweight Python protocol for exposing agent-oriented documentation from cla
13
13
 
14
14
  AI coding agents recognize established libraries from their training data, but they hallucinate when APIs change, when libraries are new, or when correct usage depends on rules that aren't visible from the API surface — pre-conditions, lifecycle order, anti-patterns, *"use `call()` for non-streaming, `stream()` for streaming."*
15
15
 
16
- Today there's nowhere to put those rules where an agent will reliably find them. Docstrings document the API surface, not behavioral rules. `AGENTS.md` and `llms.txt` work at project granularity, drift fast, and don't travel with refactors. `help()` is verbose and only describes interfaces.
16
+ Today there's nowhere to put those rules where an agent will reliably find them. Docstrings document the API surface, not behavioral rules. `AGENTS.md` and `llms.txt` work at project granularity, drift fast, and don't travel with refactors. `help()` only describes interfaces — and mixes inherited dunders and MRO detail in with the methods you actually want to use.
17
17
 
18
- `agent-readable` adds two dunders — `__agent_help__` (full custom output) and `__agent_notes__` (additive guidance that accumulates across inheritance) — that live next to the code. Library authors annotate once; any agent that calls `agent_help(cls)` gets the rules.
19
-
20
- ```text
21
- help(logging.Logger) 217 lines — every inherited method, dunder, and MRO detail.
22
- agent_help(logging.Logger) 56 lines — structured sections + any author notes.
23
- ```
24
-
25
- The compactness is a side effect; the structure is the point.
18
+ `agent-readable` adds two dunders — `__agent_help__` (full custom output) and `__agent_notes__` (additive guidance that accumulates across inheritance) — that live next to the code. Library authors annotate once; any agent that calls `agent_help(cls)` gets a curated public-API list with current signatures, the class's behavioral rules attached, and no inherited-dunder or MRO noise to wade through.
26
19
 
27
20
  ## Installation
28
21
 
@@ -105,12 +98,15 @@ Reads a value from a hardware sensor.
105
98
 
106
99
  ## Why it matters
107
100
 
108
- `help()` documents the **API surface** — what each method does. But agents fail less often on *what methods exist* than on *how to use them*: lifecycle order, pre-conditions, anti-patterns, "this method is for X, that one for Y." Those rules don't fit in docstrings (which describe single methods) and don't belong in a project-level `AGENTS.md` (which describes whole repos). They're class-level, and they need to travel with refactors.
101
+ `agent_help()` covers two failure modes agents hit on real APIs:
109
102
 
110
- `agent_help()` gives them a home next to the code:
103
+ 1. **What exists.** The `## Public API` section is a curated list of current signatures pulled from runtime introspection — no hallucinated methods, no stale signatures from training data, no private members leaking in. If the agent reads this list first, it stops inventing methods that don't exist and stops calling real ones with the wrong arguments.
104
+ 2. **How to use it correctly.** Lifecycle order, pre-conditions, anti-patterns, *"this method is for X, that one for Y."* These don't fit in any single method's docstring and don't belong in a project-level `AGENTS.md` (which describes whole repos). They're class-level, and they need to travel with refactors. `__agent_notes__()` gives them a home next to the code.
105
+
106
+ A concrete contrast:
111
107
 
112
108
  ```
113
- # help(sqlite3.Connection) — 200+ lines of terminal output:
109
+ # help(sqlite3.Connection) — every inherited dunder, in source order:
114
110
  Help on class Connection in module sqlite3:
115
111
 
116
112
  class Connection(builtins.object)
@@ -124,10 +120,11 @@ class Connection(builtins.object)
124
120
  | ...
125
121
  | backup(self, target, /, *, pages=-1, progress=None, ...)
126
122
  | blobopen(self, table, column, rowid, /, *, readonly=False, ...)
127
- | ... (continues for 200+ more lines)
123
+ | ... (no curation, no behavioral rules, no signal that backup() needs an
124
+ | open target connection before being called)
128
125
  ```
129
126
 
130
- `agent_help(sqlite3.Connection)` produces a scannable summary instead — see Example 1 below. Notes from `__agent_notes__()` accumulate across inheritance. Class docs travel with the code in commits, reviews, and refactors. Drift gets caught in code review, not weeks later in a sidecar file.
127
+ `agent_help(sqlite3.Connection)` produces a curated public-API list with current signatures and any class-level rules attached — see Example 1 below. Notes from `__agent_notes__()` accumulate across inheritance. Class docs travel with the code in commits, reviews, and refactors. Drift gets caught in code review, not weeks later in a sidecar file.
131
128
 
132
129
  The examples below demonstrate four ways to use `agent_help()`.
133
130
 
@@ -164,14 +161,14 @@ An agent-friendly wrapper around sqlite3.Connection.
164
161
 
165
162
  ## Public API
166
163
 
167
- - `backup(/, target, *, pages=-1, progress=None, name='main', sleep=0.25)` method: Makes a backup of the database.
164
+ - `backup(target, *, pages=-1, progress=None, name='main', sleep=0.25)` method: Makes a backup of the database.
168
165
  - ...
169
- - `close(/)` method: Close the database connection.
170
- - `commit(/)` method: Commit any pending transaction to the database.
166
+ - `close()` method: Close the database connection.
167
+ - `commit()` method: Commit any pending transaction to the database.
171
168
  - ...
172
169
  - `execute(...)` method: Executes an SQL statement.
173
170
  - ...
174
- - `rollback(/)` method: Roll back to the start of any pending transaction.
171
+ - `rollback()` method: Roll back to the start of any pending transaction.
175
172
  - ...
176
173
 
177
174
  ## Agent usage rules
@@ -340,7 +337,7 @@ print(agent_help(RateLimiter))
340
337
 
341
338
  ## Example 4: Any class — no setup required
342
339
 
343
- Even without the mixin or duck-typing, `agent_help()` still generates compact, structured Markdown from introspection. If the class (or any class in its MRO) defines `__agent_notes__()`, those notes are auto-appended too — no mixin required. The output is still more agent-friendly than `help()`.
340
+ Even without the mixin or duck-typing, `agent_help()` still generates structured Markdown from introspection — a curated public-API list with current signatures, free of inherited dunders and MRO clutter. If the class (or any class in its MRO) defines `__agent_notes__()`, those notes are auto-appended too — no mixin required.
344
341
  Full example: [`examples/any_class.py`](examples/any_class.py).
345
342
 
346
343
  ```python
@@ -350,7 +347,7 @@ from agent_readable import agent_help
350
347
  print(agent_help(logging.Logger))
351
348
  ```
352
349
 
353
- `help(logging.Logger)` produces **217 lines** of output. `agent_help(logging.Logger)` produces a compact, scannable summary:
350
+ Compare what `agent_help(logging.Logger)` returns to what `help(logging.Logger)` does the former lists only the public methods you'd actually call, with their current signatures and docstring summaries:
354
351
 
355
352
  ````
356
353
  # Logger
@@ -403,13 +400,15 @@ Output:
403
400
 
404
401
  ## Purpose
405
402
 
406
- Example: Using agent_help() on modules.
403
+ Example: Using agent_help() on modules, functions, and methods.
407
404
 
408
- Demonstrates both shapes of module support:
405
+ Demonstrates non-class targets:
409
406
  1. A custom module (this file itself).
410
407
  2. A stdlib module (pathlib).
408
+ 3. A function (connect, defined below).
409
+ 4. A method (Query.execute, defined below).
411
410
 
412
- Run this file to see both outputs:
411
+ Run this file to see all outputs:
413
412
  python examples/modules_and_functions.py
414
413
 
415
414
  ## Public API
@@ -450,20 +449,13 @@ operating systems.
450
449
 
451
450
  ## Public API
452
451
 
453
- - `DirEntryInfo` class: Implementation of pathlib.types.PathInfo that provides status
454
452
  - `Path` class: PurePath subclass that can make system calls.
455
- - `PathInfo` class: Implementation of pathlib.types.PathInfo that provides status
456
453
  - `PosixPath` class: Path subclass for non-Windows systems.
457
454
  - `PurePath` class: Base class for manipulating paths without I/O.
458
455
  - `PurePosixPath` class: PurePath subclass for non-Windows systems.
459
456
  - `PureWindowsPath` class: PurePath subclass for Windows systems.
460
457
  - `UnsupportedOperation` class: An exception that is raised when an unsupported operation is attempted.
461
458
  - `WindowsPath` class: Path subclass for Windows systems.
462
- - `copy_info(info, target, follow_symlinks=True)` function: Copy metadata from the given PathInfo to the given local path.
463
- - `copyfileobj(source_f, target_f)` function: Copy data from file-like object source_f to file-like object target_f.
464
- - `ensure_different_files(source, target)` function: Raise OSError(EINVAL) if both paths refer to the same file.
465
- - `ensure_distinct_paths(source, target)` function: Raise OSError(EINVAL) if the other path is within this path.
466
- - `magic_open(path, mode='r', buffering=-1, encoding=None, errors=None, newline=None)` function: Open the file pointed to by this path and return a file object, as
467
459
 
468
460
  ## Agent usage rules
469
461
 
@@ -473,7 +465,7 @@ operating systems.
473
465
  - If usage is ambiguous, prefer the simplest documented usage pattern.
474
466
  ````
475
467
 
476
- Modules support less customization than classes — there is no mixin inheritance or `__agent_notes__()`. You can override the auto-generated output entirely by setting a module-level `__agent_help__` attribute (callable or string), but this is discouraged since it replaces the auto-generated summary — signatures, purpose, and public API listing are all lost. Prefer clear docstrings on the module and its functions/classes instead.
468
+ Modules support less customization than classes — there is no mixin inheritance or `__agent_notes__()`. You can override the auto-generated output entirely by setting a module-level `__agent_help__` attribute (callable or string), but this is discouraged since it replaces the auto-generated summary — signatures, purpose, and public API listing are all lost. Prefer clear docstrings on the module and its functions/classes instead. If the module defines `__all__`, that list is honored as the authoritative public API — including symbols re-exported from other modules.
477
469
 
478
470
  You can also pass a function or method directly — `agent_help()` renders the signature, full docstring, and usage rules. The output is close to `help()` for a single callable; the bigger wins are still on classes and modules.
479
471
 
@@ -517,12 +509,9 @@ Outputs agent-oriented documentation for the given class, module, function, or m
517
509
 
518
510
  ### How does my agent know to call `agent_help()` instead of `help()`?
519
511
 
520
- Today, you tell it. Either:
521
-
522
- - Paste [`AGENT-PROMPT.md`](AGENT-PROMPT.md) into your conversation, or
523
- - Add it permanently to your repo's `AGENTS.md` / `CLAUDE.md` / `.cursor/rules` / equivalent instruction file.
512
+ Install the agent **skill** that ships in this repo at [`skills/agent-readable/`](skills/agent-readable/). It follows the [Agent Skills open standard](https://agentskills.io) — adopted by Claude Code, Codex CLI (OpenAI), Gemini CLI (Google), GitHub Copilot, Cursor, JetBrains Junie, Goose, OpenCode, and 40+ other tools — so dropping the folder into your agent's skills directory (`~/.claude/skills/`, `~/.codex/skills/`, your editor's equivalent) is enough for the agent to discover it. 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.
524
513
 
525
- "You tell it" is the hard part of any new agent protocol. An MCP server (so MCP-aware clients auto-discover the tool) is on the roadmap.
514
+ The folder lives next to the source code for now; a hub-published version (so you can install it through your harness's marketplace) is the next step on the roadmap.
526
515
 
527
516
  ### How is this different from `AGENTS.md` / `llms.txt` / Cursor rules?
528
517
 
@@ -550,7 +539,7 @@ Yes — `agent_help()` falls back to introspection (Example 4). You get a struct
550
539
 
551
540
  ## Keeping agent docs up to date
552
541
 
553
- Agent docs can go stale when classes change — new methods, changed behavior, removed APIs. Copy [`AGENT-PROMPT.md`](AGENT-PROMPT.md) into your coding agent's conversation, or permanently add it to your repo's `AGENTS.md`, `CLAUDE.md`, `.cursor/rules`, `.trae/rules`, `.github/copilot-instructions.md`, or equivalent instruction file. It tells your coding agent to run `agent_help()` before modifying a class, prefer docstrings over `__agent_notes__()`, and verify that docs stay accurate after changes.
542
+ Agent docs can go stale when classes change — new methods, changed behavior, removed APIs. Install the skill at [`skills/agent-readable/`](skills/agent-readable/) into your agent (see the FAQ above for the install). It teaches your agent to run `agent_help()` before modifying a class, prefer docstrings over `__agent_notes__()`, and verify that the output stays accurate after changes.
554
543
 
555
544
  ## The `__agent_help__` protocol
556
545
 
@@ -568,13 +557,13 @@ Classes that define a `@classmethod` named `__agent_help__` returning a `str` ar
568
557
 
569
558
  The two dunders intentionally encode different composition rules:
570
559
 
571
- | Aspect | `__agent_help__()` | `__agent_notes__()` |
572
- | --------------- | ----------------------------------------------- | --------------------------------------------------------------------------- |
573
- | Semantics | **Replacement** — returned string IS the output | **Additive** — appended to auto-generated docs |
574
- | Composition | Single class wins (the one closest in MRO) | Accumulated across the MRO; leaf class wins on conflict (header marks this) |
575
- | When to use | Total control over the rendered text | "Auto-doc + my extra do/don't rules" |
576
- | Skipped when | (always called if defined) | Skipped when a duck-typed `__agent_help__` is present (it owns the output) |
577
- | Mixin required? | No — duck-typed classmethod is enough | No — defining `__agent_notes__` on any class is enough |
560
+ | Aspect | `__agent_help__()` | `__agent_notes__()` |
561
+ | --------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------- |
562
+ | Semantics | **Replacement** — returned string IS the output | **Additive** — appended to auto-generated docs |
563
+ | Composition | Single class wins (the one closest in MRO) | Accumulated across the MRO; leaf class wins on conflict (header marks this) |
564
+ | When to use | Total control over the rendered text | "Auto-doc + my extra do/don't rules" |
565
+ | Skipped when | (always called if defined) | Skipped (with a `UserWarning`) when a custom `__agent_help__` is present (it owns the output) |
566
+ | Mixin required? | No — duck-typed classmethod is enough | No — defining `__agent_notes__` on any class is enough |
578
567
 
579
568
  ## Class docstring hints
580
569
 
@@ -606,10 +595,11 @@ If a class inherits from `AgentReadableMixin`, coding agents should call `agent_
606
595
 
607
596
  ### `agent_help(obj)`
608
597
 
609
- Returns a string of agent-oriented documentation for a class, instance, or module.
598
+ Returns a string of agent-oriented documentation for a class, instance, module, function, or method.
610
599
 
611
- - For classes and instances: if `__agent_help__()` is defined (via 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. Otherwise, auto-generated docs are produced from introspection, with `__agent_notes__()` from every class in the MRO appended automatically. If `__agent_help__()` raises, falls back to the auto-generated path (which does include notes).
612
- - For modules: if the module defines a `__agent_help__` attribute (callable or string), it is used. Otherwise, auto-generated docs are produced from the module docstring and its public functions and classes.
600
+ - For classes and instances: if `__agent_help__()` is defined (via 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). Otherwise, auto-generated docs are produced from introspection, with `__agent_notes__()` from every class in the MRO appended automatically. If `__agent_help__()` raises, falls back to the auto-generated path (which does include notes).
601
+ - For modules: if the module defines a `__agent_help__` attribute (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.
602
+ - For functions and methods (anything `inspect.isroutine` accepts): if the routine defines an `__agent_help__` attribute (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 drops `cls`. If a callable `__agent_help__` raises, falls back to the auto-generated path.
613
603
 
614
604
  ## License
615
605
 
@@ -2,9 +2,10 @@
2
2
  Example: Using agent_help() on any class — no setup required.
3
3
 
4
4
  Even without duck-typing or the mixin, ``agent_help()`` still generates
5
- compact, structured Markdown from introspection. You cannot add custom
6
- ``__agent_notes__()``, but the output is still more agent-friendly than
7
- Python's built-in ``help()``.
5
+ structured Markdown from introspection a curated public-API list with
6
+ current signatures, free of inherited dunders and MRO clutter. You cannot
7
+ add custom ``__agent_notes__()``, but the output is still more
8
+ agent-friendly than Python's built-in ``help()``.
8
9
 
9
10
  Uses logging.Logger — a stdlib class every Python developer knows.
10
11
 
@@ -18,14 +19,14 @@ import os
18
19
  from agent_readable import agent_help
19
20
 
20
21
  if __name__ == "__main__":
21
- print("=== help(logging.Logger) — verbose, not agent-friendly ===")
22
+ print("=== help(logging.Logger) — every inherited dunder and MRO detail ===")
22
23
  print()
23
24
  os.environ["PAGER"] = "cat"
24
- help(logging.Logger) # noqa: S2201
25
+ help(logging.Logger) # NOSONAR
25
26
 
26
27
  print()
27
28
  print("=" * 72)
28
29
  print()
29
- print("=== agent_help(logging.Logger) — compact, structured, agent-friendly ===")
30
+ print("=== agent_help(logging.Logger) — curated, structured public API ===")
30
31
  print()
31
32
  print(agent_help(logging.Logger))
@@ -18,7 +18,7 @@ class RateLimiter:
18
18
 
19
19
  def __init__(self, max_tokens: int, refill_rate: float): ...
20
20
 
21
- def acquire(self, tokens: int = 1) -> bool: # noqa
21
+ def acquire(self, _tokens: int = 1) -> bool:
22
22
  """Try to acquire tokens. Returns False if rate-limited."""
23
23
  return True
24
24
 
@@ -53,7 +53,7 @@ if __name__ == "__main__":
53
53
  print("=== help(RateLimiter) — no usage guidance ===")
54
54
  print()
55
55
  os.environ["PAGER"] = "cat"
56
- help(RateLimiter) # noqa: S2201
56
+ help(RateLimiter) # NOSONAR
57
57
 
58
58
  print()
59
59
  print("=" * 72)
@@ -30,7 +30,7 @@ def disconnect():
30
30
  class Query:
31
31
  """Build and execute a query."""
32
32
 
33
- def execute(self, sql: str) -> list: # noqa: S1172
33
+ def execute(self, sql: str) -> list: # NOSONAR
34
34
  """Execute a SQL statement."""
35
35
  return []
36
36
 
@@ -34,10 +34,10 @@ class Connection(sqlite3.Connection, AgentReadableMixin):
34
34
 
35
35
 
36
36
  if __name__ == "__main__":
37
- print("=== help(sqlite3.Connection) — verbose, not agent-friendly ===")
37
+ print("=== help(sqlite3.Connection) — every inherited dunder and MRO detail ===")
38
38
  print()
39
39
  os.environ["PAGER"] = "cat"
40
- help(sqlite3.Connection) # noqa: S2201
40
+ help(sqlite3.Connection) # NOSONAR
41
41
 
42
42
  print()
43
43
  print("=" * 72)
@@ -73,10 +73,10 @@ class CalibratedSensor(Sensor):
73
73
 
74
74
 
75
75
  if __name__ == "__main__":
76
- print("=== help(CalibratedSensor) — verbose, not agent-friendly ===")
76
+ print("=== help(CalibratedSensor) — every inherited dunder and MRO detail ===")
77
77
  print()
78
78
  os.environ["PAGER"] = "cat"
79
- help(CalibratedSensor) # noqa: S2201
79
+ help(CalibratedSensor) # NOSONAR
80
80
 
81
81
  print()
82
82
  print("=" * 72)