skeleton-replay 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.
- skeleton_replay-0.1.0/LICENSE +21 -0
- skeleton_replay-0.1.0/PKG-INFO +346 -0
- skeleton_replay-0.1.0/README.md +298 -0
- skeleton_replay-0.1.0/pyproject.toml +82 -0
- skeleton_replay-0.1.0/skeleton_replay/__init__.py +7 -0
- skeleton_replay-0.1.0/skeleton_replay/__main__.py +6 -0
- skeleton_replay-0.1.0/skeleton_replay/analysis/__init__.py +14 -0
- skeleton_replay-0.1.0/skeleton_replay/analysis/snapshot.py +249 -0
- skeleton_replay-0.1.0/skeleton_replay/analysis/static.py +141 -0
- skeleton_replay-0.1.0/skeleton_replay/cli.py +238 -0
- skeleton_replay-0.1.0/skeleton_replay/interface/__init__.py +7 -0
- skeleton_replay-0.1.0/skeleton_replay/interface/console.py +109 -0
- skeleton_replay-0.1.0/skeleton_replay/interface/output_paths.py +38 -0
- skeleton_replay-0.1.0/skeleton_replay/interface/report_opener.py +16 -0
- skeleton_replay-0.1.0/skeleton_replay/reporting/__init__.py +6 -0
- skeleton_replay-0.1.0/skeleton_replay/reporting/html.py +43 -0
- skeleton_replay-0.1.0/skeleton_replay/reporting/templates/__init__.py +1 -0
- skeleton_replay-0.1.0/skeleton_replay/reporting/templates/report.html +1621 -0
- skeleton_replay-0.1.0/skeleton_replay/reporting/workflow.py +101 -0
- skeleton_replay-0.1.0/skeleton_replay/runtime/__init__.py +15 -0
- skeleton_replay-0.1.0/skeleton_replay/runtime/events.py +76 -0
- skeleton_replay-0.1.0/skeleton_replay/runtime/filters.py +58 -0
- skeleton_replay-0.1.0/skeleton_replay/runtime/tracer.py +235 -0
- skeleton_replay-0.1.0/skeleton_replay/safety/__init__.py +5 -0
- skeleton_replay-0.1.0/skeleton_replay/safety/summariser.py +86 -0
- skeleton_replay-0.1.0/skeleton_replay/session.py +129 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ml-affairs
|
|
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,346 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: skeleton-replay
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Replay and visualise the living architecture of a Python application.
|
|
5
|
+
Keywords: architecture,tracing,visualization,runtime,developer-tools
|
|
6
|
+
Author: Christos Hadjinikolis
|
|
7
|
+
Author-email: Christos Hadjinikolis <christos.hadjinikolis.subs@gmail.com>
|
|
8
|
+
License: MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 ml-affairs
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
Classifier: Development Status :: 3 - Alpha
|
|
30
|
+
Classifier: Environment :: Console
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
38
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
39
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
40
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
41
|
+
Maintainer: Christos Hadjinikolis
|
|
42
|
+
Maintainer-email: Christos Hadjinikolis <christos.hadjinikolis.subs@gmail.com>
|
|
43
|
+
Requires-Python: >=3.11
|
|
44
|
+
Project-URL: Homepage, https://github.com/ml-affairs/skeleton
|
|
45
|
+
Project-URL: Repository, https://github.com/ml-affairs/skeleton
|
|
46
|
+
Project-URL: Issues, https://github.com/ml-affairs/skeleton/issues
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# skeleton
|
|
50
|
+
|
|
51
|
+
[](https://github.com/ml-affairs/skeleton/actions/workflows/ci.yml)
|
|
52
|
+

|
|
53
|
+

|
|
54
|
+

|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
Skeleton is a developer-understanding tool, not a profiler. It runs a Python
|
|
59
|
+
script under a lightweight runtime tracer and turns the observed execution into
|
|
60
|
+
an interactive, replayable architecture map.
|
|
61
|
+
|
|
62
|
+
Core promise:
|
|
63
|
+
|
|
64
|
+
> Replay and visualise the living architecture of a Python application.
|
|
65
|
+
|
|
66
|
+
Skeleton produces runtime evidence in four complementary forms:
|
|
67
|
+
|
|
68
|
+
| Surface | Purpose |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
|  `trace.jsonl` | Ordered public call and return events. |
|
|
71
|
+
|  `snapshot.json` | Graph-shaped modules, classes, functions, instances, and edges. |
|
|
72
|
+
|  `workflow.md` | LLM-readable workflow evidence with stable event and node references. |
|
|
73
|
+
|  `report.html` | Interactive visual replay for humans. |
|
|
74
|
+
|
|
75
|
+
Package naming:
|
|
76
|
+
|
|
77
|
+
```text
|
|
78
|
+
Product name: Skeleton
|
|
79
|
+
PyPI package: skeleton-replay
|
|
80
|
+
Import name: skeleton_replay
|
|
81
|
+
CLI command: skeleton
|
|
82
|
+
Module entry: python -m skeleton_replay
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## MVP workflow
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install skeleton-replay
|
|
89
|
+
skeleton run path/to/script.py
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Skeleton writes:
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
~/.skeleton/<application-name>/
|
|
96
|
+
trace.jsonl
|
|
97
|
+
snapshot.json
|
|
98
|
+
workflow.md
|
|
99
|
+
report.html
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The first version is intentionally non-invasive. You do not add decorators or
|
|
103
|
+
modify application code. The runner wraps an existing script, traces only
|
|
104
|
+
project-local public functions and methods by default, and records safe
|
|
105
|
+
summaries of arguments and return values.
|
|
106
|
+
|
|
107
|
+
Skeleton is opinionated about what makes large Python systems understandable.
|
|
108
|
+
It promotes explicit architectural actors, clear dependency direction, and I/O
|
|
109
|
+
decoupled from business logic. Modules are visual shells, runtime object
|
|
110
|
+
instances live inside the modules that define their classes, module-level public
|
|
111
|
+
functions live inside their modules, and instance methods live inside the object
|
|
112
|
+
that handled the call. Class definitions remain metadata, not runtime graph
|
|
113
|
+
boxes. Entrypoints, services, repositories, adapters, and ports are roles or
|
|
114
|
+
boundaries unless the codebase has a concrete object that owns that
|
|
115
|
+
responsibility. See
|
|
116
|
+
[`docs/design/software-design-principles.md`](docs/design/software-design-principles.md)
|
|
117
|
+
for the design principles that guide the visual model.
|
|
118
|
+
|
|
119
|
+
`workflow.md` is a compact text explanation of the observed run. It is designed
|
|
120
|
+
for humans and LLMs: event ids, node ids, caller/callee relationships, safe
|
|
121
|
+
examples, and known trace gaps are written in a form that can be quoted and
|
|
122
|
+
reasoned over without scraping the HTML report.
|
|
123
|
+
|
|
124
|
+
## Install and develop
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
make setup
|
|
128
|
+
make check
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Use `make test` for normal or targeted local pytest runs. Use `make test-cov`
|
|
132
|
+
or `make check` when you want the full-suite coverage gate that CI enforces.
|
|
133
|
+
|
|
134
|
+
Print the local artifact locations:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
make where
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Run locally from the checkout:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
uv run python -m skeleton_replay run examples/app.py
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Generate a stable local demo report:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
make demo
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The demo writes artifacts to `tests/dev/.temp/skeleton-demo/` and opens
|
|
153
|
+
`report.html` in your default browser. For a headless run that writes the same
|
|
154
|
+
files without opening a browser, use:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
make demo-no-open
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Pytest tests use `tmp_path`, so test-generated reports live in pytest-managed
|
|
161
|
+
temporary directories under `tests/dev/.temp/pytest/`. The stable report to open
|
|
162
|
+
while developing the UI is:
|
|
163
|
+
|
|
164
|
+
```text
|
|
165
|
+
tests/dev/.temp/skeleton-demo/report.html
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Regenerate it with:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
make demo-no-open
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## CLI
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
skeleton run [options] path/to/script.py [args...]
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The module entrypoint is also available:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
python -m skeleton_replay run [options] path/to/script.py [args...]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Options:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
--project-root PATH Root used to decide which files are project-local.
|
|
190
|
+
--out-dir PATH Output directory. Defaults to ~/.skeleton/<application-name>.
|
|
191
|
+
--include PATTERN Only trace matching relative paths or module names.
|
|
192
|
+
--exclude PATTERN Exclude matching relative paths or module names.
|
|
193
|
+
--max-events N Stop writing trace events after N events.
|
|
194
|
+
--no-html Skip report.html generation and opening.
|
|
195
|
+
--no-open Do not open report.html after generation.
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Output location precedence:
|
|
199
|
+
|
|
200
|
+
1. `--out-dir PATH`
|
|
201
|
+
2. `SKELETON_OUT_DIR`
|
|
202
|
+
3. `SKELETON_HOME/<application-name>`
|
|
203
|
+
4. `~/.skeleton/<application-name>`
|
|
204
|
+
|
|
205
|
+
When HTML generation is enabled, Skeleton opens `report.html` in your default
|
|
206
|
+
browser at the end of the run. Use `--no-open` for CI, scripts, or headless
|
|
207
|
+
environments.
|
|
208
|
+
|
|
209
|
+
## Python API
|
|
210
|
+
|
|
211
|
+
Use `TraceSession` when you want to generate Skeleton artifacts from Python
|
|
212
|
+
without shelling out to the CLI:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
from pathlib import Path
|
|
216
|
+
|
|
217
|
+
from skeleton_replay import TraceSession
|
|
218
|
+
|
|
219
|
+
result = TraceSession(
|
|
220
|
+
project_root=Path("path/to/project"),
|
|
221
|
+
out_dir=Path("path/to/project/.skeleton"),
|
|
222
|
+
).run_script("path/to/project/app.py")
|
|
223
|
+
|
|
224
|
+
print(result.report_path)
|
|
225
|
+
print(result.workflow_path)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The Python API writes the same `trace.jsonl`, `snapshot.json`, `workflow.md`,
|
|
229
|
+
and optional `report.html` artifacts as the CLI. Unlike the CLI, it does not
|
|
230
|
+
open the HTML report by default; pass `open_report=True` when that is wanted.
|
|
231
|
+
See [`docs/api/python-api.md`](docs/api/python-api.md).
|
|
232
|
+
|
|
233
|
+
## What gets traced
|
|
234
|
+
|
|
235
|
+
Skeleton uses `sys.setprofile` and records Python `call` and `return` events
|
|
236
|
+
when all of these are true:
|
|
237
|
+
|
|
238
|
+
- The frame's file is under the project root.
|
|
239
|
+
- The file is not in ignored local infrastructure such as `.venv`, `.git`, or
|
|
240
|
+
`.skeleton`.
|
|
241
|
+
- The callable name is public. Names beginning with `_` are ignored.
|
|
242
|
+
|
|
243
|
+
The trace identifies the module, class where practical, function or method,
|
|
244
|
+
caller, callee, instance identity where practical, call depth, event order,
|
|
245
|
+
timestamp, safe argument summaries, and safe return summaries.
|
|
246
|
+
|
|
247
|
+
## How it works
|
|
248
|
+
|
|
249
|
+
Skeleton does not patch your source code. It uses Python's own runtime
|
|
250
|
+
introspection:
|
|
251
|
+
|
|
252
|
+
- `runpy.run_path()` runs the target script as `__main__` inside a controlled
|
|
253
|
+
runner.
|
|
254
|
+
- `sys.setprofile()` receives callbacks whenever Python enters or returns from a
|
|
255
|
+
function.
|
|
256
|
+
- Each callback receives a frame object. From that frame Skeleton reads
|
|
257
|
+
`frame.f_code`, `frame.f_globals`, and `frame.f_locals` to identify the file,
|
|
258
|
+
module, function name, line number, arguments, and whether the call has
|
|
259
|
+
`self`.
|
|
260
|
+
- When `self` is present, Skeleton records `type(self).__name__` and
|
|
261
|
+
`id(self)`, giving a run-local object identity such as
|
|
262
|
+
`service.Greeter@0x...`.
|
|
263
|
+
- Values are summarized immediately, then the raw objects are discarded.
|
|
264
|
+
|
|
265
|
+
That is why the report can show instance-owned methods without decorators. It is
|
|
266
|
+
not reading class source to guess behavior; it is watching Python call real
|
|
267
|
+
functions on real objects. The object ids are only meaningful within one run,
|
|
268
|
+
not across processes or commits.
|
|
269
|
+
|
|
270
|
+
For more detail, see
|
|
271
|
+
[`docs/design/runtime-introspection.md`](docs/design/runtime-introspection.md).
|
|
272
|
+
|
|
273
|
+
## Current scope and next integrations
|
|
274
|
+
|
|
275
|
+
Skeleton currently runs a script path:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
python -m skeleton_replay run scripts/replay_checkout.py
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
That script can drive any kind of Python code: CLI workflows, service objects,
|
|
282
|
+
batch jobs, web-app internals, or library calls. The application being traced
|
|
283
|
+
does not need to be a CLI application, but v0 does need a script entrypoint that
|
|
284
|
+
exercises the behavior.
|
|
285
|
+
|
|
286
|
+
Planned integrations:
|
|
287
|
+
|
|
288
|
+
- `run-module`: support module execution such as
|
|
289
|
+
`python -m my_app.cli run-demo`, exposed as something like
|
|
290
|
+
`skeleton run-module my_app.cli -- run-demo`.
|
|
291
|
+
- pytest plugin: trace selected tests or test sessions, because tests often
|
|
292
|
+
encode real business workflows.
|
|
293
|
+
- live web request tracing: trace one request or handler inside a running
|
|
294
|
+
FastAPI, Flask, Django, or Starlette app through middleware or a capture
|
|
295
|
+
context.
|
|
296
|
+
- PyCharm plugin: a thin IDE frontend that invokes Skeleton with the configured
|
|
297
|
+
interpreter and opens the generated report.
|
|
298
|
+
|
|
299
|
+
See [`docs/api/python-api.md`](docs/api/python-api.md),
|
|
300
|
+
[`docs/development/missing-integration-plans.md`](docs/development/missing-integration-plans.md),
|
|
301
|
+
and [`docs/development/pypi-release-plan.md`](docs/development/pypi-release-plan.md).
|
|
302
|
+
|
|
303
|
+
Release history is tracked in [`CHANGELOG.md`](CHANGELOG.md). Keep the
|
|
304
|
+
changelog updated in the same pull request or commit that changes user-visible
|
|
305
|
+
behavior.
|
|
306
|
+
|
|
307
|
+
## Event schema
|
|
308
|
+
|
|
309
|
+
Each line in `.skeleton/trace.jsonl` is a JSON object:
|
|
310
|
+
|
|
311
|
+
```json
|
|
312
|
+
{
|
|
313
|
+
"schema_version": 1,
|
|
314
|
+
"event_type": "call",
|
|
315
|
+
"order": 0,
|
|
316
|
+
"timestamp": 1782740000.0,
|
|
317
|
+
"depth": 0,
|
|
318
|
+
"caller": null,
|
|
319
|
+
"callee": {
|
|
320
|
+
"module": "app",
|
|
321
|
+
"class_name": null,
|
|
322
|
+
"function": "main",
|
|
323
|
+
"qualified_name": "app.main",
|
|
324
|
+
"file": "/project/app.py",
|
|
325
|
+
"line": 10,
|
|
326
|
+
"node_id": "function:app.main",
|
|
327
|
+
"instance_id": null
|
|
328
|
+
},
|
|
329
|
+
"args": {}
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Return events use the same endpoint shape and include `return_value`.
|
|
334
|
+
|
|
335
|
+
## Safety model
|
|
336
|
+
|
|
337
|
+
Skeleton records summaries, not full object contents.
|
|
338
|
+
|
|
339
|
+
- Strings are truncated.
|
|
340
|
+
- Containers include type, length, and a small preview.
|
|
341
|
+
- Objects include only class name and object id.
|
|
342
|
+
- Argument or mapping names containing `password`, `token`, `secret`, `key`,
|
|
343
|
+
`auth`, or `credential` are redacted.
|
|
344
|
+
|
|
345
|
+
This is not a debugger replacement and not a performance profiler. It is a
|
|
346
|
+
runtime architecture replay tool for understanding how a codebase behaves.
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# skeleton
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ml-affairs/skeleton/actions/workflows/ci.yml)
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
Skeleton is a developer-understanding tool, not a profiler. It runs a Python
|
|
11
|
+
script under a lightweight runtime tracer and turns the observed execution into
|
|
12
|
+
an interactive, replayable architecture map.
|
|
13
|
+
|
|
14
|
+
Core promise:
|
|
15
|
+
|
|
16
|
+
> Replay and visualise the living architecture of a Python application.
|
|
17
|
+
|
|
18
|
+
Skeleton produces runtime evidence in four complementary forms:
|
|
19
|
+
|
|
20
|
+
| Surface | Purpose |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
|  `trace.jsonl` | Ordered public call and return events. |
|
|
23
|
+
|  `snapshot.json` | Graph-shaped modules, classes, functions, instances, and edges. |
|
|
24
|
+
|  `workflow.md` | LLM-readable workflow evidence with stable event and node references. |
|
|
25
|
+
|  `report.html` | Interactive visual replay for humans. |
|
|
26
|
+
|
|
27
|
+
Package naming:
|
|
28
|
+
|
|
29
|
+
```text
|
|
30
|
+
Product name: Skeleton
|
|
31
|
+
PyPI package: skeleton-replay
|
|
32
|
+
Import name: skeleton_replay
|
|
33
|
+
CLI command: skeleton
|
|
34
|
+
Module entry: python -m skeleton_replay
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## MVP workflow
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install skeleton-replay
|
|
41
|
+
skeleton run path/to/script.py
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Skeleton writes:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
~/.skeleton/<application-name>/
|
|
48
|
+
trace.jsonl
|
|
49
|
+
snapshot.json
|
|
50
|
+
workflow.md
|
|
51
|
+
report.html
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The first version is intentionally non-invasive. You do not add decorators or
|
|
55
|
+
modify application code. The runner wraps an existing script, traces only
|
|
56
|
+
project-local public functions and methods by default, and records safe
|
|
57
|
+
summaries of arguments and return values.
|
|
58
|
+
|
|
59
|
+
Skeleton is opinionated about what makes large Python systems understandable.
|
|
60
|
+
It promotes explicit architectural actors, clear dependency direction, and I/O
|
|
61
|
+
decoupled from business logic. Modules are visual shells, runtime object
|
|
62
|
+
instances live inside the modules that define their classes, module-level public
|
|
63
|
+
functions live inside their modules, and instance methods live inside the object
|
|
64
|
+
that handled the call. Class definitions remain metadata, not runtime graph
|
|
65
|
+
boxes. Entrypoints, services, repositories, adapters, and ports are roles or
|
|
66
|
+
boundaries unless the codebase has a concrete object that owns that
|
|
67
|
+
responsibility. See
|
|
68
|
+
[`docs/design/software-design-principles.md`](docs/design/software-design-principles.md)
|
|
69
|
+
for the design principles that guide the visual model.
|
|
70
|
+
|
|
71
|
+
`workflow.md` is a compact text explanation of the observed run. It is designed
|
|
72
|
+
for humans and LLMs: event ids, node ids, caller/callee relationships, safe
|
|
73
|
+
examples, and known trace gaps are written in a form that can be quoted and
|
|
74
|
+
reasoned over without scraping the HTML report.
|
|
75
|
+
|
|
76
|
+
## Install and develop
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
make setup
|
|
80
|
+
make check
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Use `make test` for normal or targeted local pytest runs. Use `make test-cov`
|
|
84
|
+
or `make check` when you want the full-suite coverage gate that CI enforces.
|
|
85
|
+
|
|
86
|
+
Print the local artifact locations:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
make where
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Run locally from the checkout:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv run python -m skeleton_replay run examples/app.py
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Generate a stable local demo report:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
make demo
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The demo writes artifacts to `tests/dev/.temp/skeleton-demo/` and opens
|
|
105
|
+
`report.html` in your default browser. For a headless run that writes the same
|
|
106
|
+
files without opening a browser, use:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
make demo-no-open
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Pytest tests use `tmp_path`, so test-generated reports live in pytest-managed
|
|
113
|
+
temporary directories under `tests/dev/.temp/pytest/`. The stable report to open
|
|
114
|
+
while developing the UI is:
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
tests/dev/.temp/skeleton-demo/report.html
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Regenerate it with:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
make demo-no-open
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## CLI
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
skeleton run [options] path/to/script.py [args...]
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The module entrypoint is also available:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
python -m skeleton_replay run [options] path/to/script.py [args...]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Options:
|
|
139
|
+
|
|
140
|
+
```text
|
|
141
|
+
--project-root PATH Root used to decide which files are project-local.
|
|
142
|
+
--out-dir PATH Output directory. Defaults to ~/.skeleton/<application-name>.
|
|
143
|
+
--include PATTERN Only trace matching relative paths or module names.
|
|
144
|
+
--exclude PATTERN Exclude matching relative paths or module names.
|
|
145
|
+
--max-events N Stop writing trace events after N events.
|
|
146
|
+
--no-html Skip report.html generation and opening.
|
|
147
|
+
--no-open Do not open report.html after generation.
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Output location precedence:
|
|
151
|
+
|
|
152
|
+
1. `--out-dir PATH`
|
|
153
|
+
2. `SKELETON_OUT_DIR`
|
|
154
|
+
3. `SKELETON_HOME/<application-name>`
|
|
155
|
+
4. `~/.skeleton/<application-name>`
|
|
156
|
+
|
|
157
|
+
When HTML generation is enabled, Skeleton opens `report.html` in your default
|
|
158
|
+
browser at the end of the run. Use `--no-open` for CI, scripts, or headless
|
|
159
|
+
environments.
|
|
160
|
+
|
|
161
|
+
## Python API
|
|
162
|
+
|
|
163
|
+
Use `TraceSession` when you want to generate Skeleton artifacts from Python
|
|
164
|
+
without shelling out to the CLI:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from pathlib import Path
|
|
168
|
+
|
|
169
|
+
from skeleton_replay import TraceSession
|
|
170
|
+
|
|
171
|
+
result = TraceSession(
|
|
172
|
+
project_root=Path("path/to/project"),
|
|
173
|
+
out_dir=Path("path/to/project/.skeleton"),
|
|
174
|
+
).run_script("path/to/project/app.py")
|
|
175
|
+
|
|
176
|
+
print(result.report_path)
|
|
177
|
+
print(result.workflow_path)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The Python API writes the same `trace.jsonl`, `snapshot.json`, `workflow.md`,
|
|
181
|
+
and optional `report.html` artifacts as the CLI. Unlike the CLI, it does not
|
|
182
|
+
open the HTML report by default; pass `open_report=True` when that is wanted.
|
|
183
|
+
See [`docs/api/python-api.md`](docs/api/python-api.md).
|
|
184
|
+
|
|
185
|
+
## What gets traced
|
|
186
|
+
|
|
187
|
+
Skeleton uses `sys.setprofile` and records Python `call` and `return` events
|
|
188
|
+
when all of these are true:
|
|
189
|
+
|
|
190
|
+
- The frame's file is under the project root.
|
|
191
|
+
- The file is not in ignored local infrastructure such as `.venv`, `.git`, or
|
|
192
|
+
`.skeleton`.
|
|
193
|
+
- The callable name is public. Names beginning with `_` are ignored.
|
|
194
|
+
|
|
195
|
+
The trace identifies the module, class where practical, function or method,
|
|
196
|
+
caller, callee, instance identity where practical, call depth, event order,
|
|
197
|
+
timestamp, safe argument summaries, and safe return summaries.
|
|
198
|
+
|
|
199
|
+
## How it works
|
|
200
|
+
|
|
201
|
+
Skeleton does not patch your source code. It uses Python's own runtime
|
|
202
|
+
introspection:
|
|
203
|
+
|
|
204
|
+
- `runpy.run_path()` runs the target script as `__main__` inside a controlled
|
|
205
|
+
runner.
|
|
206
|
+
- `sys.setprofile()` receives callbacks whenever Python enters or returns from a
|
|
207
|
+
function.
|
|
208
|
+
- Each callback receives a frame object. From that frame Skeleton reads
|
|
209
|
+
`frame.f_code`, `frame.f_globals`, and `frame.f_locals` to identify the file,
|
|
210
|
+
module, function name, line number, arguments, and whether the call has
|
|
211
|
+
`self`.
|
|
212
|
+
- When `self` is present, Skeleton records `type(self).__name__` and
|
|
213
|
+
`id(self)`, giving a run-local object identity such as
|
|
214
|
+
`service.Greeter@0x...`.
|
|
215
|
+
- Values are summarized immediately, then the raw objects are discarded.
|
|
216
|
+
|
|
217
|
+
That is why the report can show instance-owned methods without decorators. It is
|
|
218
|
+
not reading class source to guess behavior; it is watching Python call real
|
|
219
|
+
functions on real objects. The object ids are only meaningful within one run,
|
|
220
|
+
not across processes or commits.
|
|
221
|
+
|
|
222
|
+
For more detail, see
|
|
223
|
+
[`docs/design/runtime-introspection.md`](docs/design/runtime-introspection.md).
|
|
224
|
+
|
|
225
|
+
## Current scope and next integrations
|
|
226
|
+
|
|
227
|
+
Skeleton currently runs a script path:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
python -m skeleton_replay run scripts/replay_checkout.py
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
That script can drive any kind of Python code: CLI workflows, service objects,
|
|
234
|
+
batch jobs, web-app internals, or library calls. The application being traced
|
|
235
|
+
does not need to be a CLI application, but v0 does need a script entrypoint that
|
|
236
|
+
exercises the behavior.
|
|
237
|
+
|
|
238
|
+
Planned integrations:
|
|
239
|
+
|
|
240
|
+
- `run-module`: support module execution such as
|
|
241
|
+
`python -m my_app.cli run-demo`, exposed as something like
|
|
242
|
+
`skeleton run-module my_app.cli -- run-demo`.
|
|
243
|
+
- pytest plugin: trace selected tests or test sessions, because tests often
|
|
244
|
+
encode real business workflows.
|
|
245
|
+
- live web request tracing: trace one request or handler inside a running
|
|
246
|
+
FastAPI, Flask, Django, or Starlette app through middleware or a capture
|
|
247
|
+
context.
|
|
248
|
+
- PyCharm plugin: a thin IDE frontend that invokes Skeleton with the configured
|
|
249
|
+
interpreter and opens the generated report.
|
|
250
|
+
|
|
251
|
+
See [`docs/api/python-api.md`](docs/api/python-api.md),
|
|
252
|
+
[`docs/development/missing-integration-plans.md`](docs/development/missing-integration-plans.md),
|
|
253
|
+
and [`docs/development/pypi-release-plan.md`](docs/development/pypi-release-plan.md).
|
|
254
|
+
|
|
255
|
+
Release history is tracked in [`CHANGELOG.md`](CHANGELOG.md). Keep the
|
|
256
|
+
changelog updated in the same pull request or commit that changes user-visible
|
|
257
|
+
behavior.
|
|
258
|
+
|
|
259
|
+
## Event schema
|
|
260
|
+
|
|
261
|
+
Each line in `.skeleton/trace.jsonl` is a JSON object:
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"schema_version": 1,
|
|
266
|
+
"event_type": "call",
|
|
267
|
+
"order": 0,
|
|
268
|
+
"timestamp": 1782740000.0,
|
|
269
|
+
"depth": 0,
|
|
270
|
+
"caller": null,
|
|
271
|
+
"callee": {
|
|
272
|
+
"module": "app",
|
|
273
|
+
"class_name": null,
|
|
274
|
+
"function": "main",
|
|
275
|
+
"qualified_name": "app.main",
|
|
276
|
+
"file": "/project/app.py",
|
|
277
|
+
"line": 10,
|
|
278
|
+
"node_id": "function:app.main",
|
|
279
|
+
"instance_id": null
|
|
280
|
+
},
|
|
281
|
+
"args": {}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Return events use the same endpoint shape and include `return_value`.
|
|
286
|
+
|
|
287
|
+
## Safety model
|
|
288
|
+
|
|
289
|
+
Skeleton records summaries, not full object contents.
|
|
290
|
+
|
|
291
|
+
- Strings are truncated.
|
|
292
|
+
- Containers include type, length, and a small preview.
|
|
293
|
+
- Objects include only class name and object id.
|
|
294
|
+
- Argument or mapping names containing `password`, `token`, `secret`, `key`,
|
|
295
|
+
`auth`, or `credential` are redacted.
|
|
296
|
+
|
|
297
|
+
This is not a debugger replacement and not a performance profiler. It is a
|
|
298
|
+
runtime architecture replay tool for understanding how a codebase behaves.
|