Metadata-Version: 2.4
Name: ty-scip
Version: 0.1.0
License-File: LICENSE
License-File: THIRD_PARTY_NOTICES
Summary: A fast SCIP indexer for Python, powered by ty
Author: Brendan Murphy
License-Expression: MIT
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Issues, https://github.com/brendan-m-murphy/ty-scip/issues
Project-URL: Repository, https://github.com/brendan-m-murphy/ty-scip

# ty-scip

**A fast SCIP indexer for Python, powered by ty.**

`ty-scip` is a preview SCIP indexer for Python. It turns ty's Python
project model and semantic navigation results into a deterministic index that
is tested with SCIP 0.10 and the SCIP 0.8-based `scip-cli` 2.7 conversion path.

This is an independent project. It is not affiliated with or endorsed by
Astral or Sourcegraph.

The indexer is written in Rust because ty and Ruff expose the required parser,
project, and semantic APIs as Rust crates. `ty-scip` consumes those crates
directly at one pinned Ruff commit: it is a small adapter, not a Ruff fork and
not an LSP client.

## Status

Version 0.1.0 is preview software. It indexes useful first-party structure and
supports the common `scip-python` command shape, but it is not a drop-in
replacement. The pinned ty/Ruff crates are unpublished internal crates without
an API-stability promise, and the `ty-scip` symbol scheme may still change.

The project is MIT licensed. Version 0.1.0 provides binary wheels for Linux
x86-64 and ARM64 (glibc 2.17 or newer), macOS x86-64 and ARM64, and Windows
x86-64. There is no source distribution or crates.io package. Binary packages
include the project license and the generated
[third-party notices](THIRD_PARTY_NOTICES).

## Install

Run without keeping an installation:

```console
uvx ty-scip index . --output index.scip
```

Or install the `ty-scip` executable with one of:

```console
uv tool install ty-scip
pipx install ty-scip
python -m pip install ty-scip
```

The wheel contains a native executable, not an importable Python API. The
installer's Python environment is independent of the Python environment that
ty selects for the indexed project.

## Build from source

The crate declares Rust 1.96 and is currently exercised with Rust 1.98.1.
Building needs Git access to fetch the pinned Ruff revision.

```console
cargo build --release --locked
./target/release/ty-scip --help
```

To install the current checkout on your `PATH`:

```console
cargo install --locked --path .
```

## Use

```console
ty-scip [index] [OPTIONS] [PROJECT_PATH] [OUTPUT.scip]
```

With no arguments, `ty-scip` indexes the current directory and writes
`index.scip` there. If only `PROJECT_PATH` is supplied, the output is still
written as `index.scip` in the caller's current directory.

```console
# Current project -> ./index.scip
ty-scip

# scip-python-style command -> ./index.scip
ty-scip index . --output index.scip

# Another project discovery path -> explicit output
ty-scip ../project ./project.scip

# Override the package identity recorded in global symbols
ty-scip --project-name example --project-version 1.2.3 ../project
```

Options:

- `--output PATH`: write the index to `PATH`; cannot be combined with the
  positional output path.
- `--cwd PATH`: resolve relative project and output paths from `PATH`.
- `--quiet`: suppress successful-run diagnostics; errors still go to stderr.
- `--project-name NAME`: override the SCIP package name.
- `--project-version VERSION`: override the SCIP package version.
- `-h`, `--help`: print help.
- `-V`, `--version`: print the version.

Normal output is quiet on stdout. A summary of indexed definitions,
references, unresolved and ambiguous queries, external targets, safely skipped
links, and parser diagnostics is written to stderr. Set
`TY_SCIP_SAMPLE_LIMIT=N` to include up to `N` deterministic examples from each
unresolved and ambiguous category.

The positional project path is where ty starts configuration discovery; an
ancestor `ty.toml` or `pyproject.toml` may determine the actual project root.
Project discovery, source selection, import resolution, and Python-environment
behavior come from ty. Configure them with `ty.toml` or `[tool.ty]` in
`pyproject.toml`; Pyright configuration is not read. File symlinks are selected,
but ty does not traverse symlinked directories. Package name and version come
from the command-line overrides first, then static PEP 621 `[project]`
metadata, then an empty deterministic fallback.

See [migrating from scip-python](docs/migration-from-scip-python.md) for the
supported command mapping and deliberately unsupported options.

## What it indexes

The current index includes:

- first-party `.py` and `.pyi` files selected by ty;
- modules, classes, callables, parameters, type parameters, properties,
  fields, variables, imports, and function-local bindings;
- unambiguous first-party name, attribute, import, re-export, and keyword
  references;
- analyzer-confirmed names inside quoted annotations, without scanning
  ordinary string contents;
- normalization of overloads and repeated definitions that denote one binding;
- generated dataclass/NamedTuple/TypedDict constructor fields and TypedDict
  string-key reads when ty resolves them to declared fields;
- stable lexical symbols for named nested functions and classes while anonymous
  and ordinary function-local bindings remain document-local;
- class-member identities for instance attributes that ty proves belong to a
  direct method whose inferred callable semantics preserve normal receiver
  behavior, including inherited reads and safe decorated methods;
- direct first-party class-base implementation relationships;
- SCIP definition, import, read, write, and augmented read/write roles, symbol
  kinds including semantically verified properties, display names, docstrings,
  source-faithful callable/class/annotated-assignment/type-alias signatures,
  and enclosing ranges; and
- both SCIP 0.10 typed ranges and equivalent legacy range fields.

Missing semantic evidence is an omission, not a guessed link. Proven runtime
standard-library targets use a `python-stdlib` package identity with ty's
configured Python major/minor version. Typing-only and installed third-party
targets remain counted omissions. Distinct multi-target results remain
ambiguous, document-local identities are not linked across files, and
transformed-method receiver attributes are skipped.

See [compatibility and limitations](docs/compatibility.md) for the detailed
feature matrix and the ty APIs evaluated for future work.

## Compatibility and evidence

The dual range encoding passes SCIP 0.10 lint on the focused fixtures and
supports the SCIP 0.8-based conversion path used by `scip-cli` 2.7.0.
Compatibility is tested at the query layer because protobuf validity alone
does not prove that converted mentions survive. Both tested linter versions
intermittently misreport valid cross-document relationship targets on the
larger OpenGHG index; every reported target has symbol information and a
definition occurrence, and the error set changes between runs of identical
bytes.

The version 0.1.0 release gate indexed all 281 documents in the frozen OpenGHG
checkout with 22,975 definitions and 53,264 references, and repeated candidate
runs produced byte-identical indexes. The converted index contained 542 chunks
and 20,586 mentions and passed the isolated `scip-cli` search, code, members,
references, dependencies, and reverse-dependencies gate. The locked comparison
to the patched `scip-python` reference retains six reviewed source ranges where
`ty-scip` omits a reference target. Index replacement uses an exclusively
created sibling temporary file followed by an atomic rename. Two
planning tasks produced accurate scopes and 24/24 valid cited locations, but
the benchmarked arm did not beat built-in search: it used about 34% more total
tokens, 6.5% more uncached input, and 2% more elapsed time. These results
support `ty-scip` as a fast structural-navigation backend, not an agent
efficiency claim.

## Development

Run the smallest complete local gate before submitting a change:

```console
cargo fmt --all --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
cargo build --release --locked
```

When `Cargo.lock` or the Ruff pin changes, install the pinned maintenance tool
and regenerate the reviewed third-party notice bundle:

```console
cargo install cargo-about --locked --version 0.9.2 --features cli
python scripts/licenses.py
python scripts/licenses.py --check
```

To validate the actual binary-wheel contents and installed command:

```console
python -m pip install maturin==1.15.0
maturin build --release --locked
python scripts/check_wheel.py target/wheels/*.whl
```

These Python scripts are packaging checks, not a Python wrapper or runtime
dependency of `ty-scip`.

Semantic changes need a decoded-SCIP regression that proves both the desired
link and the relevant false-link case. Before changing the Ruff pin, follow
the update checklist in [compatibility and limitations](docs/compatibility.md).
The remaining analyzer seams are recorded as narrow
[candidate upstream ty APIs](docs/upstream-ty-api-requests.md).

## License

Copyright 2026 Brendan Murphy. Released under the [MIT License](LICENSE).
Binary distributions also carry the generated
[third-party notices](THIRD_PARTY_NOTICES).

