agent-doc-system 1.1.0 → 1.2.0
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.
- package/CHANGELOG.md +269 -0
- package/README.md +38 -0
- package/adapters/ansible.mjs +1 -1
- package/adapters/cache.mjs +8 -2
- package/adapters/contract-consumers.mjs +1 -1
- package/adapters/database.mjs +18 -4
- package/adapters/events.mjs +1 -1
- package/adapters/github-actions.mjs +244 -85
- package/adapters/go.mjs +1 -1
- package/adapters/index.mjs +3 -1
- package/adapters/object-store.mjs +2 -2
- package/adapters/python.mjs +1142 -0
- package/adapters/resource-client.mjs +1 -1
- package/adapters/rust.mjs +987 -0
- package/adapters/typescript.mjs +1 -1
- package/bin/agentdoc.mjs +2 -2
- package/core/audit.mjs +5 -3
- package/core/codes.mjs +4 -0
- package/core/compile.mjs +124 -11
- package/core/dependents.mjs +42 -0
- package/core/discover.mjs +60 -9
- package/core/fsx.mjs +17 -0
- package/core/graph.mjs +1 -1
- package/core/impact.mjs +55 -44
- package/core/query.mjs +18 -8
- package/core/scaffold.mjs +87 -22
- package/core/sourcescan.mjs +11 -2
- package/core/toml.mjs +463 -140
- package/docs/ADAPTERS.md +196 -6
- package/docs/BENCHMARK.md +68 -0
- package/docs/CI.md +1 -1
- package/docs/EVALS.md +33 -2
- package/docs/MIGRATION.md +4 -2
- package/docs/QUERY.md +53 -4
- package/docs/SPEC.md +22 -0
- package/docs/ci/github-actions.yml +1 -1
- package/evals/harness.mjs +32 -6
- package/evals/scenarios/fixture-b-03-change-shared-lib.json +8 -1
- package/evals/scenarios/fixture-c-03-shared-vocabulary.json +7 -1
- package/evals/scenarios/fixture-e-01-change-shared-lib.json +14 -0
- package/evals/scenarios/fixture-e-02-change-manifest.json +9 -0
- package/evals/scenarios/fixture-e-03-local-module.json +9 -0
- package/evals/scenarios/fixture-e-04-ambiguous-crate.json +14 -0
- package/evals/scenarios/fixture-f-01-change-shared-lib.json +9 -0
- package/evals/scenarios/fixture-f-02-change-manifest.json +9 -0
- package/evals/scenarios/fixture-f-03-shadowed-import.json +9 -0
- package/evals/scenarios/fixture-f-04-nested-workspace.json +9 -0
- package/evals/scenarios/fixture-f-05-alembic-database.json +9 -0
- package/evals/scenarios/fixture-f-06-unittest-job.json +9 -0
- package/package.json +2 -1
- package/skills/agent-doc-system/references/create-migrate.md +13 -3
- package/templates/ci.yml +1 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to AgentDoc are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
6
|
+
the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). The
|
|
7
|
+
compiler version is the package version: a graph compiled by one release is
|
|
8
|
+
refused by the next with `AGENTDOC_COMPILER_MISMATCH` until it is recompiled.
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [1.2.0] - 2026-10-27
|
|
13
|
+
|
|
14
|
+
Rust and Python are now supported at the same level as Node and Go. Before
|
|
15
|
+
this release, a Cargo crate or a Python package was invisible to the compiler:
|
|
16
|
+
`agentdoc audit` reported zero units, and a hand-written descriptor produced a
|
|
17
|
+
component with no language, no dependency edges and no verification commands.
|
|
18
|
+
|
|
19
|
+
The release also fixes how a change is routed. `impact` and `query` now follow
|
|
20
|
+
the components that depend on the changed one, not the ones it depends on, and
|
|
21
|
+
recommend those dependents' checks.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **`rust` adapter** ([#17]). Reads `Cargo.toml` and never runs Cargo or reads
|
|
26
|
+
`Cargo.lock`.
|
|
27
|
+
- A `[package]` is a unit. `[[bin]]`, `src/main.rs` or `src/bin/` make it
|
|
28
|
+
deployable; `[lib]` or `src/lib.rs` make it importable.
|
|
29
|
+
- Workspace members come from every `[workspace]` manifest, including one
|
|
30
|
+
below the repository root (`rust/Cargo.toml` next to other languages).
|
|
31
|
+
- Sibling crates become `buildDependsOn` / `testDependsOn` edges when the
|
|
32
|
+
manifest says so: a `path`, `workspace = true` resolved through the nearest
|
|
33
|
+
`[workspace.dependencies]`, or a `[patch.<registry>]` / `[replace]` path
|
|
34
|
+
redirect inside the repository. `use`, `extern crate` and `<crate>::` paths
|
|
35
|
+
add provenance to those edges but never create one, because Rust cannot
|
|
36
|
+
use a crate the manifest does not declare.
|
|
37
|
+
- Verification commands: `cargo test -p <name>` and `cargo clippy -p <name>`.
|
|
38
|
+
- Resource vocabulary: sqlx, diesel (`diesel.toml`), tokio-postgres,
|
|
39
|
+
deadpool, sea-orm, the `redis` crate and `aws-sdk-s3`.
|
|
40
|
+
- **`python` adapter** ([#18]). Reads `pyproject.toml` (PEP 621 and Poetry),
|
|
41
|
+
`setup.cfg`, `setup.py` and `requirements*.txt`. It never runs Python,
|
|
42
|
+
resolves a lockfile or inspects a virtualenv.
|
|
43
|
+
- Shape comes from evidence. An entrypoint (`[project.scripts]`,
|
|
44
|
+
`__main__.py`, `manage.py`, an ASGI/WSGI app object) makes a unit
|
|
45
|
+
deployable; a build backend plus a package makes it importable.
|
|
46
|
+
- uv workspace members come from the repository root and from workspaces
|
|
47
|
+
below it. A member with no build backend is still a unit.
|
|
48
|
+
- Sibling packages become edges from `[project] dependencies`,
|
|
49
|
+
`[tool.uv.sources]`, Poetry `path` dependencies, `-e <dir>` requirements,
|
|
50
|
+
and `import` / `from` statements. Dev groups and dev/test extras give
|
|
51
|
+
`testDependsOn`. An import that the importing unit provides itself, such
|
|
52
|
+
as a local `utils.py`, is not read as a sibling.
|
|
53
|
+
- Verification commands are derived only from evidence: `pytest`,
|
|
54
|
+
`python -m unittest discover` for unittest-only suites, `ruff check` and
|
|
55
|
+
`mypy`. `uv run` / `poetry run` is prefixed only when the lockfile names
|
|
56
|
+
the tool.
|
|
57
|
+
- Also derived: `requiresPython` when declared, and Alembic migrations as
|
|
58
|
+
database evidence.
|
|
59
|
+
- Resource vocabulary: SQLAlchemy, asyncpg, psycopg, Django `DATABASES`,
|
|
60
|
+
`redis.Redis` and boto3.
|
|
61
|
+
- `agentdoc init` enables `rust` and `python` when it finds their manifests.
|
|
62
|
+
`agentdoc scaffold` names crates and distributions from their manifests and
|
|
63
|
+
types them from their artifact shape: `service`, `library`, or `other` when
|
|
64
|
+
neither is proven. A virtual Cargo or uv workspace manifest is not scaffolded.
|
|
65
|
+
- A reproducible benchmark, `scripts/bench/run.mjs` ([docs/BENCHMARK.md]).
|
|
66
|
+
It clones four public repositories at pinned commits, runs a fresh
|
|
67
|
+
`init` → `scaffold` → `compile`, counts every hand edit the setup still
|
|
68
|
+
needs (zero for all four), checks that the graph is byte-identical across
|
|
69
|
+
compiles, and measures `query` answers.
|
|
70
|
+
- The routing evaluation reports **check selectivity**: the share of the
|
|
71
|
+
repository's checks that the answer for a change contains ([#43]). The
|
|
72
|
+
baseline's verification recall is now scored with the same rule as the
|
|
73
|
+
catalog's. It is 1.0 by construction, because the baseline runs every check.
|
|
74
|
+
- Rust and Python sample repositories (`fixtures/e-rust-workspace`,
|
|
75
|
+
`fixtures/f-python-workspace`), checked in CI and used to test context
|
|
76
|
+
routing ([#23]).
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- **Change routing follows dependents** ([#30], [#25]).
|
|
81
|
+
- A change to a component reaches the components that depend on it,
|
|
82
|
+
transitively, through reverse `buildDependsOn` / `testDependsOn` edges.
|
|
83
|
+
Before, `impact` also listed the components it depends on as affected,
|
|
84
|
+
and did not follow transitive dependents.
|
|
85
|
+
- Dependencies stay visible as typed relations in `query`. They are no
|
|
86
|
+
longer reported as affected components.
|
|
87
|
+
- `query` and `impact` recommend the dependents' checks after the changed
|
|
88
|
+
component's own: every tier for build dependents, unit checks only for test
|
|
89
|
+
dependents.
|
|
90
|
+
- `impact` adds `recommendedVerificationTotal` and
|
|
91
|
+
`recommendedVerificationTruncated`, so a capped list is never mistaken for
|
|
92
|
+
the whole.
|
|
93
|
+
- **`query` markdown shows an entity's context** ([#28]). Resources and
|
|
94
|
+
Systems now list their `docs`, `CONSTRAINTS` and `runbooks`, as components
|
|
95
|
+
already did. Constraints are never capped by default. Docs and runbooks show
|
|
96
|
+
12 paths each, and `--budget docs=…,constraints=…,runbooks=…` sets explicit
|
|
97
|
+
caps with a `[truncated: x of y]` marker.
|
|
98
|
+
- **`discovery.notUnitRoots` excludes a whole subtree from inferred units**
|
|
99
|
+
([#27]). An adapter marker or a scaffold proposal at or below an excluded
|
|
100
|
+
root is no longer a unit. A hand-written descriptor below an excluded root
|
|
101
|
+
is still honoured. A descriptor exactly at an excluded root is refused with
|
|
102
|
+
a message that names the exclusion.
|
|
103
|
+
- **GitHub Actions checks are scoped to the components they run for**
|
|
104
|
+
([#29]). A step becomes a component check only when its command is a
|
|
105
|
+
recognised test, lint or build invocation, scoped by `working-directory`,
|
|
106
|
+
`cd <dir> &&`, a path argument, a package selector (`--filter`, turbo, nx,
|
|
107
|
+
`make -C`) or a `paths:` filter. Repository scripts whose names say what
|
|
108
|
+
they check (`./scripts/test.sh`, `bash scripts/lint.sh`) are recognised
|
|
109
|
+
with the same scoping ([#40]). Anything else is a repository gate.
|
|
110
|
+
- Before, every step was attached to every component whose path or package
|
|
111
|
+
name appeared anywhere in the workflow, including multi-line ops scripts.
|
|
112
|
+
A shell `test -n` was also recorded as a unit test.
|
|
113
|
+
- `impact` on a workflow file now names the components and gates derived
|
|
114
|
+
from it, plus their dependents' checks.
|
|
115
|
+
- **The TOML reader conforms to TOML 1.0** ([#18], [#31]). It reads
|
|
116
|
+
`Cargo.toml`, `pyproject.toml` and `wrangler.toml`, and passes every case of
|
|
117
|
+
the official [toml-test](https://github.com/toml-lang/toml-test) 1.0.0
|
|
118
|
+
suite: 208 valid and 501 invalid documents. Before, it rejected valid
|
|
119
|
+
documents, such as multi-line strings and lowercase date-time delimiters,
|
|
120
|
+
which lost every fact in the file. It also accepted invalid ones, such as a
|
|
121
|
+
trailing comma in an inline table or a table declared twice. Invalid TOML
|
|
122
|
+
is rejected with `AGENTDOC_YAML_PARSE`.
|
|
123
|
+
|
|
124
|
+
### Fixed
|
|
125
|
+
|
|
126
|
+
- **A unit nested inside another unit no longer leaks its facts into the
|
|
127
|
+
parent** ([#21]). Every per-unit scan stops at nested units, so each file
|
|
128
|
+
belongs to the deepest unit that contains it. Before, an enclosing unit also
|
|
129
|
+
claimed its nested unit's health routes, ports, capabilities, resource and
|
|
130
|
+
migration evidence, imports, contract consumers, TypeScript routes, Ansible
|
|
131
|
+
playbooks and test markers. This affects any layout with nested units, such
|
|
132
|
+
as a service containing a tool package, a Cargo root package with member
|
|
133
|
+
crates below it, or a uv workspace root with its own `[project]`.
|
|
134
|
+
- An Alembic `alembic/versions` directory was listed as a migration location
|
|
135
|
+
but never recognised. It now counts as migration evidence. The evidence file
|
|
136
|
+
is a qualifying `alembic.ini` or `[tool.alembic]` configuration when one
|
|
137
|
+
exists, and otherwise a revision file.
|
|
138
|
+
- A changed migration, including an Alembic revision, now lists the logical
|
|
139
|
+
database its component uses in `impact`'s `affectedResources` ([#30]).
|
|
140
|
+
Before, the list stayed empty.
|
|
141
|
+
- The audit no longer reports a document as orphaned when it is linked only
|
|
142
|
+
from a Resource's or System's `context` ([#28]).
|
|
143
|
+
- `agentdoc scaffold --write` no longer writes descriptors into directories
|
|
144
|
+
listed in `discovery.notUnitRoots` ([#27]).
|
|
145
|
+
- **A fresh setup compiles without hand edits** ([#37], [#38]).
|
|
146
|
+
- `scaffold` now types every unit from its artifact evidence: `service`,
|
|
147
|
+
`library`, or `other` when neither is proven. Before, a Node app without
|
|
148
|
+
`exports` or `main`, or a Go module, was written as `library` and failed
|
|
149
|
+
`validate` straight away.
|
|
150
|
+
- `init` now discovers descriptors with the `*/**/agentdoc.yaml` glob
|
|
151
|
+
instead of an explicit list, and `scaffold` covers every unit an adapter
|
|
152
|
+
declares, including workspace members under `examples/`.
|
|
153
|
+
- A `setup.py` unit is named after the distribution it declares, and the
|
|
154
|
+
`python` adapter reads `name`, `python_requires` and `install_requires`
|
|
155
|
+
inside a one-line `setup(…)` or `setuptools.setup(…)` call ([#41]).
|
|
156
|
+
- On the four public repositories used for benchmarking (tokio-rs/axum,
|
|
157
|
+
pydantic/pydantic-ai, fastapi/full-stack-fastapi-template and
|
|
158
|
+
t3-oss/create-t3-turbo), `init` + `scaffold --write` + `compile` now pass
|
|
159
|
+
with no edits other than choosing each component's placement.
|
|
160
|
+
|
|
161
|
+
### Upgrading
|
|
162
|
+
|
|
163
|
+
- The compiler version is now `1.2.0`. A graph committed with 1.1.0 fails
|
|
164
|
+
`agentdoc check` with `AGENTDOC_COMPILER_MISMATCH`. Run `agentdoc compile`
|
|
165
|
+
and commit the graph.
|
|
166
|
+
- An existing catalog keeps its adapter list. To use the new adapters, add
|
|
167
|
+
`rust` and/or `python` to `adapters:` in `agentdoc/agentdoc.config.yaml`,
|
|
168
|
+
then run `agentdoc audit`: units that were invisible appear as
|
|
169
|
+
`AGENTDOC_COVERAGE_ZERO` until they have a descriptor.
|
|
170
|
+
`agentdoc scaffold --write` writes those descriptors.
|
|
171
|
+
- If your repository has nested units, recompiling removes facts that were
|
|
172
|
+
wrongly attributed to an enclosing component. Review the affected facts,
|
|
173
|
+
dependency edges and verification commands, and any descriptor or document
|
|
174
|
+
that relied on them.
|
|
175
|
+
- Tools that read `impact --json` will see fewer `affectedComponents`
|
|
176
|
+
(dependencies are gone) and more `recommendedVerification` entries
|
|
177
|
+
(dependents' checks).
|
|
178
|
+
- A unit inferred below a `notUnitRoots` entry, with no descriptor, is no
|
|
179
|
+
longer reported as `AGENTDOC_COVERAGE_ZERO`. If it should be a component,
|
|
180
|
+
write its descriptor, or remove the directory from `notUnitRoots`.
|
|
181
|
+
- If your workflows run checks for specific components, recompiling changes
|
|
182
|
+
which checks are attached to which component. Review the diff: checks that
|
|
183
|
+
were attached only because a path was mentioned elsewhere in the workflow
|
|
184
|
+
move to repository gates.
|
|
185
|
+
- Recompiling always updates the compiler version, source commit and input
|
|
186
|
+
hash. Review the other derived changes, especially in repositories with
|
|
187
|
+
nested units, Alembic migrations or Wrangler TOML manifests: a manifest the
|
|
188
|
+
old TOML reader could not parse now yields facts.
|
|
189
|
+
|
|
190
|
+
## [1.1.0] - 2026-10-18
|
|
191
|
+
|
|
192
|
+
### Added
|
|
193
|
+
|
|
194
|
+
- **MIGRATE gates normative requirements and section coverage** ([#5]).
|
|
195
|
+
Documentation checks now state their real scope, and the strict gate refuses
|
|
196
|
+
unverified requirements.
|
|
197
|
+
- **`ansible` adapter** ([#6]). Reads playbooks without running anything and
|
|
198
|
+
derives installed paths and managed services. A requirement with
|
|
199
|
+
`satisfiedBy: [ansible]` and the new `expects` field
|
|
200
|
+
(`installs: <path>` | `service: <name>`) is checked against them, so a missing
|
|
201
|
+
install ends in a conflict instead of `AGENTDOC_REQUIREMENT_UNVERIFIED`.
|
|
202
|
+
- `agentdoc <command> --help` lists each command's flags and exit codes ([#7]).
|
|
203
|
+
|
|
204
|
+
### Changed
|
|
205
|
+
|
|
206
|
+
- **The CLI rejects unknown flags** ([#7]) and names the closest valid flag. A
|
|
207
|
+
typo such as `check --strcit` no longer silently runs a non-strict check.
|
|
208
|
+
Scripts that passed flags a command does not accept now exit 2.
|
|
209
|
+
|
|
210
|
+
### Fixed
|
|
211
|
+
|
|
212
|
+
- A committed graph passes CI ([#11]). `check` no longer fails with
|
|
213
|
+
`AGENTDOC_GRAPH_FRESHNESS` after `compile` on a clean checkout, where the
|
|
214
|
+
graph file itself was counted as a changed input.
|
|
215
|
+
- A nested `.github/workflows` directory no longer fails `validate` ([#12]).
|
|
216
|
+
Only the repository-root directory is read, as GitHub does.
|
|
217
|
+
|
|
218
|
+
### Upgrading
|
|
219
|
+
|
|
220
|
+
- A graph committed with 1.0.0 fails `agentdoc check` with
|
|
221
|
+
`AGENTDOC_COMPILER_MISMATCH` until it is recompiled.
|
|
222
|
+
|
|
223
|
+
## [1.0.0] - 2026-09-29
|
|
224
|
+
|
|
225
|
+
First public release.
|
|
226
|
+
|
|
227
|
+
### Added
|
|
228
|
+
|
|
229
|
+
- The machine-installed `agentdoc` CLI for Node 22, 24 and 26, with zero
|
|
230
|
+
runtime dependencies.
|
|
231
|
+
- A deterministic repository graph: repeated compiles of the same tree are
|
|
232
|
+
byte-identical.
|
|
233
|
+
- Evidence separation between AUTHORED documentation, DERIVED facts extracted
|
|
234
|
+
from code, and OBSERVED runtime evidence.
|
|
235
|
+
- A fail-closed authority model: contradictions surface as conflicts and are
|
|
236
|
+
never silently overwritten.
|
|
237
|
+
- `agentdoc query`, which routes minimal, budgeted context for a task, and
|
|
238
|
+
`agentdoc impact`, which reports what a change forces you to keep consistent.
|
|
239
|
+
- CREATE and MIGRATE workflows through `init`, `audit`, `scaffold`,
|
|
240
|
+
`validate`, `compile` and `check`.
|
|
241
|
+
- `agentdoc doctor` for machine diagnostics, and `agentdoc doctor --project`
|
|
242
|
+
for project health.
|
|
243
|
+
- An Agent Skill under `skills/agent-doc-system/`.
|
|
244
|
+
|
|
245
|
+
[Unreleased]: https://github.com/lbframe/agent-doc-system/compare/v1.2.0...HEAD
|
|
246
|
+
[1.2.0]: https://github.com/lbframe/agent-doc-system/compare/v1.1.0...v1.2.0
|
|
247
|
+
[1.1.0]: https://github.com/lbframe/agent-doc-system/compare/v1.0.0...v1.1.0
|
|
248
|
+
[1.0.0]: https://github.com/lbframe/agent-doc-system/releases/tag/v1.0.0
|
|
249
|
+
[docs/BENCHMARK.md]: docs/BENCHMARK.md
|
|
250
|
+
[#5]: https://github.com/lbframe/agent-doc-system/issues/5
|
|
251
|
+
[#6]: https://github.com/lbframe/agent-doc-system/issues/6
|
|
252
|
+
[#7]: https://github.com/lbframe/agent-doc-system/issues/7
|
|
253
|
+
[#11]: https://github.com/lbframe/agent-doc-system/issues/11
|
|
254
|
+
[#12]: https://github.com/lbframe/agent-doc-system/issues/12
|
|
255
|
+
[#17]: https://github.com/lbframe/agent-doc-system/issues/17
|
|
256
|
+
[#18]: https://github.com/lbframe/agent-doc-system/issues/18
|
|
257
|
+
[#21]: https://github.com/lbframe/agent-doc-system/issues/21
|
|
258
|
+
[#23]: https://github.com/lbframe/agent-doc-system/issues/23
|
|
259
|
+
[#25]: https://github.com/lbframe/agent-doc-system/issues/25
|
|
260
|
+
[#27]: https://github.com/lbframe/agent-doc-system/issues/27
|
|
261
|
+
[#28]: https://github.com/lbframe/agent-doc-system/issues/28
|
|
262
|
+
[#29]: https://github.com/lbframe/agent-doc-system/issues/29
|
|
263
|
+
[#30]: https://github.com/lbframe/agent-doc-system/issues/30
|
|
264
|
+
[#31]: https://github.com/lbframe/agent-doc-system/issues/31
|
|
265
|
+
[#37]: https://github.com/lbframe/agent-doc-system/issues/37
|
|
266
|
+
[#38]: https://github.com/lbframe/agent-doc-system/issues/38
|
|
267
|
+
[#40]: https://github.com/lbframe/agent-doc-system/issues/40
|
|
268
|
+
[#41]: https://github.com/lbframe/agent-doc-system/issues/41
|
|
269
|
+
[#43]: https://github.com/lbframe/agent-doc-system/issues/43
|
package/README.md
CHANGED
|
@@ -69,6 +69,41 @@ AgentDoc turns scattered repository knowledge into task-specific context your co
|
|
|
69
69
|
|
|
70
70
|

|
|
71
71
|
|
|
72
|
+
## What it understands
|
|
73
|
+
|
|
74
|
+
AgentDoc reads manifests, contracts and configuration. It never runs your toolchain.
|
|
75
|
+
|
|
76
|
+
Support comes from adapters and from built-in contract validation (AsyncAPI needs no adapter).
|
|
77
|
+
- `agentdoc init` picks `node`, `go`, `rust`, `python`, `dockerfile` and `wrangler` from the files it finds.
|
|
78
|
+
- It always includes `database`, `openapi`, `events` and `github-actions`.
|
|
79
|
+
- Add the others in `agentdoc/agentdoc.config.yaml`.
|
|
80
|
+
|
|
81
|
+
| area | supported |
|
|
82
|
+
|---|---|
|
|
83
|
+
| languages & packages | Node (npm, pnpm workspaces, Turborepo), TypeScript, Go (modules, `go.work`), Rust (Cargo packages and workspaces), Python (`pyproject.toml` with PEP 621 or Poetry, uv workspaces, `setup.cfg` / `setup.py`, `requirements*.txt`) |
|
|
84
|
+
| contracts | OpenAPI, protobuf, GraphQL, AsyncAPI, OIDC discovery |
|
|
85
|
+
| deployment & CI | Dockerfile / Containerfile, `fly.toml`, `Procfile` and similar deploy configs, Cloudflare Wrangler, Ansible playbooks, GitHub Actions |
|
|
86
|
+
| resources | databases (migrations, ORM config, connection evidence), caches, object stores, event subjects |
|
|
87
|
+
|
|
88
|
+
For each language, AgentDoc derives:
|
|
89
|
+
|
|
90
|
+
- the units;
|
|
91
|
+
- whether each one is deployable or importable;
|
|
92
|
+
- dependency edges between sibling units;
|
|
93
|
+
- verification commands taken from the repository's own evidence (`go test`, `cargo test -p`, `pytest`, `python -m unittest`, npm scripts, …).
|
|
94
|
+
|
|
95
|
+
What every adapter derives, and what it deliberately cannot see, is in [docs/ADAPTERS.md](docs/ADAPTERS.md).
|
|
96
|
+
|
|
97
|
+
## By the numbers
|
|
98
|
+
|
|
99
|
+
Measured, reproducible, and with no model in the loop. Method and caveats are in [docs/BENCHMARK.md](docs/BENCHMARK.md).
|
|
100
|
+
|
|
101
|
+
- **The right context: 100% vs. 58%.** Across 30 routing scenarios (Node, Go, Rust, Python), `query` + `impact` retrieves every fact the change needs. Reading only the touched component retrieves 58%. Noise stays under 9%, against 40%. Every check the change requires is in the answer, and that answer holds about half of the repository's checks (29% on the largest corpus), not all of them. The thresholds were fixed before the first run and have not moved since.
|
|
102
|
+
- **Seconds to map a real repository.** A fresh `init` → `scaffold` → `compile` takes 1.0–4.6 s on four public repositories, from 141 to 5,142 files (axum, pydantic-ai, full-stack-fastapi-template, create-t3-turbo). No edit was needed beyond choosing each component's placement.
|
|
103
|
+
- **A briefing, not a dump.** A `query` answer is about 100–260 tokens: what the change reaches, what to read, and which checks to run.
|
|
104
|
+
- **The same graph every time.** Compiles are byte-identical, and CI can verify it.
|
|
105
|
+
- **Small and strict.** Zero runtime dependencies, a package of about 285 kB packed, 21 adapters, and 709/709 cases on the official TOML 1.0 conformance suite.
|
|
106
|
+
|
|
72
107
|
## Install manually
|
|
73
108
|
|
|
74
109
|
Requires Node.js 22+.
|
|
@@ -92,7 +127,10 @@ AgentDoc also ships with an Agent Skill at [`skills/agent-doc-system/`](skills/a
|
|
|
92
127
|
- [Authority & conflicts](docs/AUTHORITY.md)
|
|
93
128
|
- [CI & verification](docs/CI.md)
|
|
94
129
|
- [Specification](docs/SPEC.md)
|
|
130
|
+
- [Adapters](docs/ADAPTERS.md)
|
|
131
|
+
- [Benchmark](docs/BENCHMARK.md)
|
|
95
132
|
- [Agent Skill](skills/agent-doc-system/SKILL.md)
|
|
133
|
+
- [Changelog](CHANGELOG.md)
|
|
96
134
|
|
|
97
135
|
## License
|
|
98
136
|
|
package/adapters/ansible.mjs
CHANGED
|
@@ -132,7 +132,7 @@ function isYaml(f) {
|
|
|
132
132
|
|
|
133
133
|
function playbooks(repo, root) {
|
|
134
134
|
const out = [];
|
|
135
|
-
for (const f of repo.
|
|
135
|
+
for (const f of repo.walkUnit(root)) {
|
|
136
136
|
if (!isYaml(f) || /(^|\/)(tasks|handlers|vars|defaults|meta|group_vars|host_vars|templates|files)\//.test(f.slice(root.length))) continue;
|
|
137
137
|
const docs = parse(repo, f);
|
|
138
138
|
if (!docs) continue;
|
package/adapters/cache.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Cache adapter: Redis / in-memory cache client evidence as a derived binding.
|
|
2
2
|
import { Adapter } from "./registry.mjs";
|
|
3
3
|
|
|
4
|
-
const CACHE_HINT = /(@upstash\/redis|ioredis|redis|go-redis|redis\.go|valkey|memcache|@memcached)/i;
|
|
4
|
+
const CACHE_HINT = /(@upstash\/redis|ioredis|redis\.Redis|redis|go-redis|redis\.go|valkey|memcache|@memcached)/i;
|
|
5
5
|
|
|
6
6
|
export class CacheAdapter extends Adapter {
|
|
7
7
|
static adapterName = "cache";
|
|
@@ -10,7 +10,13 @@ export class CacheAdapter extends Adapter {
|
|
|
10
10
|
}
|
|
11
11
|
extract(ctx, unit) {
|
|
12
12
|
const { repo, prov, compRef } = ctx;
|
|
13
|
-
const evFile = unit.goModule
|
|
13
|
+
const evFile = unit.goModule
|
|
14
|
+
? unit.root + "/go.mod"
|
|
15
|
+
: unit.pythonManifest
|
|
16
|
+
? unit.pythonManifest
|
|
17
|
+
: repo.exists(unit.root + "/package.json")
|
|
18
|
+
? unit.root + "/package.json"
|
|
19
|
+
: unit.root + "/Cargo.toml";
|
|
14
20
|
if (!repo.exists(evFile)) return {};
|
|
15
21
|
const text = repo.readText(evFile);
|
|
16
22
|
if (!CACHE_HINT.test(text)) return {};
|
|
@@ -18,7 +18,7 @@ const DOC_EXT = /\.(md|mdx|txt|adoc|rst)$/;
|
|
|
18
18
|
|
|
19
19
|
export function contractReferenceSites(repo, unit) {
|
|
20
20
|
const out = new Map(); // file -> true
|
|
21
|
-
for (const f of repo.
|
|
21
|
+
for (const f of repo.walkUnit(unit.root)) {
|
|
22
22
|
const base = path.posix.basename(f);
|
|
23
23
|
if (DOC_EXT.test(f)) continue;
|
|
24
24
|
if (f.includes("/docs/") || f.startsWith("docs/")) continue;
|
package/adapters/database.mjs
CHANGED
|
@@ -15,6 +15,9 @@ const ORM_CONFIG = [
|
|
|
15
15
|
"prisma/schema.prisma", "schema.prisma",
|
|
16
16
|
"knexfile.js", "knexfile.ts", "sequelize.config.js", "ormconfig.json",
|
|
17
17
|
];
|
|
18
|
+
// Probed only for a Cargo package. Adding it to the list above would record
|
|
19
|
+
// a new existence probe on every non-Rust unit and change those graphs.
|
|
20
|
+
const RUST_ORM_CONFIG = ["diesel.toml"];
|
|
18
21
|
|
|
19
22
|
export class DatabaseAdapter extends Adapter {
|
|
20
23
|
static adapterName = "database";
|
|
@@ -25,12 +28,23 @@ export class DatabaseAdapter extends Adapter {
|
|
|
25
28
|
const { repo, prov, compRef } = ctx;
|
|
26
29
|
const root = unit.root;
|
|
27
30
|
const migrationDirs = findMigrationDirs(repo, root);
|
|
28
|
-
const ormConfig = firstExistingFile(repo, root, ORM_CONFIG);
|
|
31
|
+
const ormConfig = firstExistingFile(repo, root, unit.cargoPackage ? ORM_CONFIG.concat(RUST_ORM_CONFIG) : ORM_CONFIG);
|
|
29
32
|
if (!migrationDirs.length && !ormConfig) return {};
|
|
30
33
|
|
|
31
34
|
let evidencePath = ormConfig;
|
|
32
35
|
if (migrationDirs.length) {
|
|
33
|
-
evidencePath = repo.
|
|
36
|
+
evidencePath = repo.walkUnit(root, migrationDirs[0])[0] || migrationDirs[0];
|
|
37
|
+
}
|
|
38
|
+
const alembicDir = migrationDirs.find((d) => d === "alembic/versions" || d.endsWith("/alembic/versions"));
|
|
39
|
+
if (alembicDir) {
|
|
40
|
+
const ini = root + "/alembic.ini";
|
|
41
|
+
const pyproject = root + "/pyproject.toml";
|
|
42
|
+
if (repo.exists(ini)) {
|
|
43
|
+
const text = repo.readText(ini);
|
|
44
|
+
if (/^\s*\[alembic\]/m.test(text) || /^\s*script_location\s*=/m.test(text)) evidencePath = ini;
|
|
45
|
+
} else if (repo.exists(pyproject) && /\[tool\.alembic\]/.test(repo.readText(pyproject))) {
|
|
46
|
+
evidencePath = pyproject;
|
|
47
|
+
}
|
|
34
48
|
}
|
|
35
49
|
const pr = prov.add("observed", evidencePath, "migration-extractor", ["der:" + compRef + ":/bindings"]);
|
|
36
50
|
|
|
@@ -93,10 +107,10 @@ export class DatabaseAdapter extends Adapter {
|
|
|
93
107
|
}
|
|
94
108
|
}
|
|
95
109
|
|
|
96
|
-
const POOL_HINT = /(createPool|new Pool|pg\.Pool|psycopg2?\.connect|sql\.Open|mysql\.createConnection|Pool\(|DataSource|prisma\.(datasource|client)|DATABASE_URL|DB_DSN)/;
|
|
110
|
+
const POOL_HINT = /(createPool|new Pool|pg\.Pool|PgPool|psycopg2?\.connect|asyncpg\.(?:connect|create_pool)|sql\.Open|mysql\.createConnection|Pool\(|DataSource|prisma\.(datasource|client)|DATABASE_URL|DB_DSN|sqlx::migrate!|tokio_postgres|tokio-postgres|deadpool|sea_orm|sea-orm|diesel::|create_engine\s*\(|\bDATABASES\s*=)/;
|
|
97
111
|
|
|
98
112
|
function hasConnectionEvidence(ctx, unit) {
|
|
99
|
-
for (const f of ctx.repo.
|
|
113
|
+
for (const f of ctx.repo.walkUnit(unit.root)) {
|
|
100
114
|
if (/\.(ts|tsx|js|mjs|go|py|rb|java|kt|rs|ex|cs|php)$/.test(f)) {
|
|
101
115
|
if (/(^|\/)(tests?|__tests__)\//.test(f)) continue;
|
|
102
116
|
if (POOL_HINT.test(ctx.repo.readText(f))) return true;
|
package/adapters/events.mjs
CHANGED
|
@@ -70,7 +70,7 @@ export class EventsAdapter extends Adapter {
|
|
|
70
70
|
if (other.component && visible.has(other.component.ref) && other.component.ref !== compRef) collectDecls(other.root);
|
|
71
71
|
}
|
|
72
72
|
const families = new Set();
|
|
73
|
-
for (const f of repo.
|
|
73
|
+
for (const f of repo.walkUnit(unit.root)) {
|
|
74
74
|
if (!SRC_EXT.test(f)) continue;
|
|
75
75
|
if (TEST_PATH.test(f) || TEST_FILE.test(f)) continue;
|
|
76
76
|
const text = repo.readText(f);
|