One command. Every language. A single index.scip.
SCIP Index Orchestrator — detect languages, download indexers, run them, merge the results.
SCIP-IO is a polyglot SCIP index orchestrator written in Rust. It takes the pain out of generating precise code-intelligence indexes for multi-language projects by doing the whole pipeline for you:
- Detects every language in your project from manifest files.
- Installs the correct SCIP indexer binary for each language (downloading from GitHub releases, npm,
dotnet tool, Coursier, or reusing what's already on yourPATH). - Runs each indexer against your project with sensible defaults.
- Merges every per-language
.scipfile into a single deterministicindex.scip. - Validates the final index so you know it's wellformed.
It ships as both a CLI (scip-io) and a Tauri GUI with a dark/cyberpunk-corporate aesthetic — use whichever fits your workflow.
SCIP is the modern successor to LSIF for code intelligence. Every language has its own indexer, every indexer has its own install method, flags, and output conventions, and merging them requires understanding the SCIP protobuf schema. SCIP-IO collapses that entire workflow into:
scip-io indexSCIP-IO currently orchestrates 11 languages across 9 different indexers:
| Language | Indexer | Install Method | Detected From |
|---|---|---|---|
| TypeScript | scip-typescript |
npm | tsconfig.json |
| JavaScript | scip-typescript |
npm | package.json |
| Python | scip-python |
npm | pyproject.toml, setup.py, setup.cfg, requirements.txt, Pipfile |
| Rust | rust-analyzer |
GitHub release (gz/zip) | Cargo.toml |
| Go | scip-go |
GitHub release (tar.gz) | go.mod |
| Java | scip-java |
Coursier launcher | pom.xml, build.gradle |
| Scala | scip-java |
Coursier launcher | build.sbt |
| Kotlin | via scip-java |
compiler plugin | build.gradle.kts, settings.gradle.kts |
| C# | scip-dotnet |
dotnet tool |
*.csproj, *.sln |
| Ruby | scip-ruby |
GitHub release | Gemfile |
| C / C++ | scip-clang |
GitHub release | CMakeLists.txt, compile_commands.json |
SCIP-IO will also pick up any of these binaries already on your system PATH before downloading a fresh copy.
flowchart TB
subgraph Row1[" "]
direction LR
A[Project Root] --> B[Detect<br/>Languages]
B --> C[Resolve Indexers<br/>from Registry]
C --> D[Ensure Indexers<br/>Installed]
D --> E[Run Indexers<br/>in parallel]
end
subgraph Row2[" "]
direction LR
F[Per-language<br/>.scip files] --> G[Merge]
G --> H[(index.scip)]
H --> I[Validate]
end
E --> F
style Row1 fill:transparent,stroke:transparent
style Row2 fill:transparent,stroke:transparent
style A fill:#1e2336,stroke:#00ffcc,stroke-width:2px,color:#fff
style B fill:#1e2336,stroke:#00ffcc,stroke-width:2px,color:#fff
style C fill:#1e2336,stroke:#00ffcc,stroke-width:2px,color:#fff
style D fill:#1e2336,stroke:#00ffcc,stroke-width:2px,color:#fff
style E fill:#1e2336,stroke:#00ffcc,stroke-width:2px,color:#fff
style F fill:#1e2336,stroke:#8b5cf6,stroke-width:2px,color:#fff
style G fill:#1e2336,stroke:#ff00aa,stroke-width:2px,color:#fff
style H fill:#0a0e1b,stroke:#ff00aa,stroke-width:3px,color:#ff00aa
style I fill:#1e2336,stroke:#00ffcc,stroke-width:2px,color:#fff
Detection is manifest-driven, not extension-based. Walking every .ts or .py file in a monorepo is slow and noisy; SCIP-IO looks for the files that unambiguously declare a language project:
flowchart TD
Start([Start]) --> Walk[Walk project tree<br/>max depth 3]
Walk --> Skip{Hidden or<br/>ignored dir?<br/>.git, node_modules,<br/>target, vendor, venv}
Skip -- Yes --> Walk
Skip -- No --> Match{Matches a<br/>manifest pattern?}
Match -- No --> Walk
Match -- Yes --> Record[Record language<br/>+ evidence path]
Record --> Walk
Walk --> Done([Dedupe + sort])
style Start fill:#0a0e1b,stroke:#00ffcc,color:#00ffcc
style Done fill:#0a0e1b,stroke:#ff00aa,color:#ff00aa
SCIP-IO supports several install methods because no two SCIP indexers ship the same way:
flowchart TD
Need[Need indexer X] --> OnPath{Already on<br/>system PATH?}
OnPath -- Yes --> Use[Use existing binary]
OnPath -- No --> Cached{In local<br/>cache dir?}
Cached -- Yes --> Use
Cached -- No --> Method{Install method?}
Method -- GitHubBinary --> DL1[Download release asset]
Method -- GitHubGz --> DL2[Download + gunzip]
Method -- GitHubTarGz --> DL3[Download + untar]
Method -- GitHubZip --> DL4[Download + unzip]
Method -- GitHubLauncher --> DL5[Download Coursier<br/>launcher script]
Method -- Npm --> DL6[npm install into<br/>cache dir]
Method -- DotnetTool --> DL7[dotnet tool install]
Method -- Unsupported --> Fail[Error: manual install required]
DL1 --> Use
DL2 --> Use
DL3 --> Use
DL4 --> Use
DL5 --> Use
DL6 --> Use
DL7 --> Use
style Use fill:#0a0e1b,stroke:#00ffcc,color:#00ffcc
style Fail fill:#0a0e1b,stroke:#ff3366,color:#ff3366
Merging is deterministic: same inputs always produce a byte-identical index.scip, regardless of which order indexers finished. Overlapping documents (e.g. generated files touched by more than one indexer) are combined rather than duplicated.
flowchart LR
T[typescript.scip] --> M{{merge_scip_files}}
P[python.scip] --> M
R[rust.scip] --> M
G[go.scip] --> M
D[….scip] --> M
M --> O[(index.scip)]
O --> V[Validate<br/>documents, symbols,<br/>occurrences, languages]
style M fill:#1e2336,stroke:#8b5cf6,color:#fff
style O fill:#0a0e1b,stroke:#ff00aa,color:#ff00aa
style V fill:#1e2336,stroke:#00ffcc,color:#fff
Linux / macOS:
curl -LsSf https://github.com/GlitterKill/scip-io/releases/latest/download/install.sh | shWindows (PowerShell):
irm https://github.com/GlitterKill/scip-io/releases/latest/download/install.ps1 | iexBoth scripts download the right binary for your OS/architecture, extract it to a user-writable location (~/.local/bin or %LOCALAPPDATA%\scip-io\bin), and update your PATH.
Grab the right file for your platform from the latest release:
| Platform | File |
|---|---|
| CLI — Windows x64 | scip-io-vX.Y.Z-x86_64-pc-windows-msvc.zip |
| CLI — macOS x64 (Intel) | scip-io-vX.Y.Z-x86_64-apple-darwin.tar.gz |
| CLI — macOS ARM (Silicon) | scip-io-vX.Y.Z-aarch64-apple-darwin.tar.gz |
| CLI — Linux x64 | scip-io-vX.Y.Z-x86_64-unknown-linux-gnu.tar.gz |
| GUI — Windows installer | SCIP-IO_X.Y.Z_x64-setup.exe or SCIP-IO_X.Y.Z_x64_en-US.msi |
| GUI — macOS disk image | SCIP-IO_X.Y.Z_x64.dmg / SCIP-IO_X.Y.Z_aarch64.dmg |
| GUI — Linux package | scip-io_X.Y.Z_amd64.deb or scip-io_X.Y.Z_amd64.AppImage |
Verify your download with SHA256SUMS.txt attached to the release.
Heads up — unsigned binaries: Until SCIP-IO is code-signed, Windows SmartScreen will warn "unrecognized app" (click More info → Run anyway) and macOS Gatekeeper will block first launch (right-click the app → Open, then confirm).
Requires Rust stable 1.80+ (rustup.rs). For the GUI you also need the Tauri 2 prerequisites (WebView2 on Windows, webkit2gtk on Linux).
git clone https://github.com/GlitterKill/scip-io.git
cd scip-io
# CLI only
cargo build --release -p scip-io-cli
./target/release/scip-io --help
# GUI
cargo install tauri-cli --version "^2.0"
cargo tauri buildThe CLI binary is scip-io; the GUI bundles as SCIP-IO via Tauri.
SCIP-IO downloads and manages indexer binaries, but some indexers need a language runtime installed on your system:
- Node.js — for
scip-typescriptandscip-python(both npm packages) - JVM — for
scip-java(Scala and Java indexing) - .NET SDK — for
scip-dotnet(C# indexing)
Other indexers (rust-analyzer, scip-go, scip-ruby, scip-clang) ship as standalone binaries and don't need extra toolchains. Run scip-io status to see which indexers are ready.
cd your/polyglot/project
scip-io detect # see what SCIP-IO found
scip-io index # download indexers, run them, merge → index.scip
scip-io validate index.scipThat's it. Point any SCIP-consuming tool at index.scip.
All commands accept --help. The examples below assume you're running them from inside the project you want to index.
Scan a project for supported languages without touching any indexers.
scip-io detect
scip-io detect --path ./services/api
scip-io detect --format json
scip-io detect --depth 5Example output:
Detected 3 languages:
rust — Cargo.toml
typescript — gui/tsconfig.json
javascript — gui/package.json
Options:
| Flag | Description |
|---|---|
-p, --path |
Project root (defaults to current directory) |
-f, --format |
text (default) or json |
-d, --depth |
Max directory depth to scan |
The main event: detect, install, run, merge, and write a single index.scip.
# Index everything in the current directory
scip-io index
# Only index specific languages
scip-io index --lang rust,typescript
# Custom output path
scip-io index --output ./artifacts/project.scip
# Dry run — see what would happen, don't touch anything
scip-io index --dry-run
# Index a monorepo by discovering every sub-project root
scip-io index --all-roots
# Index specific sub-project roots
scip-io index --roots ./services/api,./services/web
# Keep the per-language .scip files instead of merging
scip-io index --no-merge
# Control concurrency and timeouts
scip-io index --parallel 4 --timeout 600Options:
| Flag | Description |
|---|---|
-p, --path |
Project root |
-l, --lang |
Comma-separated language filter (case-insensitive) |
-o, --output |
Merged output path (default index.scip) |
--no-merge |
Keep individual .scip files, skip the merge step |
--parallel |
Max concurrent indexer processes |
--timeout |
Per-indexer timeout in seconds |
-f, --format |
text or json progress output |
--dry-run |
Print the plan without running anything |
--roots |
Comma-separated sub-project roots to index |
--all-roots |
Auto-discover every sub-project root in a monorepo |
Show which indexers are installed and where.
scip-io status
scip-io status --verbose
scip-io status --format json
scip-io status --check-updatesExample output:
Indexer Status:
scip-typescript v0.4.0 ● installed (npm cache)
scip-python v0.6.6 ● installed (npm cache)
rust-analyzer 2026-03-30 ● installed (PATH)
scip-java v0.12.3 ○ not installed
scip-clang v0.4.0 ○ not installed
Manually merge a set of .scip files into one. Useful for CI where per-language files are built in separate stages.
scip-io merge ts.scip py.scip rust.scip --output all.scip
scip-io merge *.scip --output merged.scip --validateOptions:
| Flag | Description |
|---|---|
<inputs> |
One or more .scip files (required) |
-o, --output |
Output path (default index.scip) |
--validate |
Validate the merged output after writing |
Parse a .scip file, check structural invariants, and print stats.
scip-io validate index.scip
scip-io validate index.scip --format jsonExample output:
index.scip is valid
documents: 1,247
symbols: 38,091
occurrences: 214,563
languages: rust, typescript, javascript
Remove cached indexer binaries.
scip-io clean # interactive prompt
scip-io clean --lang rust # only rust-analyzer
scip-io clean --all # wipe the whole cache dir
scip-io clean --dry-run # show what would be removedLaunch the Tauri GUI (when the GUI crate is built).
scip-io gui
scip-io gui --path ./my-projectDrop a .scip-io.toml at the root of any project to override defaults:
# .scip-io.toml
output = "artifacts/index.scip"
parallel = 4
timeout = 600
[indexers.typescript]
binary = "/usr/local/bin/scip-typescript" # use a custom binary
[indexers.rust]
args = ["scip", ".", "--exclude", "vendor"]All config keys can be overridden on the command line.
scip-io/
├── crates/
│ ├── scip-io-core/ ← library: detection, registry, install, run, merge, validate
│ └── scip-io-cli/ ← scip-io binary (clap)
├── src-tauri/ ← Tauri v2 GUI backend
├── gui/ ← Vite + TypeScript frontend
├── docs/assets/ ← README images, diagrams
└── Cargo.toml ← workspace root
Issues and PRs welcome. Before sending a PR:
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo testThe CI GitHub Actions workflow runs these same checks on Linux, macOS, and Windows for every PR.
Releases are fully automated: pushing a vX.Y.Z git tag triggers .github/workflows/release.yml, which cross-compiles the CLI for Windows, macOS (Intel + Apple Silicon), and Linux, builds the Tauri GUI installers for all three OSes, and publishes everything to a GitHub Release with SHA-256 checksums and install scripts.
See RELEASING.md for the full release checklist and CHANGELOG.md for the version history.
