Skip to main content

See your project structure clearly — a tree generator with gitignore-compatible exclusion, multi-format output, and AI-ready summaries.

Project description

tree2guide

License: MIT Python CI PyPI Downloads

Understand your project's structure in seconds.

Generate clean project trees, AI-ready summaries, and reusable documentation from any directory — all with zero dependencies.

Author: Lawrence Roble (@law4percent) Open-source, MIT licensed. Contributions, issues, and pull requests are welcome.


Why this exists

Many developers start building before they’ve had time to study every architectural principle in depth. tree2guide exists to make project structure easier to see, understand, and improve.

It provides a quick way to visualize folder hierarchies, spot signs of architectural drift, and evaluate whether a codebase is maintaining clear separation of concerns — or simply accumulating complexity over time.

What began as a tool for checking project structure quickly became useful for documentation, onboarding, PR descriptions, AI prompts, and general project analysis. The goal, however, remains the same: help developers catch structural problems early, before they become expensive to untangle.

tree2guide starts as a project structure generator, but its long-term vision is to become the foundation for project understanding — providing structured representations that can power documentation, analysis, automation, and intelligent developer tools.


Why not just use tree?

Feature tree tree2guide
Markdown output
HTML output (collapsible)
JSON output
YAML output
AI-ready summary
.tree2ignore (gitignore-style)
Python library API
Cross-platform ⚠️
Zero dependencies N/A

Example Output

Running tree2guide src --stdout:

src/
├── tree2guide/
│   ├── renderers/
│   │   ├── __init__.py
│   │   ├── html.py
│   │   ├── json_renderer.py
│   │   ├── llm.py
│   │   ├── markdown.py
│   │   ├── text.py
│   │   └── yaml_renderer.py
│   ├── __init__.py
│   ├── cli.py
│   ├── ignore.py
│   ├── llm.py
│   └── scanner.py

Running tree2guide . --llm --stdout:

============================================================
PROJECT STRUCTURE SUMMARY: tree2guide
============================================================

DETECTED STACK / LANGUAGE:
  - Python (pyproject.toml)

SIZE:
  Files      : 18
  Directories: 4

TOP-LEVEL LAYOUT:
  Directories:
    src/
    tests/
    docs/
  Files:
    pyproject.toml
    README.md
    LICENSE

NOTABLE FLAGS:
  - Tests directory present
  - GitHub Actions / workflows present
  - LICENSE file present
  - CHANGELOG present

Tested Environments

Verified on Windows 11, macOS 26.2, and Ubuntu via CI. See Tested Environments for full details and known platform-specific issues.


Philosophy

tree2guide follows a few simple principles:

  • One scan, many outputs. The filesystem is walked once; any renderer can consume the result.
  • Zero third-party dependencies. Always. pip install tree2guide is instant.
  • Human-readable first. Markdown is the default because humans read it everywhere.
  • AI-ready by design. The --llm flag produces structured output optimised for AI context windows.
  • CLI and library. Every feature available on the command line is also available as a Python API.
  • Never reads file contents. Only structure and filenames — your code stays on your machine.

Privacy

tree2guide operates entirely on your local machine.

It does:

  • ✅ Read directory structure and filenames
  • ✅ Apply ignore rules
  • ✅ Generate output locally

It does not:

  • ❌ Read file contents
  • ❌ Upload anything
  • ❌ Require an internet connection
  • ❌ Collect telemetry
  • ❌ Send data to any AI service

Installation

pip install tree2guide

Requires Python 3.9+, no other dependencies. Installs a tree2guide command directly — no python prefix needed.

Development setup (for contributors)

macOS / Linux

cd tree2guide
python3 -m venv venv
source venv/bin/activate
pip install -e ".[dev]"

Windows

cd tree2guide
python -m venv venv
venv\Scripts\activate
pip install -e ".[dev]"

Quick Start

# Markdown output (default) — writes docs_tree.md
tree2guide docs

# Plain text
tree2guide . --format text

# JSON
tree2guide . --format json

# Self-contained HTML with collapsible folders
tree2guide . --format html

# AI-ready project summary (no network call, no API key)
tree2guide . --llm

# Print to stdout instead of writing a file
tree2guide . --stdout

# Pipe to clipboard
tree2guide . --stdout | pbcopy      # macOS
tree2guide . --stdout | clip        # Windows

Command Reference

tree2guide <target_folder> [options]
Flag Description
-o, --output Output file path (default: <folder>_tree.<ext> based on format)
--exclude-file Use a specific exclude file instead of auto-detecting .tree2ignore
--title Add a heading above the tree
--no-footer Omit the author/license footer (markdown and html only)
--stdout Print to stdout instead of writing a file
--format {markdown,text,json,yaml,html,llm} Output format (default: markdown)
--llm Shorthand for --format llm — AI-friendly project summary
--max-depth N Limit recursion depth
--dirs-only Only show directories
--files-only Only show files (directories shown as scaffolding only)
--no-hidden Skip dotfiles/dotfolders without needing .tree2ignore entries
--sort {dirs-first,files-first,alpha} Sort order within each folder (default: dirs-first)

Symlinks are rendered as name -> target and never followed — avoids infinite loops.

Default output filenames

Format Output file
markdown <folder>_tree.md
text <folder>_tree.txt
json <folder>_tree.json
yaml <folder>_tree.yaml
html <folder>_tree.html
llm <folder>_llm.txt

The .tree2ignore file

The #1 rule: where it goes

.tree2ignore must sit directly inside the folder you pass as the target. Patterns are written relative to that folder — never include the target folder's name as a prefix.

# .tree2ignore lives at docs/.tree2ignore
tree2guide docs
# correct — relative to docs/
api
_drafts

# wrong — only correct if you ran: tree2guide .
docs/api
docs/_drafts

Pattern syntax (real .gitignore rules)

Pattern Meaning
build Matches a file or folder named build at any depth
build/ Same, but only matches directories
/build Matches build only at the root of the target (anchored)
*.log Matches all files ending in .log, anywhere
**/android/key.properties Matches that exact path at any depth
!keep-this Negates — re-includes something an earlier rule excluded
# comment Ignored

Patterns evaluate top to bottom — later rules override earlier ones, same as Git.

Whitelist example

Show only admin/, hide everything else:

*
!admin
!admin/**

Copy your .gitignore directly

The matching engine reimplements Git's rules exactly — copy your .gitignore into .tree2ignore and it will behave identically.


Defaults (always excluded, no setup needed)

  • .git
  • .tree2ignore
  • __pycache__
  • *.pyc
  • .DS_Store

Library API

tree2guide works as an importable library, not just a CLI:

import tree2guide
from pathlib import Path

root = Path("./my-project").resolve()
patterns = tree2guide.load_exclude_patterns(root / tree2guide.EXCLUDE_FILENAME)
matcher = tree2guide.ExcludeMatcher(patterns)

# Build the tree once
tree = tree2guide.build_node_tree(root, matcher)

# Render to any format
print(tree2guide.render_markdown(tree, title="My Project"))
print(tree2guide.render_text(tree))
print(tree2guide.render_json(tree))
print(tree2guide.render_yaml(tree))
print(tree2guide.render_html(tree, title="My Project"))
print(tree2guide.render_llm(tree, title="My Project"))

# Get the heuristic summary directly
summary = tree2guide.analyze(tree)
print(summary.detected_stack)
print(summary.file_count, summary.dir_count)
print(summary.notable_flags)

Public API surface

Name Description
build_node_tree(root, matcher, options=None) Scan filesystem → TreeNode
build_tree(root, matcher, options=None) Backward-compatible wrapper → list[str]
TreeNode Internal tree model (dataclass)
TreeOptions Scanner options (max_depth, dirs_only, sort, etc.)
ExcludeMatcher Evaluates .tree2ignore patterns
GitignoreRule Single compiled pattern rule
load_exclude_patterns(path) Parse a .tree2ignore file
analyze(node) Heuristic analysis → LlmSummary
LlmSummary Detected stack, file/dir counts, notable flags
render_markdown(tree, ...) Markdown string
render_text(tree, ...) Plain text string
render_json(tree) JSON string
render_yaml(tree) YAML string
render_html(tree, ...) Self-contained HTML string
render_llm(tree, ...) LLM-optimised plain text string

Project Structure

tree2guide/
├── .github/
│   └── workflows/
│       └── ci.yml
├── docs/                        # GitHub Pages docs site
│   ├── _config.yml
│   ├── index.md
│   ├── installation.md
│   ├── quickstart.md
│   ├── tree2ignore.md
│   ├── cli.md
│   ├── examples.md
│   ├── api.md
│   └── contributing.md
├── src/
│   └── tree2guide/
│       ├── __init__.py          # public API surface
│       ├── cli.py               # argparse + entry point
│       ├── ignore.py            # GitignoreRule, ExcludeMatcher
│       ├── llm.py               # analyze(), LlmSummary
│       ├── scanner.py           # build_node_tree(), TreeNode, TreeOptions
│       └── renderers/
│           ├── __init__.py
│           ├── html.py
│           ├── json_renderer.py
│           ├── llm.py
│           ├── markdown.py
│           ├── text.py
│           └── yaml_renderer.py
├── tests/
│   ├── test_ignore.py
│   ├── test_llm.py
│   ├── test_markdown_renderer.py
│   ├── test_renderers.py
│   └── test_scanner.py
├── CHANGELOG.md
├── LICENSE
├── README.md
└── pyproject.toml

Architecture: Scanner → Tree Model → Renderer. The scanner builds a TreeNode once; each renderer transforms the same object into a different format. Adding a new output format means writing a new renderer — no changes to the scanner or CLI needed.


Troubleshooting

"No exclude file found at .../.tree2ignore".tree2ignore must be directly inside the folder you passed as the target.

Patterns aren't excluding anything → Check for a stray prefix. If you ran tree2guide docs, write api not docs/api.

I want to exclude everything except one folder

*
!keepme
!keepme/**

--stdout produces garbled characters on Windows → Pipe directly to clipboard instead: tree2guide . --stdout | clip


Contributing

Pull requests, feature ideas, and bug reports are welcome. See CONTRIBUTING for the full guide, architecture walkthrough, and how to add a new renderer or stack signal.

Open stretch goals:

  • Browser playground (Pyodide/WASM)
  • Interactive HTML viewer from JSON output
  • --format csv — flat path list with type column
  • File size annotations
  • Character class patterns in .tree2ignore ([abc], [!abc])
  • Windows CI in the test matrix

License

MIT — see LICENSE for details.


Built and maintained by Lawrence Roble.

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

tree2guide-1.1.0.tar.gz (30.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tree2guide-1.1.0-py3-none-any.whl (25.6 kB view details)

Uploaded Python 3

File details

Details for the file tree2guide-1.1.0.tar.gz.

File metadata

  • Download URL: tree2guide-1.1.0.tar.gz
  • Upload date:
  • Size: 30.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for tree2guide-1.1.0.tar.gz
Algorithm Hash digest
SHA256 e01256e707ff97fda803630964d626dc367c1a6006e92ef7f431f948a7680249
MD5 680b43caf6684e49fc958460637d70d0
BLAKE2b-256 bb67ede0c2472245d51a7989fe52ddc29020ca4bb600fbabed82ecb5daecc8a0

See more details on using hashes here.

File details

Details for the file tree2guide-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: tree2guide-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.7

File hashes

Hashes for tree2guide-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9a860bf0eb23def1f972524b5c50c4dd9c4103780a4eeac67af0043f48cc1095
MD5 1f1078119145cde3ff49ba8f7c83d057
BLAKE2b-256 5d293cc902b44715c2cb938cbaa7a4bfb82c88ad8dbfe9319184acd219a82440

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page