Logical Folders
Virtual directory tree from flat filenames for VSCode.
Files stay flat on disk — the hierarchy is purely visual. Bridges the gap between agent-friendly flat structures and human-readable project navigation.
Screenshots


Why
AI agents prefer flat directories: fewer hops, simpler file access, no path ambiguity. But humans staring at 500 flat files in one folder lose their minds.
Logical Folders splits filenames on a configurable separator and displays them as a tree. The physical files never move.
On disk: In the tree:
auth_login_handler.ts auth/
auth_login_session.ts login/
utils_helpers.ts handler.ts
config_env.ts session.ts
utils/
helpers.ts
config/
env.ts
Install
From source (development)
cd vscode-logical-folders
npm install
npm run compile
Then press F5 in VSCode to launch an Extension Development Host.
From VSIX (distribution)
npm run package # produces .vsix file
# Install in VSCode: Extensions → ⋯ → Install from VSIX
Configuration
Open Settings → search "Logical Folders".
| Setting |
Default |
Description |
logicalFolders.separator |
_ |
Separator to split filenames. Common: _, __, -, ., :: |
logicalFolders.exclude |
["**/node_modules/**", "**/.git/**", ...] |
Glob patterns to exclude |
logicalFolders.maxFiles |
10000 |
Max files to scan (performance guard) |
Separator reference
| Separator |
Flat file |
Logical tree |
_ (default) |
auth_login_handler.ts |
auth/ > login/ > handler.ts |
__ |
auth__login__handler.ts |
auth/ > login/ > handler.ts |
- |
auth-login-handler.ts |
auth/ > login/ > handler.ts |
. |
auth.login.handler.ts |
auth/ > login/ > handler.ts |
:: |
auth::login::handler.ts |
auth/ > login/ > handler.ts |
_ is the default because it's the most common convention in AI-generated codebases. Any custom string works — just set logicalFolders.separator to whatever your project uses.
Operations
| Action |
How |
Effect on disk |
| New File |
Right-click folder → "New File" |
Creates flat file with joined name |
| Rename |
Right-click file → "Rename" |
Renames the flat file |
| Delete |
Right-click file → "Delete" |
Deletes the flat file |
| Copy Path |
Right-click file → "Copy Path" |
Copies physical path to clipboard |
| Reveal in Explorer |
Right-click file → "Reveal" |
Opens in OS file manager |
| Refresh |
View toolbar button |
Rebuilds the tree |
Creating a file
Right-click the auth/login/ folder → "New File" → type handler.ts:
- Logical segments:
["auth", "login", "handler.ts"]
- Flat name:
auth_login_handler.ts (segments joined with _)
- Created on disk in the same physical directory as the other files in that logical folder
How it works
- Scans workspace files via
vscode.workspace.findFiles (respecting exclude patterns)
- For each file: strips the extension, splits the basename on the separator, reattaches the extension to the last segment
- Builds a virtual tree from the resulting path segments
- Physical directories pass through as-is — only filenames get split
- File watcher debounces changes at 500ms and rebuilds the tree
Edge cases
- Dotfiles (
.gitignore, .env) are never split — shown as-is
- No separator in filename → shown as-is, no virtual folders created
- Physical + logical merge → if
src/ is a real directory and src_auth.ts is a flat file, both appear under src/ in the tree
- File extension ambiguity with
. separator → path.extname() strips the last extension first, so auth.login.handler.ts correctly splits to auth/ > login/ > handler.ts. But auth.login.handler.test.ts → auth/ > login/ > handler/ > test.ts (the .test part becomes a virtual folder). Use _ or - to avoid this entirely.
License
MIT
If this saves you time, buy me a coffee ☕