# dirmd
Generate markdown documentation from directory structure. Optimized for LLM ingestion.
## Features
- Recursive directory traversal
- ASCII tree visualization (LLM-friendly, minimal token overhead)
- Full tree in every generated file — navigate from anywhere, no matter how deep you are
- Filtered files and directories stay visible in the tree with annotations (`~ ignored`, `~ tests omitted`)
- Flags provenance block: every generated file records which filters were active
- Full file contents with explicit delimiters and metadata
- Filters dotfiles, binaries, and blacklisted extensions
- Vertical slices mode: index file + root slice + one markdown per top-level directory
- Pick mode: include specific individual files alongside the slices
- Append mode for single files or directories
- Force overwrite of existing output files
- Configurable depth, file size limits, ignore patterns
- Optional upload to Proton Drive after generating output
- Skip frontend files (`.html`, `.css`, `.js`, etc.)
- Frontend only mode (include only frontend files and `README.md`)
- Omit test files and inline test blocks (Go, Java, Rust)
## Installation
Only for linux.
Download binary from release page or install with go
```bash
go install git.flo.fo/FLO/dirmd@latest
```
## Use with Git Post Hook
combine with git post hook to sync with proton drive on each commit
add something like this in ./.git/hooks/post-commit
```bash
#!/bin/bash
set -euo pipefail
if ! command -v dirmd &>/dev/null; then
exit 0
fi
REPO_ROOT=$(git rev-parse --show-toplevel)
REPO_NAME=$(basename "$REPO_ROOT")
dirmd -o "/tmp/${REPO_NAME}" "$REPO_ROOT" -f --vertical-slices --proton-drive
```
## Build
go build -o dirmd .
## Usage
# Create new documentation
dirmd -o output.md ~/repos/myproject
# Overwrite existing output file
dirmd -o output.md ~/repos/myproject -f
# Append a single file
dirmd -a -i README.md -o existing.md
# Append another directory
dirmd -a ~/repos/anotherproject -o existing.md
# Generate with vertical slices
dirmd -o output.md ~/repos/myproject --vertical-slices
# Skip frontend files (.html, .css, .js, etc.)
dirmd -o output.md ~/repos/myproject --skip-frontend
# Frontend only (include only frontend files and README.md)
dirmd -o output.md ~/repos/myproject --frontend-only
# Omit test files and inline test blocks
# Go: excludes *_test.go
# Java: excludes *Test.java, *Tests.java, src/test/java/*
# Rust: strips #[cfg(test)] mod tests { ... } blocks
dirmd -o output.md ~/repos/myproject --omit-test
# Combine filters
dirmd -o output.md ~/repos/myproject --frontend-only --omit-test
# Pick specific files alongside vertical slices
dirmd -o output.md ~/repos/myproject --vertical-slices \
--pick common/src/config.rs --pick init/src/main.rs
# Same, with a compact breadcrumb instead of the full tree in pick files
dirmd -o output.md ~/repos/myproject --vertical-slices \
--pick common/src/config.rs --small-tree
# Generate and upload to Proton Drive (default: /my-files/md/)
dirmd -o output.md ~/repos/myproject --proton-drive
# Generate and upload to a specific remote path
dirmd -o output.md ~/repos/myproject --proton-drive --drive-path /my-files/docs/api.md
## Test File Omission
The `--omit-test` flag removes test files and inline test blocks to reduce token overhead in LLM context windows. Behavior varies by language:
| Language | Exclusion Strategy | What Gets Removed |
|----------|-------------------|-------------------|
| **Go** | File exclusion | All `*_test.go` files |
| **Java** | File exclusion | `*Test.java`, `*Tests.java`, files under `src/test/java/` |
| **Rust** | Content stripping | Entire `#[cfg(test)] mod tests { ... }` blocks removed from `.rs` files |
The Rust stripping works by detecting the `#[cfg(test)]` attribute, then tracking brace depth until the module closes. Nested braces in string literals may occasionally throw off the count, but this is acceptable for RAG use cases.
Omitted test files and directories remain visible in the directory tree with a `~ tests omitted (--omit-test)` annotation, so consumers of the snapshot know they exist and can request them.
## Frontend Filtering
Two complementary flags control frontend file inclusion:
| Flag | Effect |
|------|--------|
| `--skip-frontend` | Exclude frontend files, keep everything else |
| `--frontend-only` | Include only frontend files and `README.md`, exclude everything else |
Frontend extensions covered:
| Type | Extensions |
|------|------------|
| Templates | `.html`, `.htm`, `.gohtml`, `.tmpl` |
| Stylesheets | `.css`, `.scss`, `.sass`, `.less` |
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` |
| TypeScript | `.ts`, `.tsx` |
| Frameworks | `.vue`, `.svelte` |
`--skip-frontend` and `--frontend-only` are mutually exclusive. Both can be combined with `--omit-test`.
## Vertical Slices Mode
When `--vertical-slices` is passed, dirmd splits output into multiple files instead of one monolithic document:
- **Index file** (`index_.md`): timestamp, commit, `.dirmd` instructions (if `--instructions`), flags block, full directory tree with annotations and cross-references to slice files, and the vertical slices index table. Deliberately thin — no file contents. This is the always-load document.
- **Root slice** (`root_.md`): contents of all root-level files (README, Cargo.toml, justfile, etc.). Selectable like any other slice.
- **Slice files** (`/_.md`): one per top-level directory, placed in a subdirectory named after it. Each carries the full project tree (not just its subtree), a back-reference to the root document, the flags block, and full recursive file contents for that directory.
Every generated file carries the **full project tree**, so navigation works no matter which file is loaded. Directories excluded via `--ignore` appear as a single collapsed node annotated `~ ignored (--ignore)` — never recursed into — and files filtered by `--omit-test`, `--omit-md`, or frontend flags appear annotated instead of vanishing. The tree tells the consumer what exists but was left out.
This mode cannot be combined with `--append` or `--input-file`.
Example output with `dirmd -o docs ~/repos/myproject --vertical-slices`:
docs/
├── index_myproject.md ← index: metadata + tree + slices table
├── root_myproject.md ← root files (README, etc.)
├── cmd/
│ ├── cmd_myproject.md ← slice: full tree + contents of cmd/
│ └── main.rs.md ← pick file (only if --pick was used)
└── internal/
└── internal_myproject.md
## Pick Mode
`--pick ` selects individual files for inclusion in a sliced run. Repeatable. Requires `--vertical-slices`.
- Picks are written to `