Recursively scans a directory and outputs a flat, LLM-friendly file tree
Project description
filescan
filescan is a Python tool for analyzing code at scale through flat graph representations.
Scan two layers of your codebase and export them as graph data:
- ๐ Filesystem Graph: Directory structure โ parent/child relationships
- ๐ง Python AST Graph: Python source code โ modules, classes, functions, and cross-file semantic relationships
Instead of nested trees, filescan produces flat node and edge tables (CSV/JSON) suitable for:
- ๐ SQL and Pandas analysis
- ๐ค LLM code understanding (token-efficient)
- ๐ Static analysis pipelines
- ๐๏ธ Graph algorithms and embeddings
Why Flat Graphs?
Traditional nested JSON/tree structures are:
- ๐ Verbose and deeply nested
- ๐ฉ Hard to filter, join, or aggregate
- ๐ฐ Expensive for LLM token usage
- โ ๏ธ Inefficient for large codebases
filescan instead uses explicit node and edge tables:
nodes.csv (id, type/kind, name, metadata...)
edges.csv (id, source, target, relation, ...)
Benefits:
- โ Materialize relationships explicitly
- โ Works naturally with SQL, Pandas, DuckDB
- โ Lower token overhead for LLMs
- โ Great for graph algorithms
- โ Deterministic and reproducible
Features
๐ Filesystem Scanner
- Recursive directory traversal in deterministic order
- Parent โ child edge relationships
- File size and metadata
- Supports
.gitignore-style ignore rules (.fscanignore) - CSV + JSON export
- Deterministic, collision-safe node IDs
๐ง Python AST Scanner
- Definitions: Modules, classes, functions, methods
- Docstrings: First-line capture for context
- Signatures: Function/method parameters (best-effort)
- Line numbers: Exact source locations
- Cross-file relationships:
containsโ class contains methodimportsโ module imports symbolcallsโ function calls another functioninheritsโ class inherits from base classreferencesโ any other reference
โ๏ธ Core Capabilities
- Multi-root scanning support
- Unified programmatic API
- CLI with multiple commands (
scan,watch,search) - File watcher with auto-rescan
- Hybrid text + semantic search
- Built-in ignore rules (Python-aware defaults)
Installation
From PyPI
pip install filescan
Development Mode
git clone https://github.com/DreamSoul-AI/filescan.git
cd filescan
pip install -e .
Requirements: Python 3.10+
Quick Start
CLI: Scan a Directory
# Scan filesystem structure
filescan ./src
# Include Python AST analysis
filescan ./src --ast
# Export as JSON instead of CSV
filescan ./src --ast --format json
# Custom output location
filescan ./src --ast -o results/myproject
Output:
results/
โโโ myproject_nodes.csv
โโโ myproject_edges.csv
โโโ myproject.json
โโโ myproject_ast_nodes.csv
โโโ myproject_ast_edges.csv
โโโ myproject_ast.json
CLI: Watch Mode (Auto-Rescan)
filescan watch ./src --ast --debounce 0.5
Re-scans automatically when .py files change. Useful during development.
CLI: Semantic Search
filescan search ./src "MyClass" \
--nodes graph_ast_nodes.csv \
--edges graph_ast_edges.csv
Finds all references to MyClass in the codebase with semantic context.
Library Usage
Filesystem Scanner
from filescan import Scanner
# Create scanner for directory
scanner = Scanner(root="./data")
# Scan into a graph builder
builder = GraphBuilder()
builder.build(roots=["./data"])
builder.export_filesystem("output/fs")
# Access data
nodes = scanner.scan()
print(f"Found {len(nodes)} nodes")
Python AST Scanner
from filescan import AstScanner, GraphBuilder
# Create AST scanner
scanner = AstScanner(
root="./src",
ignore_file=".fscanignore"
)
# Build and export
builder = GraphBuilder()
builder.build(roots=["./src"], include_ast=True, ignore_file=".fscanignore")
builder.export_ast("output/ast")
Advanced: GraphBuilder
from filescan import GraphBuilder
from pathlib import Path
# Single-pass builder for both graphs
builder = GraphBuilder()
builder.build(
roots=[Path("./src"), Path("./tests")], # Multiple roots
include_filesystem=True,
include_ast=True,
ignore_file=".fscanignore"
)
# Export with custom prefixes
builder.export_filesystem("output/fs")
builder.export_ast("output/ast")
# Access graph data programmatically
fs_nodes = builder.filesystem.nodes
fs_edges = list(builder.filesystem.edges)
ast_nodes = builder.ast.nodes
ast_edges = list(builder.ast.edges)
Ignore Rules (.fscanignore)
filescan supports gitignore-style patterns via pathspec.
Resolution order:
--ignore-fileCLI argument (if provided)./.fscanignorein working directory (if exists)- Built-in defaults (ignore
.git,__pycache__,.pyc, etc.)
Example .fscanignore:
# Version control
.git/
.hg/
# IDEs
.vscode/
.idea/
*.swp
# Python
__pycache__/
*.pyc
*.pyo
*.egg-info/
.venv/
venv/
# Build & dist
build/
dist/
*.egg
# Project-specific
node_modules/
.DS_Store
Patterns apply to both filesystem and AST scanning (ignored files are skipped).
Output Schemas
Filesystem Graph
Nodes (*_nodes.csv):
| Field | Type | Description |
|---|---|---|
id |
String | Unique node identifier (hash-based) |
type |
Char | 'd' (directory) or 'f' (file) |
name |
String | Base name of file/directory |
abs_path |
String | Absolute file system path |
size |
Integer | File size in bytes (null for dirs) |
Edges (*_edges.csv):
| Field | Type | Description |
|---|---|---|
id |
String | Unique edge identifier |
source |
String | Parent node ID |
target |
String | Child node ID |
relation |
String | Always 'contains' |
Python AST Graph
Nodes (*_nodes.csv):
| Field | Type | Description |
|---|---|---|
id |
String | Unique symbol identifier |
kind |
String | module, class, function, method |
name |
String | Symbol name (unqualified) |
qualified_name |
String | Full dotted path (e.g., module.Class.method) |
module_path |
String | File path relative to scan root |
lineno |
Integer | Starting line number (1-based) |
end_lineno |
Integer | Ending line number |
signature |
String | Function/method signature (best-effort) |
doc |
String | First line of docstring (if present) |
Edges (*_edges.csv):
| Field | Type | Description |
|---|---|---|
id |
String | Unique edge identifier |
source |
String | Source node ID |
target |
String | Target node ID |
relation |
String | Relationship type (see below) |
lineno |
Integer | Line where relationship occurs |
end_lineno |
Integer | End line of relationship |
Relation Types:
containsโ Parent symbol contains child (class โ method, module โ class)importsโ Module imports a symbolcallsโ Function/method calls anotherinheritsโ Class inherits from base classreferencesโ Other semantic reference
Use Cases
1. LLM-Based Code Understanding
Feed flat CSVs to Claude/GPT for code analysis without token bloat:
nodes_csv, edges_csv = scan_project(root)
context = build_context_for_llm(nodes_csv, edges_csv)
response = llm.analyze(context)
2. Static Analysis & Code Quality
Use SQL/DuckDB for queries:
-- Find all functions with no docstring
SELECT name, qualified_name, module_path
FROM ast_nodes
WHERE kind = 'function' AND doc IS NULL;
-- Find unused classes (no incoming calls/references)
SELECT n.name
FROM ast_nodes n
LEFT JOIN ast_edges e ON n.id = e.target
WHERE n.kind = 'class' AND e.id IS NULL;
3. Refactoring & Architecture
Build dependency graphs, identify circular imports, plan migrations.
4. Embeddings & Search
Compute embeddings per node, build semantic search indexes.
5. Data Pipelines
Load into Pandas for custom analysis:
import pandas as pd
nodes = pd.read_csv("ast_nodes.csv")
edges = pd.read_csv("ast_edges.csv")
# Classes per module
classes_per_module = nodes[nodes['kind'] == 'class'].groupby('module_path').size()
print(classes_per_module)
Commands Reference
filescan scan
Run filesystem and/or AST scan.
filescan scan <ROOT> [OPTIONS]
Options:
--ignore-file FILEโ Use custom ignore file--astโ Include Python AST scan (default: filesystem only)--ast-onlyโ Skip filesystem, only scan AST-o, --output PREFIXโ Output file prefix (default:graph)--output-ast PREFIXโ Separate prefix for AST output--format {csv,json}โ Export format (default:csv)
Examples:
# Filesystem only
filescan scan ./src -o results/fs
# Both filesystem and AST
filescan scan ./src --ast -o results/project
# AST only, JSON format
filescan scan ./src --ast-only --format json -o results/ast
# Custom ignore file
filescan scan ./src --ast --ignore-file .scanignore -o results/custom
filescan watch
Watch a project directory and auto-scan on Python file changes.
filescan watch <ROOT> [OPTIONS]
Options:
--ignore-file FILEโ Use custom ignore file-o, --output PREFIXโ Output file prefix (default:graph)--output-ast PREFIXโ Separate prefix for AST output--debounce SECONDSโ Debounce interval (default:0.5)
Example:
# Watch for changes, rescan every 0.5 seconds
filescan watch ./src --ast -o results/live --debounce 0.5
Press Ctrl+C to stop watching.
filescan search
Search an existing AST graph with semantic context.
filescan search <ROOT> <QUERY> --nodes <FILE> --edges <FILE>
Required:
<ROOT>โ Project root (must match AST scan root)<QUERY>โ Search query (symbol name)--nodes FILEโ Path to AST nodes CSV--edges FILEโ Path to AST edges CSV
Example:
filescan search ./src "MyClass" \
--nodes graph_ast_nodes.csv \
--edges graph_ast_edges.csv
Output:
Shows all occurrences with semantic context:
- Match type (definition, call, reference, import, inherit)
- File path and line number
- Source code context
- Definition source (if available)
Development
Project Structure
filescan/
โโโ src/filescan/
โ โโโ __init__.py # Public API
โ โโโ base.py # ScannerBase (ID generation, ignore handling)
โ โโโ scanner.py # Filesystem scanner
โ โโโ ast_scanner.py # Python AST scanner (astroid)
โ โโโ graph_builder.py # Unified builder
โ โโโ search_engine.py # Hybrid search (ripgrep + AST)
โ โโโ file_watcher.py # File change watcher
โ โโโ utils.py # Utilities
โ โโโ commands/
โ โ โโโ cli.py # CLI entry point
โ โโโ default.fscanignore # Built-in ignore rules
โโโ tests/ # Unit tests
โโโ examples/ # Usage examples
โโโ pyproject.toml
Running Tests
pytest tests/
Running Examples
python examples/scan_self.py
python examples/search_self.py
python -m examples.watch_self
Building & Publishing
# Build wheel
python -m build
# Upload to PyPI
python -m twine upload dist/*
Comparison to Alternatives
| Feature | filescan |
AST-only tools | Tree JSON | ripgrep |
|---|---|---|---|---|
| Filesystem structure | โ | โ | โ | โ |
| Python AST | โ | โ | โ | โ |
| Flat graph design | โ | โ | โ | โ |
| CSV/SQL-friendly | โ | โ | โ | โ |
| Cross-file semantics | โ | ~Some | โ | โ |
| CLI + Library | โ | ~Some | โ | โ |
| LLM-optimized | โ | โ | โ | โ |
Architecture Notes
Deterministic IDs
All node and edge IDs are generated deterministically from content hashes. This ensures:
- โ Reproducible scans (same input โ same IDs)
- โ Collision detection and handling
- โ Stable linking across multiple scans
Two-Pass AST Scanning
- Pass 1 โ Definitions: Collect all module/class/function definitions across all Python files
- Pass 2 โ Relationships: Resolve cross-file imports, calls, inherits, and references
This ensures all semantic relationships are resolvable in a single pass.
Hybrid Search
The search engine combines:
- ripgrep for fast text search
- AST index for semantic enrichment
Results are ranked by semantic priority (definition > call > reference > import).
Performance
Typical scan times (on modern hardware):
| Target | Filesystem | AST | Combined |
|---|---|---|---|
| 1K files | ~50ms | ~200ms | ~250ms |
| 10K files | ~200ms | ~2s | ~2.2s |
| 100K files | ~2s | ~20s | ~22s |
filescan is designed for sub-second iteration during development via watch mode.
Limitations & Known Issues
- AST signatures are best-effort (lambda functions, comprehensions may be incomplete)
- Dynamically resolved imports (e.g.,
__import__, exec) are not captured - Relationship extraction depends on static analysis (no runtime tracing)
- Search is file-relative; cross-filesystem projects need unified root
Contributing
Contributions welcome! Open issues or PRs on GitHub.
License
MIT License โ see LICENSE file.
Support
- ๐ Documentation: See this README and examples/
- ๐ Report Issues: GitHub Issues
- ๐ฌ Discussions: GitHub Discussions
Made with โค๏ธ by DreamSoul
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file filescan-0.0.5.tar.gz.
File metadata
- Download URL: filescan-0.0.5.tar.gz
- Upload date:
- Size: 29.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c3a93d90a356512c098087d9f4518631196b28bb9865498465906f2e7769e9c
|
|
| MD5 |
3a7dc821c1530ebb3b7ee0e8c577937c
|
|
| BLAKE2b-256 |
b0d9a27986fe89786ba9dc92ae7d7d0ff4eb721960232d7666f24fa225ed5128
|
Provenance
The following attestation bundles were made for filescan-0.0.5.tar.gz:
Publisher:
publish.yml on DreamSoul-AI/filescan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
filescan-0.0.5.tar.gz -
Subject digest:
4c3a93d90a356512c098087d9f4518631196b28bb9865498465906f2e7769e9c - Sigstore transparency entry: 1018869087
- Sigstore integration time:
-
Permalink:
DreamSoul-AI/filescan@644719fd18219bdce3e53eb6ef4d4fce8af752e6 -
Branch / Tag:
refs/tags/v0.0.5 - Owner: https://github.com/DreamSoul-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@644719fd18219bdce3e53eb6ef4d4fce8af752e6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file filescan-0.0.5-py3-none-any.whl.
File metadata
- Download URL: filescan-0.0.5-py3-none-any.whl
- Upload date:
- Size: 23.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c69705417fc6c6ceeb6dd548ce29f4b42b73116ec246cd062f33b20a4ef28c1f
|
|
| MD5 |
dd6666580e2a601d464da6cdf7060345
|
|
| BLAKE2b-256 |
3ec2b6200e1cd774e2df24bdd68aa169966b9e3967e29187b2e3d4fffde71d01
|
Provenance
The following attestation bundles were made for filescan-0.0.5-py3-none-any.whl:
Publisher:
publish.yml on DreamSoul-AI/filescan
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
filescan-0.0.5-py3-none-any.whl -
Subject digest:
c69705417fc6c6ceeb6dd548ce29f4b42b73116ec246cd062f33b20a4ef28c1f - Sigstore transparency entry: 1018869163
- Sigstore integration time:
-
Permalink:
DreamSoul-AI/filescan@644719fd18219bdce3e53eb6ef4d4fce8af752e6 -
Branch / Tag:
refs/tags/v0.0.5 - Owner: https://github.com/DreamSoul-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@644719fd18219bdce3e53eb6ef4d4fce8af752e6 -
Trigger Event:
push
-
Statement type: