Metadata-Version: 2.3
Name: skeleton-replay
Version: 0.4.0
Summary: Replay and visualise the living architecture of a Python application.
Keywords: architecture,tracing,visualization,runtime,developer-tools
Author: Christos Hadjinikolis
Author-email: Christos Hadjinikolis <christos.hadjinikolis.subs@gmail.com>
License: MIT License
         
         Copyright (c) 2026 ml-affairs
         
         Permission is hereby granted, free of charge, to any person obtaining a copy
         of this software and associated documentation files (the "Software"), to deal
         in the Software without restriction, including without limitation the rights
         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         copies of the Software, and to permit persons to whom the Software is
         furnished to do so, subject to the following conditions:
         
         The above copyright notice and this permission notice shall be included in all
         copies or substantial portions of the Software.
         
         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         SOFTWARE.
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Debuggers
Classifier: Topic :: Software Development :: Documentation
Classifier: Topic :: Software Development :: Quality Assurance
Maintainer: Christos Hadjinikolis
Maintainer-email: Christos Hadjinikolis <christos.hadjinikolis.subs@gmail.com>
Requires-Python: >=3.11
Project-URL: Homepage, https://github.com/ml-affairs/skeleton
Project-URL: Repository, https://github.com/ml-affairs/skeleton
Project-URL: Issues, https://github.com/ml-affairs/skeleton/issues
Description-Content-Type: text/markdown

# skeleton

[![CI](https://github.com/ml-affairs/skeleton/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/ml-affairs/skeleton/actions/workflows/ci.yml)
![Coverage](https://img.shields.io/badge/coverage-86%25-brightgreen)
![Python](https://img.shields.io/badge/python-3.11%2B-blue)
![License](https://img.shields.io/badge/license-MIT-green)

![Skeleton: replay and visualise the living architecture of your code.](https://raw.githubusercontent.com/ml-affairs/skeleton/812eefb6e8105844e306df2a282ce5f876c31695/docs/images/readme.png)

Skeleton is a developer-understanding tool, not a profiler. It runs a Python
script under a lightweight runtime tracer and turns the observed execution into
an interactive, replayable architecture map.

Core promise:

> Replay and visualise the living architecture of a Python application.

Skeleton produces runtime evidence in four complementary forms:

| Surface | Purpose |
| --- | --- |
| ![Trace icon](https://raw.githubusercontent.com/ml-affairs/skeleton/812eefb6e8105844e306df2a282ce5f876c31695/docs/images/product/trace.svg) `trace.jsonl` | Ordered public call and return events. |
| ![Snapshot icon](https://raw.githubusercontent.com/ml-affairs/skeleton/812eefb6e8105844e306df2a282ce5f876c31695/docs/images/product/snapshot.svg) `snapshot.json` | Graph-shaped modules, classes, functions, instances, and edges. |
| ![Workflow icon](https://raw.githubusercontent.com/ml-affairs/skeleton/812eefb6e8105844e306df2a282ce5f876c31695/docs/images/product/workflow.svg) `workflow.md` | LLM-readable workflow evidence with stable event and node references. |
| ![Replay icon](https://raw.githubusercontent.com/ml-affairs/skeleton/812eefb6e8105844e306df2a282ce5f876c31695/docs/images/product/replay.svg) `report.html` | Interactive visual replay for humans. |

Package naming:

```text
Product name:  Skeleton
PyPI package:  skeleton-replay
Import name:   skeleton_replay
CLI command:   skeleton
Module entry:  python -m skeleton_replay
```

## MVP workflow

```bash
pip install skeleton-replay
skeleton run path/to/script.py
```

Skeleton writes:

```text
~/.skeleton/<application-name>/
  trace.jsonl
  snapshot.json
  workflow.md
  report.html
```

The first version is intentionally non-invasive. You do not add decorators or
modify application code. The runner wraps an existing script, traces only
project-local public functions and methods by default, and records safe
summaries of arguments and return values.

Skeleton is opinionated about what makes large Python systems understandable.
It promotes explicit architectural actors, clear dependency direction, and I/O
decoupled from business logic. Modules are visual shells, runtime object
instances live inside the modules that define their classes, module-level public
functions live inside their modules, and instance methods live inside the object
that handled the call. Class definitions remain metadata, not runtime graph
boxes. Entrypoints, services, repositories, adapters, and ports are roles or
boundaries unless the codebase has a concrete object that owns that
responsibility. See
[`docs/design/software-design-principles.md`](docs/design/software-design-principles.md)
for the design principles that guide the visual model.

`workflow.md` is a compact text explanation of the observed run. It is designed
for humans and LLMs: event ids, node ids, caller/callee relationships, safe
examples, and known trace gaps are written in a form that can be quoted and
reasoned over without scraping the HTML report.

## Install and develop

```bash
make setup
make check
```

Use `make test` for normal or targeted local pytest runs. Use `make test-cov`
or `make check` when you want the full-suite coverage gate that CI enforces.

Print the local artifact locations:

```bash
make where
```

Run locally from the checkout:

```bash
uv run python -m skeleton_replay run examples/app.py
```

Generate a stable local demo report:

```bash
make demo
```

The demo writes artifacts to `tests/dev/.temp/skeleton-demo/` and opens
`report.html` in your default browser. For a headless run that writes the same
files without opening a browser, use:

```bash
make demo-no-open
```

Pytest tests use `tmp_path`, so test-generated reports live in pytest-managed
temporary directories under `tests/dev/.temp/pytest/`. The stable report to open
while developing the UI is:

```text
tests/dev/.temp/skeleton-demo/report.html
```

Regenerate it with:

```bash
make demo-no-open
```

## CLI

```bash
skeleton run [options] path/to/script.py [args...]
```

The module entrypoint is also available:

```bash
python -m skeleton_replay run [options] path/to/script.py [args...]
```

Options:

```text
--project-root PATH   Root used to decide which files are project-local.
--out-dir PATH        Output directory. Defaults to ~/.skeleton/<application-name>.
--include PATTERN     Only trace matching relative paths or module names.
--exclude PATTERN     Exclude matching relative paths or module names.
--max-events N        Stop writing trace events after N events.
--no-html             Skip report.html generation and opening.
--no-open             Do not open report.html after generation.
```

Output location precedence:

1. `--out-dir PATH`
2. `SKELETON_OUT_DIR`
3. `SKELETON_HOME/<application-name>`
4. `~/.skeleton/<application-name>`

When HTML generation is enabled, Skeleton opens `report.html` in your default
browser at the end of the run. Use `--no-open` for CI, scripts, or headless
environments.

## Python API

Use `TraceSession` when you want to generate Skeleton artifacts from Python
without shelling out to the CLI:

```python
from pathlib import Path

from skeleton_replay import TraceSession

result = TraceSession(
    project_root=Path("path/to/project"),
    out_dir=Path("path/to/project/.skeleton"),
).run_script("path/to/project/app.py")

print(result.report_path)
print(result.workflow_path)
```

The Python API writes the same `trace.jsonl`, `snapshot.json`, `workflow.md`,
and optional `report.html` artifacts as the CLI. Unlike the CLI, it does not
open the HTML report by default; pass `open_report=True` when that is wanted.
See [`docs/api/python-api.md`](docs/api/python-api.md).

## What gets traced

Skeleton uses `sys.setprofile` and records Python `call` and `return` events
when all of these are true:

- The frame's file is under the project root.
- The file is not in ignored local infrastructure such as `.venv`, `.git`, or
  `.skeleton`.
- The callable name is public. Names beginning with `_` are ignored.

The trace identifies the module, class where practical, function or method,
caller, callee, instance identity where practical, call depth, event order,
timestamp, safe argument summaries, and safe return summaries.

When project-local code is already on the trace stack, Skeleton also records a
small allow-list of standard-library boundary calls. Today that includes
stdout, filesystem operations, SQLite operations, and basic network socket
calls. Filesystems, stdout, and databases appear as resource cylinders.
Network calls appear as external-service diamonds, because an external service
is an architectural collaborator rather than an I/O resource.

## How it works

Skeleton does not patch your source code. It uses Python's own runtime
introspection:

- `runpy.run_path()` runs the target script as `__main__` inside a controlled
  runner.
- `sys.setprofile()` receives callbacks whenever Python enters or returns from a
  function, plus selected C-level resource calls such as `print` or
  `sqlite3.connect`.
- Each callback receives a frame object. From that frame Skeleton reads
  `frame.f_code`, `frame.f_globals`, and `frame.f_locals` to identify the file,
  module, function name, line number, arguments, and whether the call has
  `self`.
- When `self` is present, Skeleton records `type(self).__name__` and
  `id(self)`, giving a run-local object identity such as
  `service.Greeter@0x...`.
- Values are summarized immediately, then the raw objects are discarded.

That is why the report can show instance-owned methods without decorators. It is
not reading class source to guess behavior; it is watching Python call real
functions on real objects. The object ids are only meaningful within one run,
not across processes or commits.

For more detail, see
[`docs/design/runtime-introspection.md`](docs/design/runtime-introspection.md).

## Current scope and next integrations

Skeleton currently runs a script path:

```bash
python -m skeleton_replay run scripts/replay_checkout.py
```

That script can drive any kind of Python code: CLI workflows, service objects,
batch jobs, web-app internals, or library calls. The application being traced
does not need to be a CLI application, but v0 does need a script entrypoint that
exercises the behavior.

Planned integrations:

- `run-module`: support module execution such as
  `python -m my_app.cli run-demo`, exposed as something like
  `skeleton run-module my_app.cli -- run-demo`.
- pytest plugin: trace selected tests or test sessions, because tests often
  encode real business workflows.
- live web request tracing: trace one request or handler inside a running
  FastAPI, Flask, Django, or Starlette app through middleware or a capture
  context.
- PyCharm plugin: a thin IDE frontend that invokes Skeleton with the configured
  interpreter and opens the generated report.

See [`docs/api/python-api.md`](docs/api/python-api.md),
[`docs/development/missing-integration-plans.md`](docs/development/missing-integration-plans.md),
and [`docs/development/pypi-release-plan.md`](docs/development/pypi-release-plan.md).

Release history is tracked in [`CHANGELOG.md`](CHANGELOG.md). Keep the
changelog updated in the same pull request or commit that changes user-visible
behavior.

## Event schema

Each line in `.skeleton/trace.jsonl` is a JSON object:

```json
{
  "schema_version": 1,
  "event_type": "call",
  "order": 0,
  "timestamp": 1782740000.0,
  "depth": 0,
  "caller": null,
  "callee": {
    "module": "app",
    "class_name": null,
    "function": "main",
    "qualified_name": "app.main",
    "file": "/project/app.py",
    "line": 10,
    "node_id": "function:app.main",
    "instance_id": null,
    "endpoint_type": "function",
    "resource_category": null
  },
  "args": {}
}
```

Return events use the same endpoint shape and include `return_value`.
Resource endpoints use the same shape with `endpoint_type: "resource"`, a
`resource_category` such as `stdout`, `file`, or `db`, and a
`node_id` beginning with `resource:`. Resource nodes are aggregated by boundary
kind, for example `resource.database` or `resource.stdout`; the specific
operation, such as `connect` or `print`, is kept in the safe event evidence.
Network endpoints use `endpoint_type: "external_service"` and render as
diamond-shaped external service entities.

## Safety model

Skeleton records summaries, not full object contents.

- Strings are truncated.
- Containers include type, length, and a small preview.
- Objects include only class name and object id.
- Argument or mapping names containing `password`, `token`, `secret`, `key`,
  `auth`, or `credential` are redacted.

This is not a debugger replacement and not a performance profiler. It is a
runtime architecture replay tool for understanding how a codebase behaves.
