An intelligent tool to map, analyze, and compile project source code for LLM context.
Project description
An intelligent tool to map, analyze, and compile project source code into a single, context-optimized text file for Large Language Models (LLMs), available as both a powerful CLI and a flexible Python library.
📖 Table of Contents
- 🤔 Why ProjectScriber?
- ✨ Key Features
- 🚀 Quick Start
- 💾 Installation
- 🖥️ Command-Line Usage
- 📚 Library Usage (API)
- ⚙️ Configuration
- 🤝 Contributing & Development
🤔 Why ProjectScriber?
When working with Large Language Models, providing the full context of a codebase is crucial for getting accurate
analysis, documentation, or refactoring suggestions.
Manually copying and pasting files is tedious, error-prone, and
unsustainable for projects of any real size.
ProjectScriber automates this entire process. It intelligently scans your project, respects your existing
.gitignore rules, applies custom filters, and bundles all relevant code into a single, clean, and readable format
perfect for any AI model.
📁 Your Codebase → 📦 ProjectScriber → 📋 LLM-Ready Context
✨ Key Features
| Feature | Description |
|---|---|
| 🌳 Smart Project Mapping | Generates a clear and intuitive tree view of your project's structure. |
| ⚙️ Intelligent Filtering | Automatically respects .gitignore and supports custom include, exclude, and hidden patterns. You can even define language-specific exclusions! |
| 📊 In-depth Code Analysis | Provides a summary with total file size, estimated token count (using cl100k_base), and a language breakdown. |
| 🐍 Flexible Python Library | Import and use the Scriber class directly in your Python projects for full programmatic control. |
| ✨ Interactive CLI | A simple scriber init command walks you through creating a configuration file for your project. |
| 📋 Clipboard Integration | Use the --copy flag to automatically send the entire output to your clipboard, ready for pasting. |
| 💨 Lightweight & Fast | The default installation is minimal, and file analysis is multi-threaded for improved performance. |
🚀 Quick Start
Install the package directly from the Python Package Index (PyPI).
-
Install Scriber:
pip install project-scriber
-
Navigate to your project's root and run:
scriber
-
That's it! A
scriber_output.txtfile is now in your directory. It will look something like this:=== Mapped Folder Structure === ProjectScriber ├── .github │ └── workflows │ ├── ci.yml │ └── release.yml ├── README.md └── src └── scriber ├── __init__.py └── core.py --- File: .github/workflows/ci.yml Size: 512 bytes --- ```yaml name: Continuous Integration on: push: branches: - develop jobs: run_tests: ...
💾 Installation
You have two options for installation.
Standard Installation
This provides the core functionality with a minimal, text-based interface.
pip install project-scriber
With Rich UI ✨
For an enhanced terminal experience with colors, tables, and progress bars, install the rich extra:
pip install project-scriber[rich]
🖥️ Command-Line Usage
Basic Commands
- Scan the current directory:
scriber
- Scan a different directory:
scriber /path/to/your/project - Interactive Setup: Create a configuration file (
.scriber.jsonorpyproject.toml) for your project.scriber init
CLI Options
| Option | Alias | Description |
|---|---|---|
root_path |
The project directory to map. Defaults to the current directory. | |
--output [file] |
-o |
Set a custom name for the output file. |
--config [path] |
Path to a custom config file (e.g., a pyproject.toml in a monorepo). |
|
--copy |
-c |
Copy the final output to the clipboard. |
--tree-only |
Generate only the file tree structure, without any file content. | |
--version |
-v |
Show the installed version of ProjectScriber. |
--help |
-h |
Display the help message. |
Advanced Example
Scan another project, save the output to custom_map.txt, and copy the result to the clipboard in one go:
scriber ../my-other-project --output custom_map.txt --copy
📚 Library Usage (API)
Use ProjectScriber directly in your Python code for maximum flexibility and automation.
Basic Example: Get Context as a String
Initialize Scriber, and it will automatically handle mapping and analysis.
from pathlib import Path
from scriber import Scriber # The class is exposed for direct import
# 1. Initialize Scriber for the current directory
scriber = Scriber(root_path=Path('.'))
# 2. Get the complete output directly as a string
project_context = scriber.get_output_as_string()
# 3. Use the context for your application
print(f"Generated context of {len(project_context)} characters.")
# 4. Access the calculated statistics
stats = scriber.get_stats()
print(f"Total files mapped: {stats['total_files']}")
print(f"Estimated tokens: {stats['total_tokens']:,}")
Advanced Configuration via Dictionary
Bypass all on-disk configuration files by passing a dictionary directly to the constructor. This is perfect for dynamic or controlled environments.
from pathlib import Path
from scriber import Scriber
my_config = {
"use_gitignore": True,
"exclude": ["node_modules/", "dist/"],
"include": ["*.py", "*.js", "Dockerfile"],
"hidden": ["poetry.lock", "package-lock.json"],
"exclude_map": {
"global": ["*.log", "temp.*"],
"python": ["*_test.py", "conftest.py"],
"javascript": ["*.min.js"]
}
}
scriber = Scriber(root_path=Path('/path/to/your/project'), config=my_config)
project_context = scriber.get_output_as_string()
print(project_context)
Scanning Multiple Directories
You can pass a list of paths to the Scriber constructor to map multiple directories into a single output. The first path in the list is treated as the "primary root" for loading configurations (.gitignore, pyproject.toml, etc.).
from pathlib import Path
from scriber import Scriber
# Example: Scan both a 'backend' and a 'frontend' directory
backend_path = Path('./my_backend_project')
frontend_path = Path('./my_frontend_project')
# Create dummy directories and files for the example
backend_path.mkdir(exist_ok=True)
(backend_path / "main.py").write_text("print('hello from backend')")
frontend_path.mkdir(exist_ok=True)
(frontend_path / "app.js").write_text("console.log('hello from frontend')")
# Initialize with a list of paths. `backend_path` is the primary root.
scriber = Scriber(root_path=[backend_path, frontend_path])
# Get the combined context as a single string
combined_context = scriber.get_output_as_string()
print(combined_context)
# The output will contain two separate trees and file content blocks,
# with file paths prefixed by their root folder's name.
Accessing Intermediate Data
You can also access the generated file tree and the list of mapped files before the final output is compiled.
from pathlib import Path
from scriber import Scriber
scriber = Scriber(root_path=Path('.'))
# Get just the formatted file tree
tree_representation = scriber.get_tree()
print("--- Project Tree ---")
print(tree_representation)
# Get a list of all mapped file paths
print("\n--- Mapped Files ---")
file_paths = scriber.get_mapped_files()
for path in file_paths:
print(path.relative_to(scriber.primary_root))
Practical Example: Preparing Context for an LLM
Here's a small function demonstrating how you can use ProjectScriber to generate a complete, well-formatted prompt for an LLM.
from pathlib import Path
from scriber import Scriber
def get_llm_context(project_path: Path, task: str) -> str:
'''
Generates a complete project context string ready for an LLM.
Args:
project_path: The root directory of the project.
task: The specific task you want the LLM to perform.
Returns:
A formatted string to be used as a prompt for an LLM.
'''
# Initialize Scriber and get the project map
scriber = Scriber(root_path=project_path)
project_map = scriber.get_output_as_string()
# Get some stats for the context header
stats = scriber.get_stats()
token_count = stats.get("total_tokens", 0)
# Assemble the final prompt for the LLM
prompt = (
f"Please perform the following task: {task}\n\n"
f"Here is the full context of the project codebase. "
f"It includes a file tree and the content of all relevant files.\n"
f"Estimated Token Count: {token_count:,}\n\n"
"--- PROJECT CONTEXT BEGINS ---\n"
f"{project_map}"
"--- PROJECT CONTEXT ENDS ---"
)
return prompt
# --- Usage ---
if __name__ == "__main__":
my_project_path = Path('.')
user_task = "Analyze the code for potential bugs and suggest improvements."
llm_prompt = get_llm_context(my_project_path, user_task)
print(llm_prompt)
# Now you can send `llm_prompt` to your favorite LLM API.
⚙️ Configuration
ProjectScriber is configured via a file in your project's root. It searches for configurations in the following order of precedence:
- Direct
configdictionary (Library mode only). --config [path]flag (CLI mode only)..scriber.jsonin the project root.[tool.scriber]section inpyproject.toml.- Default Config: If no file is found, a default
.scriber.jsonis created on the first run.
Configuration Keys
| Key | Type | Default | Description |
|---|---|---|---|
use_gitignore |
boolean | true |
If true, all patterns in the .gitignore file will be used for exclusion. |
exclude |
list | See core.py |
A list of file/folder names or patterns to exclude globally (e.g., "node_modules", "*.log"). |
include |
list | [] |
If not empty, only files matching these patterns will be included. |
hidden |
list | [] |
Files matching these patterns will appear in the tree but their content will be replaced with a placeholder. Useful for large lock files. |
exclude_map |
object | {} |
A dictionary for language-specific and global exclusion patterns. See example below. |
output |
string | "scriber_output.txt" |
The default name for the output file. |
Example pyproject.toml Configuration
Here is an example of a well-configured [tool.scriber] section in your pyproject.toml file:
[tool.scriber]
# Respect the project's .gitignore file
use_gitignore = true
# Globally exclude common folders and file types
exclude = [
"__pycache__",
"node_modules",
"dist",
"build",
".venv",
]
# Only include files with these extensions
include = [
"*.py",
"*.js",
"*.css",
"*.md"
]
# Show these files in the tree, but hide their content
hidden = [
"poetry.lock"
]
# Language-specific and global exclusion rules
[tool.scriber.exclude_map]
# Exclude these patterns from all files
global = ["*.log", "*.tmp"]
# In Python files, exclude tests and setup scripts
python = ["*_test.py", "setup.py"]
# In JavaScript files, exclude spec files
javascript = ["*.spec.js"]
💡 Note on Excluding Directories: For patterns that should only match directories (e.g.,
build/), it's best practice to use your.gitignorefile, which has more advanced pattern matching that ProjectScriber understands.
🤝 Contributing & Development
Contributions are welcome! If you have a suggestion or find a bug, please open an issue to discuss it first.
Development Setup
-
Prerequisites:
- Python 3.10 or higher.
-
Clone the Repository:
git clone https://github.com/SunneV/ProjectScriber.git
-
Navigate to the Project Directory:
cd ProjectScriber
-
Install Dependencies: Choose one of the following methods to install the project in editable mode with all development dependencies.
-
Using
pip:pip install -e .[dev]
-
Using
uv:uv sync --all-packages --extra dev
-
Running Tests
Run the test suite using pytest:
pytest
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 project_scriber-1.1.0.tar.gz.
File metadata
- Download URL: project_scriber-1.1.0.tar.gz
- Upload date:
- Size: 33.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
767e37bb7be6d7e7141c9f7fe6be1a6e6b70ce5d3c9b87c2114f35e019912381
|
|
| MD5 |
200dc05c757ece8578dc7bbb2ca66c1d
|
|
| BLAKE2b-256 |
3d1137e0c8a78a6d2dba6eed19cd1d0374d73912cb5a388a265eb4b6d22830b3
|
File details
Details for the file project_scriber-1.1.0-py3-none-any.whl.
File metadata
- Download URL: project_scriber-1.1.0-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.8.17
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f09102afde4ddd4057e661e4dde7b9c79bf562ade4b1cd49d41cc1e0d9772cee
|
|
| MD5 |
8ae27e67762073a879a44b8369cb6089
|
|
| BLAKE2b-256 |
4144848d1632d60e08d54402f5ee53cbef54e162fcef964dedd4c16b7a362372
|