DirScribe is an open-source Python tool that exports an entire software project into a single readable text file. It generates a directory tree followed by the contents of every supported source file, making it ideal for AI coding assistants, code reviews, documentation, debugging, and sharing codebases.
It ships with three interfaces so you can use whichever fits your workflow: a graphical desktop app, an interactive terminal menu, and a scriptable CLI.
- Features
- Project Structure
- Requirements
- Installation
- Usage
- Output Format
- What Gets Included
- What Gets Ignored
- Configuration Reference
- Core API Reference
- License
- Directory tree — generates a visual
├──tree of your project structure. - Tree-only mode — export only the project directory tree without reading or including file contents using the
--tree-onlyCLI flag. - File content extraction — reads every supported text file and appends its contents below the tree.
- Smart filtering — skips build outputs, dependency folders, IDE files, and OS noise out of the box.
.gitignoreaware — loads and respects the project's own.gitignoreautomatically.- Per-file line cap — truncates files longer than a configurable limit so the output stays usable.
- Three interfaces — GUI desktop app, interactive terminal menu, and a fully scriptable CLI.
- Embeddable core — the
corepackage can be imported directly into other Python projects. - Cross-platform — runs on Windows, macOS, and Linux anywhere Python 3.10+ is available.
DirScribe/
├── core/ # All scanning and writing logic
│ ├── __init__.py # Public API surface
│ ├── file_reader.py # Extension allowlist + file reading
│ ├── tree_builder.py # Directory tree + ignore rule engine
│ └── writer.py # Orchestrates tree + contents into output
├── cli/ # Scriptable command-line interface
│ ├── __init__.py
│ └── main.py
├── cui/ # Interactive terminal menu (embeddable)
│ └── main.py
├── gui/ # Tkinter desktop application
│ ├── __init__.py
│ ├── __main__.py # `python -m gui` entrypoint
│ └── app.py
├── LICENSE
├── README.md
└── requirements.txt
-
Python 3.10 or higher
-
Tkinter — required for the GUI app and the GUI folder picker in the CLI/CUI. Tkinter ships with most Python installers. On Linux it may need to be installed separately:
# Debian / Ubuntu sudo apt install python3-tk # Fedora sudo dnf install python3-tkinter # Arch sudo pacman -S tk
No third-party Python packages are required. The standard library is sufficient.
git clone https://github.com/yourusername/dirscribe.git
cd dirscribe
pip install -e .Installing with pip install -e . makes core, cli, cui, and gui importable from anywhere without path manipulation.
If you do not want to install the package, you can run every command from the repository root directly — see each interface below.
The desktop app is the easiest way to use DirScribe. It provides a two-panel layout: controls on the left, a live preview of the generated output on the right.
Launch:
python -m guiWorkflow:
- Click the folder icon next to Project Folder and select your project root, or type the path directly.
- The Output File field auto-populates to
<project>/project_overview.txt. Change it if needed. - Click Generate. The preview pane fills with the output and the line count appears in the header.
- Use Copy output to copy the full text to the clipboard, or Open file to open the saved file in your system's default text editor.
The GUI runs the scan in a background thread so the window stays responsive on large projects.
The CUI is an interactive numbered menu intended for terminal users and for embedding DirScribe into other projects or scripts that call it as a subprocess.
Launch:
python -m cui.mainMenu:
DirScribe CUI
1) Enter project folder path
2) Open GUI folder picker
3) Quit
Choose an option [1-3]:
You can also pass flags to skip the menu entirely:
python -m cui.main --path /path/to/project --output summary.txt
python -m cui.main --gui --output summary.txtThe CLI is designed for scripting, automation, and CI pipelines. All options are passed as flags.
Basic usage:
# Scan a project and write to the default output file
python -m cli.main --path /path/to/project
# Specify a custom output file
python -m cli.main --path /path/to/project --output ~/exports/my_project.txt
# Limit each file to 200 lines instead of the default 500
python -m cli.main --path /path/to/project --max-lines 200
# Export only the directory tree
python -m cli.main --path /path/to/project --tree-only
# Open a GUI folder picker instead of typing a path
python -m cli.main --gui
# Run interactively (prompts for a path, then falls back to the GUI picker)
python -m cli.mainAll flags:
| Flag | Default | Description |
|---|---|---|
--path PATH |
(none) | Path to the project folder to scan. |
--output FILE |
project_overview.txt |
Where to write the output. Parent directories are created automatically. |
--max-lines N |
500 |
Maximum lines to read from each file before truncating with a [truncated] marker. |
--tree-only |
false |
Export only the directory tree and skip file contents. |
--gui |
false |
Open a GUI folder picker dialog instead of reading --path. |
Getting help:
python -m cli.main --helpImport DirScribe's core directly into your own Python scripts or tools.
Generate a summary string:
from pathlib import Path
from core.writer import build_project_summary
summary = build_project_summary(
Path("/path/to/project"),
tree_only=True,
)Generate and save to a file:
from pathlib import Path
from core.writer import run
run(
project_path=Path("/path/to/project"),
output_file=Path("summary.txt"),
max_lines=300, # optional, defaults to 500
tree_only=True,
)Use individual components:
from pathlib import Path
from core.tree_builder import DEFAULT_IGNORE, generate_tree, load_gitignore
from core.file_reader import extract_contents
project = Path("/path/to/project")
ignore = DEFAULT_IGNORE | load_gitignore(project)
tree = generate_tree(project, ignore)
contents = extract_contents(project, ignore, max_lines=200)
print(tree)
print(contents)When the --tree-only flag is used, only the project directory structure is exported.
my-project/
├── src/
│ ├── main.py
│ └── utils.py
├── tests/
└── README.md
No file contents are included. ...
The output is a plain UTF-8 text file with two sections:
Selected Files Directory Structure:
my-project/
├── src/
│ ├── main.py
│ └── utils.py
├── tests/
│ └── test_main.py
├── pyproject.toml
└── README.md
File Contents:
--- src/main.py ---
<contents of main.py>
--- src/utils.py ---
<contents of utils.py>
... (and so on for every included file)
Files are listed in sorted order. If a file exceeds the line limit, its content ends with:
... [truncated at 500 lines]
DirScribe reads files with the following extensions:
| Category | Extensions |
|---|---|
| Python | .py |
| JavaScript / TypeScript | .js .ts .jsx .tsx |
| Systems languages | .c .cpp .cc .cxx .h .hpp .rs .go .zig |
| JVM languages | .java .scala .kt .clj .cljs |
| Other languages | .rb .php .swift .dart .lua .pl .r .hs .ml .fs .vb .cs .ex .exs .nim .cr .d .elm .v |
| Web | .html .htm .css .scss .sass .less .vue .svelte .pug .ejs .hbs .mustache .twig .jsp .asp .aspx .erb .haml |
| Config & manifests | .json .xml .yaml .yml .toml .ini .cfg .conf .properties .env .dotenv .lock .sum .mod .gradle .pom .gitignore .gitattributes .editorconfig .prettierrc .eslintrc .babelrc |
| Shell & scripts | .sh .bash .zsh .fish .ps1 .bat .cmd .awk .sed |
| Documentation | .md .rst .adoc .tex .bib .txt |
| Data (text-based) | .csv .tsv .sql |
| Logs | .log |
Binary formats (.pdf, .docx, .epub, .db, .sqlite, .parquet, images, etc.) are intentionally excluded — they cannot be read as text.
The following are skipped automatically regardless of the project being scanned:
Directories:
| Category | Names |
|---|---|
| Version control | .git .svn .hg |
| Dependencies | node_modules vendor packages |
| Python envs | venv __pycache__ .eggs *.egg-info |
| Build outputs | dist build target out bin obj |
| IDEs | .idea .vscode .vs |
| OS artifacts | .DS_Store Thumbs.db desktop.ini |
| Logs & temp | logs tmp temp .tmp .cache |
| Test coverage | .coverage coverage .nyc_output |
| Secrets | .env .env.* secrets |
Additionally: any pattern present in the project's .gitignore file is loaded and applied on top of the defaults above.
These constants are defined in core/file_reader.py and core/tree_builder.py. You can modify them directly or override them at call time via the API.
| Constant | Location | Default | Description |
|---|---|---|---|
MAX_FILE_LINES |
file_reader.py |
500 |
Default per-file line cap. Overridable via --max-lines in the CLI or the max_lines parameter in the API. |
TEXT_FILE_EXTENSIONS |
file_reader.py |
(see above) | Set of extensions DirScribe will attempt to read. |
DEFAULT_IGNORE |
tree_builder.py |
(see above) | Set of directory names and glob patterns always excluded. |
Builds and returns the complete summary string for a project.
| Parameter | Type | Description |
|---|---|---|
project_path |
Path |
Resolved path to the project root. |
max_lines |
int |
Maximum lines per file before truncation. |
Generates the summary and writes it to output_file. Prints progress and the final line count to stdout. Creates parent directories of output_file if they do not exist.
Walks root recursively, reads every file whose extension is in TEXT_FILE_EXTENSIONS and which does not match ignore_patterns, and returns all contents concatenated with --- relative/path --- headers.
Returns True if path.suffix.lower() is in TEXT_FILE_EXTENSIONS.
Returns a multi-line string representing the directory tree rooted at root, skipping anything that matches ignore_patterns.
Parses root/.gitignore and returns all non-comment, non-empty lines as a set of pattern strings. Returns an empty set if no .gitignore exists.
Returns True if path matches any pattern in ignore_patterns via fnmatch or direct name comparison.
DirScribe is licensed under the Apache License 2.0.