Skip to main content

Translate between ASCII 'tree' text, JSON/YAML tree specs, and real directory structures.

Project description

🪵 fs-tree-spec (tree_adapter)

Translate between ASCII “tree” text, JSON/YAML tree specs, and real directory structures.
This tiny Python utility helps you describe, version, and reproduce directory layouts in a portable, human-readable way.


✨ Features

  • Parse ASCII "tree" text (like tree command output) → nested Python structure
  • Scan existing directories (--from-fs) → generate tree specs
  • Serialize / deserialize JSON and YAML tree specs
  • Render a Unicode tree from structured data
  • Validate naming rules (strict enforcement, no invalid characters)
  • Compute a dry-run plan (--plan) of what would be created
  • Apply (--apply) to actually build the filesystem
  • Smart defaults: ignores __pycache__, .git, node_modules, etc.
  • Optional YAML support via pip install fs-tree-spec[yaml]

🧩 Installation

pip install fs-tree-spec
# or with YAML support:
pip install fs-tree-spec[yaml]

After installation, the CLI command fs-tree-spec becomes available.


🧭 Usage (CLI)

Basic

# Plan creation from an ASCII spec
fs-tree-spec --from-ascii second_brain_tree.txt --root ./second-brain --plan

# Apply (actually create directories/files)
fs-tree-spec --from-ascii second_brain_tree.txt --root ./second-brain --apply

# Print as normalized ASCII and JSON
fs-tree-spec --from-ascii second_brain_tree.txt --print-tree --print-json

From JSON or YAML

fs-tree-spec --from-json my_tree.json --plan
fs-tree-spec --from-yaml my_tree.yaml --apply

From Existing Directory

Generate a tree spec by scanning an existing directory structure:

# Generate ASCII tree from current directory
fs-tree-spec --from-fs . --print-tree

# Generate JSON spec from a project
fs-tree-spec --from-fs ./my-project --print-json

# Generate YAML spec
fs-tree-spec --from-fs ./src --print-yaml

# Exclude root directory name from output
fs-tree-spec --from-fs ./my-project --print-tree --no-root-label

Default ignore patterns: __pycache__, *.pyc, .git, .venv, node_modules, .pytest_cache, .mypy_cache, .ruff_cache, *.egg-info, .DS_Store

# Custom ignore patterns
fs-tree-spec --from-fs . --print-tree --ignore "*.log" "tmp/" "build/"

# Disable default ignores (include everything)
fs-tree-spec --from-fs . --print-tree --ignore

📜 Example Input

ASCII tree text

second-brain/
├─ .env                      # API keys + config (not committed)
├─ pyproject.toml
├─ README.md
├─ data/
│  ├─ raw/
│  │  └─ apple_notes_export/
│  ├─ attachments/
│  │  └─ ...
│  ├─ processed/
│  │  ├─ notes.jsonl
│  │  ├─ attachments.jsonl
│  │  └─ urls.jsonl
└─ notebooks/
   └─ exploration.ipynb

Equivalent JSON

{
  "second-brain": {
    ".env": null,
    "pyproject.toml": null,
    "README.md": null,
    "data": {
      "raw": { "apple_notes_export": {} },
      "attachments": {},
      "processed": {
        "notes.jsonl": null,
        "attachments.jsonl": null,
        "urls.jsonl": null
      }
    },
    "notebooks": {
      "exploration.ipynb": null
    }
  }
}

Equivalent YAML

second-brain:
  .env: null
  pyproject.toml: null
  README.md: null
  data:
    raw:
      apple_notes_export: {}
    attachments: {}
    processed:
      notes.jsonl: null
      attachments.jsonl: null
      urls.jsonl: null
  notebooks:
    exploration.ipynb: null

🧠 Naming Rules (Enforced)

  1. Names are single path segments (no / or \).
  2. Names must be non-empty after trimming.
  3. Names cannot be ., .., ..., or .
  4. Names cannot contain tree/box characters: `├└│─|+```
  5. Inline comments begin with " #" and are ignored.
  6. "..." and "…" lines are treated as placeholders only.
  7. Conflicts between file vs. directory at same level raise an error.

🧪 Python API Example

Create from spec

from tree_adapter import parse_ascii_tree, plan_fs_from_tree, create_fs_from_tree

ascii_spec = Path("second_brain_tree.txt").read_text()
tree = parse_ascii_tree(ascii_spec)

# Inspect
print(plan_fs_from_tree(tree, "./second-brain"))

# Create directories and files
create_fs_from_tree(tree, "./second-brain", create_files=True)

Generate from existing directory

from tree_adapter import from_fs, to_ascii_tree, to_json, to_yaml

# Scan a directory
tree = from_fs("./my-project", include_root_label=True)

# Convert to different formats
print(to_ascii_tree(tree))
print(to_json(tree))
print(to_yaml(tree))  # requires PyYAML

# Custom ignore patterns
tree = from_fs("./src", ignore_patterns=["*.log", "tmp/"])

# Include everything (no filtering)
tree = from_fs("./src", ignore_patterns=[])

🛠️ Development

# Clone and set up development environment
git clone https://github.com/swoodeng/fs-tree-spec.git
cd fs-tree-spec

# Install dependencies with uv
uv sync --all-extras --dev

# Run tests
uv run pytest

# Run linters
uv run ruff check .
uv run black --check .
uv run mypy tree_adapter.py

Run locally:

uv run fs-tree-spec --from-ascii second_brain_tree.txt --plan

📦 Packaging

This project uses PEP 621 metadata and can be built with:

python -m build

⚖️ License

MIT License © 2025 Stephen Wood


💡 Inspiration

  • tree command output formatting
  • JSON/YAML for reproducible data models
  • Cross-tool “infrastructure as text” patterns

🪴 Example Workflows

Spec → Filesystem

  1. Write a tree spec in a README.md for documentation.
  2. Extract the snippet and feed it to fs-tree-spec --from-ascii.
  3. Plan or apply to generate the directory structure for new projects.
  4. Optionally export the same spec to JSON or YAML for automation.

Filesystem → Spec

  1. Scan an existing project with fs-tree-spec --from-fs ./project --print-tree.
  2. Document by copying the output into your README.
  3. Export to JSON/YAML for programmatic use or version control.
  4. Recreate the structure elsewhere with --apply.

"Describe once. Recreate anywhere."

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

fs_tree_spec-0.2.0.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

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

fs_tree_spec-0.2.0-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file fs_tree_spec-0.2.0.tar.gz.

File metadata

  • Download URL: fs_tree_spec-0.2.0.tar.gz
  • Upload date:
  • Size: 11.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for fs_tree_spec-0.2.0.tar.gz
Algorithm Hash digest
SHA256 5c5cf56f938ee3c53665ff049920f0e183846268f9cea415b2f7a5698911d9af
MD5 e945a435980f4ec6e7594a27a867b5a7
BLAKE2b-256 fb518e1e1e3bebed5ca14fe9f854d473b71b2cc5b1821a4708de207b0036f9c0

See more details on using hashes here.

File details

Details for the file fs_tree_spec-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: fs_tree_spec-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 11.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for fs_tree_spec-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1e34af3178bbf021207768bfb456df6e14d2cbfaeb4478eea5f0aadf1502d63d
MD5 f96aa4f88825fac7c9d9748833115403
BLAKE2b-256 ef8b2edb6a17860477e7129591acf92a8ff45d6ed9cdc1c429b66d753c77da38

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