doctracker 0.1.0__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.
- doctracker-0.1.0/LICENSE +21 -0
- doctracker-0.1.0/PKG-INFO +234 -0
- doctracker-0.1.0/README.md +202 -0
- doctracker-0.1.0/pyproject.toml +48 -0
- doctracker-0.1.0/pyproject.toml.orig +44 -0
- doctracker-0.1.0/src/doctracker/__init__.py +5 -0
- doctracker-0.1.0/src/doctracker/__main__.py +4 -0
- doctracker-0.1.0/src/doctracker/cli.py +55 -0
- doctracker-0.1.0/src/doctracker/config.py +65 -0
- doctracker-0.1.0/src/doctracker/extraction/__init__.py +5 -0
- doctracker-0.1.0/src/doctracker/extraction/griffe_loader.py +148 -0
- doctracker-0.1.0/src/doctracker/server/__init__.py +1 -0
- doctracker-0.1.0/src/doctracker/server/app.py +78 -0
- doctracker-0.1.0/src/doctracker/server/guide.md +62 -0
- doctracker-0.1.0/src/doctracker/server/guide.py +68 -0
- doctracker-0.1.0/src/doctracker/server/state.py +32 -0
- doctracker-0.1.0/src/doctracker/server/tools.py +76 -0
- doctracker-0.1.0/src/doctracker/server/watcher.py +63 -0
- doctracker-0.1.0/src/doctracker/server/web.py +120 -0
- doctracker-0.1.0/src/doctracker/wiki/__init__.py +1 -0
- doctracker-0.1.0/src/doctracker/wiki/pages.py +356 -0
- doctracker-0.1.0/src/doctracker/wiki/static/htmx-LICENSE.txt +13 -0
- doctracker-0.1.0/src/doctracker/wiki/static/htmx.min.js +1 -0
- doctracker-0.1.0/src/doctracker/wiki/static/live.js +178 -0
- doctracker-0.1.0/src/doctracker/wiki/static/style.css +424 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/base.html +33 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/entity.html +97 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/fragment.html +3 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/fragment_content.html +5 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/header.html +20 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/loading.html +2 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/members.html +18 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/module.html +19 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/not_found.html +6 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/search.html +21 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/source.html +1 -0
- doctracker-0.1.0/src/doctracker/wiki/templates/tree.html +31 -0
doctracker-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Carlos Filipe de Castro Lemos
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: doctracker
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server that centralizes the documentation of Python projects developed with LLM agents.
|
|
5
|
+
Author: Carlos Filipe de Castro Lemos
|
|
6
|
+
Author-email: Carlos Filipe de Castro Lemos <carlos.lemos.dev@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: src/doctracker/wiki/static/htmx-LICENSE.txt
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
19
|
+
Requires-Dist: click>=8.5.0
|
|
20
|
+
Requires-Dist: griffe>=2.4.1
|
|
21
|
+
Requires-Dist: jinja2>=3.1.6
|
|
22
|
+
Requires-Dist: markdown-it-py>=4.2.0
|
|
23
|
+
Requires-Dist: mcp>=2.3.0,<3
|
|
24
|
+
Requires-Dist: pygments>=2.21.0
|
|
25
|
+
Requires-Dist: starlette>=1.10.0
|
|
26
|
+
Requires-Dist: uvicorn>=0.54.0
|
|
27
|
+
Requires-Python: >=3.11
|
|
28
|
+
Project-URL: Homepage, https://github.com/cfclemos/doctracker
|
|
29
|
+
Project-URL: Repository, https://github.com/cfclemos/doctracker
|
|
30
|
+
Project-URL: Issues, https://github.com/cfclemos/doctracker/issues
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# DOCUMENTATION TRACKER (DOCTRACKER)
|
|
34
|
+
|
|
35
|
+
**One place for the documentation of a Python project developed with LLM agents.**
|
|
36
|
+
|
|
37
|
+
When agents work on a codebase, documentation ends up scattered: notes in many
|
|
38
|
+
Markdown files, memories, code comments and commit messages, all drifting out of
|
|
39
|
+
sync. Documentation Tracker (doctracker) centralizes it. It runs an [MCP](https://modelcontextprotocol.io)
|
|
40
|
+
server that any agent (Claude Code, OpenCode, …) can connect to, and serves a live
|
|
41
|
+
wiki of the project in your browser.
|
|
42
|
+
|
|
43
|
+
> **Status: alpha (0.1).** This first version builds the technical reference of the
|
|
44
|
+
> code. Notes, commit history and LLM summaries come in the next versions (see
|
|
45
|
+
> [Roadmap](#roadmap)).
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- **Technical reference built from the code** — modules, classes, functions,
|
|
50
|
+
methods and attributes, with signatures, type hints, decorators and parsed
|
|
51
|
+
docstrings (Google, NumPy or Sphinx style).
|
|
52
|
+
- **Static analysis only** — the code is read with [griffe](https://mkdocstrings.github.io/griffe/),
|
|
53
|
+
never imported or executed.
|
|
54
|
+
- **Live wiki** — edit a file and the open page updates by itself.
|
|
55
|
+
- **MCP server** — agents can list and read the documentation, and get a guide on
|
|
56
|
+
how to document the code so the wiki stays complete.
|
|
57
|
+
- **Search** — by name, path and description, with keyboard navigation.
|
|
58
|
+
- **Everything in one folder** — doctracker keeps its files in `doc/` inside your
|
|
59
|
+
project and never touches anything else.
|
|
60
|
+
- **Cross-platform** — Windows and Linux, Python 3.11+.
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
Install it as a development dependency of the project you want to document:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
uv add --dev doctracker
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
or with pip:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install doctracker
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Quick start
|
|
77
|
+
|
|
78
|
+
From the root of your project:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
doctracker init # creates doc/config/config.json (packages are detected automatically)
|
|
82
|
+
doctracker start # starts the server
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
With uv, prefix the commands with `uv run` (e.g. `uv run doctracker start`).
|
|
86
|
+
`start` runs `init` on its own if the project has no configuration yet.
|
|
87
|
+
|
|
88
|
+
The server prints its two addresses:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
Wiki: http://127.0.0.1:8765/
|
|
92
|
+
MCP: http://127.0.0.1:8765/mcp
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Open the wiki in your browser. Keep the server running while you work on the code;
|
|
96
|
+
stop it with `Ctrl+C`.
|
|
97
|
+
|
|
98
|
+
## Connecting an agent
|
|
99
|
+
|
|
100
|
+
The MCP server uses the Streamable HTTP transport at `http://127.0.0.1:8765/mcp`.
|
|
101
|
+
The server must be running before the agent connects.
|
|
102
|
+
|
|
103
|
+
**Claude Code** — add a `.mcp.json` file at the root of your project:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"mcpServers": {
|
|
108
|
+
"doctracker": { "type": "http", "url": "http://127.0.0.1:8765/mcp" }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
or register it from the terminal:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
claude mcp add --transport http doctracker http://127.0.0.1:8765/mcp
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**OpenCode** — in `opencode.json`:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"mcp": {
|
|
124
|
+
"doctracker": { "type": "remote", "url": "http://127.0.0.1:8765/mcp" }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Other agents** — any MCP client that supports Streamable HTTP can connect to the
|
|
130
|
+
same URL.
|
|
131
|
+
|
|
132
|
+
### What the agent gets
|
|
133
|
+
|
|
134
|
+
| Name | Kind | What it does |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| `list_entities` | tool | Lists documented entities, filtered by path prefix and kind. |
|
|
137
|
+
| `get_entity` | tool | Full technical reference of one entity. |
|
|
138
|
+
| `status` | tool | Whether the documentation is built, and loading errors. |
|
|
139
|
+
| `documentation_guide` | tool | How to document this project's code (adapted to its settings). |
|
|
140
|
+
| `doctracker://guide` | resource | The same guide, as a Markdown resource. |
|
|
141
|
+
|
|
142
|
+
The server's instructions tell the agent to read the guide before writing or
|
|
143
|
+
changing docstrings.
|
|
144
|
+
|
|
145
|
+
## The wiki
|
|
146
|
+
|
|
147
|
+
- **Tree** — packages (📦/📁), modules (📄), classes (**C**), functions (**f**) and
|
|
148
|
+
methods (**m**). Branches collapse; the tree can be resized or hidden (☰).
|
|
149
|
+
- **Module pages** — description, public API (`__all__`) and members grouped by kind.
|
|
150
|
+
- **Entity pages** — description, signature, parameters table, returns, raises,
|
|
151
|
+
examples, notes, members (for classes) and the source code with syntax
|
|
152
|
+
highlighting. Every section can be collapsed from its badge.
|
|
153
|
+
- **Code theme** — choose among the Pygments themes in the Source section; the
|
|
154
|
+
choice is saved in `config.json`.
|
|
155
|
+
- **Search** — press `/` anywhere, type, use ↑/↓ and Enter.
|
|
156
|
+
|
|
157
|
+
## Configuration
|
|
158
|
+
|
|
159
|
+
`doc/config/config.json` (created by `doctracker init`):
|
|
160
|
+
|
|
161
|
+
| Key | Default | Description |
|
|
162
|
+
| --- | --- | --- |
|
|
163
|
+
| `packages` | detected | Top-level packages to document. |
|
|
164
|
+
| `search_paths` | `["src", "."]` | Folders where the packages are found, relative to the project root. |
|
|
165
|
+
| `host` | `"127.0.0.1"` | Address the server listens on. |
|
|
166
|
+
| `port` | `8765` | Port of the server (also `doctracker start --port`). |
|
|
167
|
+
| `docstring_style` | `"google"` | `google`, `numpy` or `sphinx`. |
|
|
168
|
+
| `show_private` | `true` | Show `_private` members. |
|
|
169
|
+
| `code_theme` | `"default"` | Pygments theme of the source code. |
|
|
170
|
+
| `ssl_certfile` / `ssl_keyfile` | `null` | Certificate and key files; when both are set, the server uses HTTPS. |
|
|
171
|
+
| `watch_interval` | `1.0` | Seconds between checks for changed files. |
|
|
172
|
+
|
|
173
|
+
### The `doc/` folder
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
doc/
|
|
177
|
+
├── .gitignore # keeps local data out of git
|
|
178
|
+
└── config/
|
|
179
|
+
└── config.json # commit this file
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Other folders (local data, models) are created only when a feature needs them, and
|
|
183
|
+
are ignored by `doc/.gitignore`.
|
|
184
|
+
|
|
185
|
+
## Documenting your code
|
|
186
|
+
|
|
187
|
+
doctracker shows what the code says, so the wiki is as good as the docstrings. In
|
|
188
|
+
short:
|
|
189
|
+
|
|
190
|
+
- a docstring for every module, public class, function and method;
|
|
191
|
+
- the first line is a one-sentence summary (it is used in lists and search);
|
|
192
|
+
- type hints on every parameter and return value;
|
|
193
|
+
- `Args`, `Returns`, `Raises`, `Attributes` and `Examples` sections as needed;
|
|
194
|
+
- constants documented with a string on the line after the assignment.
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
def get_weather(city: str, units: str = "metric") -> Forecast:
|
|
198
|
+
"""Fetch the forecast for a city.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
city: City name, e.g. `Lisbon`.
|
|
202
|
+
units: `metric` or `imperial`.
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
Forecast data for the city.
|
|
206
|
+
|
|
207
|
+
Raises:
|
|
208
|
+
CityNotFound: When the city is unknown.
|
|
209
|
+
"""
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Agents get the complete guide from the `documentation_guide` tool.
|
|
213
|
+
|
|
214
|
+
## Security
|
|
215
|
+
|
|
216
|
+
- By default the server listens only on `127.0.0.1`, and the MCP endpoint
|
|
217
|
+
validates the `Host` and `Origin` headers (protection against DNS rebinding).
|
|
218
|
+
- The wiki only accepts changes (such as the code theme) from its own pages.
|
|
219
|
+
- Exposing the server on a network is not supported yet: there is no
|
|
220
|
+
authentication in this version.
|
|
221
|
+
|
|
222
|
+
## Roadmap
|
|
223
|
+
|
|
224
|
+
- Notes recorded by the agent through the MCP server, turned into atomic commits.
|
|
225
|
+
- Commit history linked to each function and class, with LLM summaries
|
|
226
|
+
(llama.cpp or vLLM).
|
|
227
|
+
- Knowledge graph of the code: callers, callees, dead code.
|
|
228
|
+
- Semantic search.
|
|
229
|
+
- Editing the documentation from the wiki.
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
[MIT](LICENSE). The bundled [htmx](https://htmx.org) is distributed under the
|
|
234
|
+
Zero-Clause BSD license (`src/doctracker/wiki/static/htmx-LICENSE.txt`).
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# DOCUMENTATION TRACKER (DOCTRACKER)
|
|
2
|
+
|
|
3
|
+
**One place for the documentation of a Python project developed with LLM agents.**
|
|
4
|
+
|
|
5
|
+
When agents work on a codebase, documentation ends up scattered: notes in many
|
|
6
|
+
Markdown files, memories, code comments and commit messages, all drifting out of
|
|
7
|
+
sync. Documentation Tracker (doctracker) centralizes it. It runs an [MCP](https://modelcontextprotocol.io)
|
|
8
|
+
server that any agent (Claude Code, OpenCode, …) can connect to, and serves a live
|
|
9
|
+
wiki of the project in your browser.
|
|
10
|
+
|
|
11
|
+
> **Status: alpha (0.1).** This first version builds the technical reference of the
|
|
12
|
+
> code. Notes, commit history and LLM summaries come in the next versions (see
|
|
13
|
+
> [Roadmap](#roadmap)).
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Technical reference built from the code** — modules, classes, functions,
|
|
18
|
+
methods and attributes, with signatures, type hints, decorators and parsed
|
|
19
|
+
docstrings (Google, NumPy or Sphinx style).
|
|
20
|
+
- **Static analysis only** — the code is read with [griffe](https://mkdocstrings.github.io/griffe/),
|
|
21
|
+
never imported or executed.
|
|
22
|
+
- **Live wiki** — edit a file and the open page updates by itself.
|
|
23
|
+
- **MCP server** — agents can list and read the documentation, and get a guide on
|
|
24
|
+
how to document the code so the wiki stays complete.
|
|
25
|
+
- **Search** — by name, path and description, with keyboard navigation.
|
|
26
|
+
- **Everything in one folder** — doctracker keeps its files in `doc/` inside your
|
|
27
|
+
project and never touches anything else.
|
|
28
|
+
- **Cross-platform** — Windows and Linux, Python 3.11+.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Install it as a development dependency of the project you want to document:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv add --dev doctracker
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
or with pip:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install doctracker
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick start
|
|
45
|
+
|
|
46
|
+
From the root of your project:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
doctracker init # creates doc/config/config.json (packages are detected automatically)
|
|
50
|
+
doctracker start # starts the server
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
With uv, prefix the commands with `uv run` (e.g. `uv run doctracker start`).
|
|
54
|
+
`start` runs `init` on its own if the project has no configuration yet.
|
|
55
|
+
|
|
56
|
+
The server prints its two addresses:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
Wiki: http://127.0.0.1:8765/
|
|
60
|
+
MCP: http://127.0.0.1:8765/mcp
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Open the wiki in your browser. Keep the server running while you work on the code;
|
|
64
|
+
stop it with `Ctrl+C`.
|
|
65
|
+
|
|
66
|
+
## Connecting an agent
|
|
67
|
+
|
|
68
|
+
The MCP server uses the Streamable HTTP transport at `http://127.0.0.1:8765/mcp`.
|
|
69
|
+
The server must be running before the agent connects.
|
|
70
|
+
|
|
71
|
+
**Claude Code** — add a `.mcp.json` file at the root of your project:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"doctracker": { "type": "http", "url": "http://127.0.0.1:8765/mcp" }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
or register it from the terminal:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
claude mcp add --transport http doctracker http://127.0.0.1:8765/mcp
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**OpenCode** — in `opencode.json`:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"mcp": {
|
|
92
|
+
"doctracker": { "type": "remote", "url": "http://127.0.0.1:8765/mcp" }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Other agents** — any MCP client that supports Streamable HTTP can connect to the
|
|
98
|
+
same URL.
|
|
99
|
+
|
|
100
|
+
### What the agent gets
|
|
101
|
+
|
|
102
|
+
| Name | Kind | What it does |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `list_entities` | tool | Lists documented entities, filtered by path prefix and kind. |
|
|
105
|
+
| `get_entity` | tool | Full technical reference of one entity. |
|
|
106
|
+
| `status` | tool | Whether the documentation is built, and loading errors. |
|
|
107
|
+
| `documentation_guide` | tool | How to document this project's code (adapted to its settings). |
|
|
108
|
+
| `doctracker://guide` | resource | The same guide, as a Markdown resource. |
|
|
109
|
+
|
|
110
|
+
The server's instructions tell the agent to read the guide before writing or
|
|
111
|
+
changing docstrings.
|
|
112
|
+
|
|
113
|
+
## The wiki
|
|
114
|
+
|
|
115
|
+
- **Tree** — packages (📦/📁), modules (📄), classes (**C**), functions (**f**) and
|
|
116
|
+
methods (**m**). Branches collapse; the tree can be resized or hidden (☰).
|
|
117
|
+
- **Module pages** — description, public API (`__all__`) and members grouped by kind.
|
|
118
|
+
- **Entity pages** — description, signature, parameters table, returns, raises,
|
|
119
|
+
examples, notes, members (for classes) and the source code with syntax
|
|
120
|
+
highlighting. Every section can be collapsed from its badge.
|
|
121
|
+
- **Code theme** — choose among the Pygments themes in the Source section; the
|
|
122
|
+
choice is saved in `config.json`.
|
|
123
|
+
- **Search** — press `/` anywhere, type, use ↑/↓ and Enter.
|
|
124
|
+
|
|
125
|
+
## Configuration
|
|
126
|
+
|
|
127
|
+
`doc/config/config.json` (created by `doctracker init`):
|
|
128
|
+
|
|
129
|
+
| Key | Default | Description |
|
|
130
|
+
| --- | --- | --- |
|
|
131
|
+
| `packages` | detected | Top-level packages to document. |
|
|
132
|
+
| `search_paths` | `["src", "."]` | Folders where the packages are found, relative to the project root. |
|
|
133
|
+
| `host` | `"127.0.0.1"` | Address the server listens on. |
|
|
134
|
+
| `port` | `8765` | Port of the server (also `doctracker start --port`). |
|
|
135
|
+
| `docstring_style` | `"google"` | `google`, `numpy` or `sphinx`. |
|
|
136
|
+
| `show_private` | `true` | Show `_private` members. |
|
|
137
|
+
| `code_theme` | `"default"` | Pygments theme of the source code. |
|
|
138
|
+
| `ssl_certfile` / `ssl_keyfile` | `null` | Certificate and key files; when both are set, the server uses HTTPS. |
|
|
139
|
+
| `watch_interval` | `1.0` | Seconds between checks for changed files. |
|
|
140
|
+
|
|
141
|
+
### The `doc/` folder
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
doc/
|
|
145
|
+
├── .gitignore # keeps local data out of git
|
|
146
|
+
└── config/
|
|
147
|
+
└── config.json # commit this file
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Other folders (local data, models) are created only when a feature needs them, and
|
|
151
|
+
are ignored by `doc/.gitignore`.
|
|
152
|
+
|
|
153
|
+
## Documenting your code
|
|
154
|
+
|
|
155
|
+
doctracker shows what the code says, so the wiki is as good as the docstrings. In
|
|
156
|
+
short:
|
|
157
|
+
|
|
158
|
+
- a docstring for every module, public class, function and method;
|
|
159
|
+
- the first line is a one-sentence summary (it is used in lists and search);
|
|
160
|
+
- type hints on every parameter and return value;
|
|
161
|
+
- `Args`, `Returns`, `Raises`, `Attributes` and `Examples` sections as needed;
|
|
162
|
+
- constants documented with a string on the line after the assignment.
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
def get_weather(city: str, units: str = "metric") -> Forecast:
|
|
166
|
+
"""Fetch the forecast for a city.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
city: City name, e.g. `Lisbon`.
|
|
170
|
+
units: `metric` or `imperial`.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Forecast data for the city.
|
|
174
|
+
|
|
175
|
+
Raises:
|
|
176
|
+
CityNotFound: When the city is unknown.
|
|
177
|
+
"""
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Agents get the complete guide from the `documentation_guide` tool.
|
|
181
|
+
|
|
182
|
+
## Security
|
|
183
|
+
|
|
184
|
+
- By default the server listens only on `127.0.0.1`, and the MCP endpoint
|
|
185
|
+
validates the `Host` and `Origin` headers (protection against DNS rebinding).
|
|
186
|
+
- The wiki only accepts changes (such as the code theme) from its own pages.
|
|
187
|
+
- Exposing the server on a network is not supported yet: there is no
|
|
188
|
+
authentication in this version.
|
|
189
|
+
|
|
190
|
+
## Roadmap
|
|
191
|
+
|
|
192
|
+
- Notes recorded by the agent through the MCP server, turned into atomic commits.
|
|
193
|
+
- Commit history linked to each function and class, with LLM summaries
|
|
194
|
+
(llama.cpp or vLLM).
|
|
195
|
+
- Knowledge graph of the code: callers, callees, dead code.
|
|
196
|
+
- Semantic search.
|
|
197
|
+
- Editing the documentation from the wiki.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
[MIT](LICENSE). The bundled [htmx](https://htmx.org) is distributed under the
|
|
202
|
+
Zero-Clause BSD license (`src/doctracker/wiki/static/htmx-LICENSE.txt`).
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "doctracker"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server that centralizes the documentation of Python projects developed with LLM agents."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = [
|
|
8
|
+
"LICENSE",
|
|
9
|
+
"src/doctracker/wiki/static/htmx-LICENSE.txt",
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
19
|
+
"Operating System :: Microsoft :: Windows",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
"Topic :: Software Development :: Documentation",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"click>=8.5.0",
|
|
25
|
+
"griffe>=2.4.1",
|
|
26
|
+
"jinja2>=3.1.6",
|
|
27
|
+
"markdown-it-py>=4.2.0",
|
|
28
|
+
"mcp>=2.3.0,<3",
|
|
29
|
+
"pygments>=2.21.0",
|
|
30
|
+
"starlette>=1.10.0",
|
|
31
|
+
"uvicorn>=0.54.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[[project.authors]]
|
|
35
|
+
name = "Carlos Filipe de Castro Lemos"
|
|
36
|
+
email = "carlos.lemos.dev@gmail.com"
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/cfclemos/doctracker"
|
|
40
|
+
Repository = "https://github.com/cfclemos/doctracker"
|
|
41
|
+
Issues = "https://github.com/cfclemos/doctracker/issues"
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
doctracker = "doctracker.cli:main"
|
|
45
|
+
|
|
46
|
+
[build-system]
|
|
47
|
+
requires = ["uv_build>=0.13.1,<0.14.0"]
|
|
48
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "doctracker"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server that centralizes the documentation of Python projects developed with LLM agents."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE", "src/doctracker/wiki/static/htmx-LICENSE.txt"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Carlos Filipe de Castro Lemos", email = "carlos.lemos.dev@gmail.com" }
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
19
|
+
"Operating System :: Microsoft :: Windows",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
"Topic :: Software Development :: Documentation",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"click>=8.5.0",
|
|
25
|
+
"griffe>=2.4.1",
|
|
26
|
+
"jinja2>=3.1.6",
|
|
27
|
+
"markdown-it-py>=4.2.0",
|
|
28
|
+
"mcp>=2.3.0,<3",
|
|
29
|
+
"pygments>=2.21.0",
|
|
30
|
+
"starlette>=1.10.0",
|
|
31
|
+
"uvicorn>=0.54.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/cfclemos/doctracker"
|
|
36
|
+
Repository = "https://github.com/cfclemos/doctracker"
|
|
37
|
+
Issues = "https://github.com/cfclemos/doctracker/issues"
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
doctracker = "doctracker.cli:main"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["uv_build>=0.13.1,<0.14.0"]
|
|
44
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Command line interface: `doctracker init` and `doctracker start`."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from doctracker import __version__
|
|
8
|
+
from doctracker.config import CONFIG_PATH, Config, detect_packages, load_config, write_config
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group()
|
|
12
|
+
@click.version_option(__version__, prog_name="doctracker")
|
|
13
|
+
def main() -> None:
|
|
14
|
+
"""Centralized documentation for Python projects developed with LLM agents."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@main.command()
|
|
18
|
+
@click.option("--force", is_flag=True, help="Overwrite an existing configuration.")
|
|
19
|
+
def init(force: bool) -> None:
|
|
20
|
+
"""Create doc/config/config.json in the current project."""
|
|
21
|
+
project_root = Path.cwd()
|
|
22
|
+
if (project_root / CONFIG_PATH).exists() and not force:
|
|
23
|
+
raise click.ClickException(f"{CONFIG_PATH.as_posix()} already exists (use --force to overwrite).")
|
|
24
|
+
_initialize(project_root)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@main.command()
|
|
28
|
+
@click.option("--host", help="Override the host from the configuration.")
|
|
29
|
+
@click.option("--port", type=int, help="Override the port from the configuration.")
|
|
30
|
+
def start(host: str | None, port: int | None) -> None:
|
|
31
|
+
"""Start the server (MCP endpoint, wiki and watcher) for the current project."""
|
|
32
|
+
from doctracker.server.app import run
|
|
33
|
+
|
|
34
|
+
project_root = Path.cwd()
|
|
35
|
+
if not (project_root / CONFIG_PATH).exists():
|
|
36
|
+
_initialize(project_root)
|
|
37
|
+
config = load_config(project_root)
|
|
38
|
+
if host:
|
|
39
|
+
config.host = host
|
|
40
|
+
if port:
|
|
41
|
+
config.port = port
|
|
42
|
+
if not config.packages:
|
|
43
|
+
raise click.ClickException(f"No packages to document. Add them to {CONFIG_PATH.as_posix()}.")
|
|
44
|
+
scheme = "https" if config.ssl_certfile else "http"
|
|
45
|
+
click.echo(f"Wiki: {scheme}://{config.host}:{config.port}/")
|
|
46
|
+
click.echo(f"MCP: {scheme}://{config.host}:{config.port}/mcp")
|
|
47
|
+
run(project_root, config)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _initialize(project_root: Path) -> None:
|
|
51
|
+
config = Config()
|
|
52
|
+
config.packages = detect_packages(project_root, config.search_paths)
|
|
53
|
+
write_config(project_root, config)
|
|
54
|
+
found = ", ".join(config.packages) or "none (edit the file to add them)"
|
|
55
|
+
click.echo(f"Created {CONFIG_PATH.as_posix()}. Packages: {found}")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Load and write the doctracker configuration (`doc/config/config.json`)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import asdict, dataclass, field
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
DOC_DIR = "doc"
|
|
8
|
+
CONFIG_PATH = Path(DOC_DIR) / "config" / "config.json"
|
|
9
|
+
GITIGNORE_PATH = Path(DOC_DIR) / ".gitignore"
|
|
10
|
+
GITIGNORE_CONTENT = "sqlite/\nmodels/\n"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Config:
|
|
15
|
+
"""Settings read from `doc/config/config.json`."""
|
|
16
|
+
|
|
17
|
+
packages: list[str] = field(default_factory=list)
|
|
18
|
+
search_paths: list[str] = field(default_factory=lambda: ["src", "."])
|
|
19
|
+
host: str = "127.0.0.1"
|
|
20
|
+
port: int = 8765
|
|
21
|
+
docstring_style: str = "google"
|
|
22
|
+
show_private: bool = True
|
|
23
|
+
code_theme: str = "default"
|
|
24
|
+
ssl_certfile: str | None = None
|
|
25
|
+
ssl_keyfile: str | None = None
|
|
26
|
+
watch_interval: float = 1.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def load_config(project_root: Path) -> Config:
|
|
30
|
+
"""Read the config file of a project, filling missing keys with defaults."""
|
|
31
|
+
path = project_root / CONFIG_PATH
|
|
32
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
33
|
+
known = Config.__dataclass_fields__
|
|
34
|
+
return Config(**{key: value for key, value in data.items() if key in known})
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def write_config(project_root: Path, config: Config) -> None:
|
|
38
|
+
"""Write the config file and the `doc/.gitignore`."""
|
|
39
|
+
path = project_root / CONFIG_PATH
|
|
40
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
path.write_text(json.dumps(asdict(config), indent=2) + "\n", encoding="utf-8")
|
|
42
|
+
(project_root / GITIGNORE_PATH).write_text(GITIGNORE_CONTENT, encoding="utf-8")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def update_config_value(project_root: Path, key: str, value) -> None:
|
|
46
|
+
"""Change one key in the config file, keeping everything else as it is on disk."""
|
|
47
|
+
path = project_root / CONFIG_PATH
|
|
48
|
+
data = json.loads(path.read_text(encoding="utf-8"))
|
|
49
|
+
data[key] = value
|
|
50
|
+
path.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def detect_packages(project_root: Path, search_paths: list[str]) -> list[str]:
|
|
54
|
+
"""Find top-level Python packages (folders with `__init__.py`) in the search paths."""
|
|
55
|
+
packages = []
|
|
56
|
+
for search_path in search_paths:
|
|
57
|
+
base = project_root / search_path
|
|
58
|
+
if not base.is_dir():
|
|
59
|
+
continue
|
|
60
|
+
for child in sorted(base.iterdir()):
|
|
61
|
+
if child.name.startswith(".") or child.name == DOC_DIR:
|
|
62
|
+
continue
|
|
63
|
+
if (child / "__init__.py").is_file() and child.name not in packages:
|
|
64
|
+
packages.append(child.name)
|
|
65
|
+
return packages
|