Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Directory Structure

Requiem is flexible about how you organize requirements on disk. This chapter explains directory organization options and best practices.

Directory Structure Modes

Requiem supports two fundamental modes for organizing requirements, controlled by the subfolders_are_namespaces configuration option:

1. Filename-Based Mode (Default)

Configuration: subfolders_are_namespaces = false (or omitted)

In this mode, the full HRID is encoded in the filename, and directory structure is purely organizational:

my-requirements/
├── USR-001.md              → HRID: USR-001
├── SYS-002.md              → HRID: SYS-002
├── auth-USR-003.md         → HRID: auth-USR-003
└── custom/folder/
    └── system-REQ-004.md   → HRID: system-REQ-004

Use when: You want maximum flexibility in folder organization without affecting requirement namespaces.

2. Path-Based Mode

Configuration: subfolders_are_namespaces = true

In this mode, subfolders encode the namespace, and the filename contains only KIND-ID:

my-requirements/
├── REQ-001.md              → HRID: REQ-001 (no namespace)
├── system/
│   └── auth/
│       ├── REQ-002.md      → HRID: system-auth-REQ-002
│       └── USR/
│           └── 003.md      → HRID: system-auth-USR-003 (KIND from parent)

The filename format is automatically inferred:

  • Numeric only (e.g., 003.md) → KIND taken from parent folder
  • KIND-ID (e.g., REQ-002.md) → KIND and ID from filename

Use when: You want folder structure to directly mirror requirement namespaces.

Basic Structure

At minimum, you need a directory containing requirement markdown files:

my-requirements/
├── USR-001.md
├── USR-002.md
├── SYS-001.md
└── SYS-002.md

That's it! No initialization or hidden directories required.

With Configuration

Add a config.toml for project-specific settings:

my-requirements/
├── config.toml      ← Configuration
├── USR-001.md
├── USR-002.md
├── SYS-001.md
└── SYS-002.md

The configuration file is optional but recommended for projects with specific needs.

Using Subdirectories

Requiem recursively searches subdirectories, enabling hierarchical organization.

Organize by Requirement Kind

requirements/
├── config.toml
├── user/
│   ├── USR-001.md
│   ├── USR-002.md
│   └── USR-003.md
├── system/
│   ├── SYS-001.md
│   ├── SYS-002.md
│   └── SYS-003.md
└── test/
    ├── TST-001.md
    └── TST-002.md

Advantages:

  • Clear separation of requirement levels
  • Easy to navigate
  • Natural for large projects

Note: In filename-based mode (default), directory names don't affect requirement behavior. user/USR-001.md and system/USR-001.md would create a filename conflict (both have HRID USR-001), so use different kinds. In path-based mode, these would have different HRIDs: user-USR-001 and system-USR-001.

Organize by Feature

requirements/
├── config.toml
├── authentication/
│   ├── USR-001.md   # User login
│   ├── SYS-001.md   # Auth service
│   └── TST-001.md   # Auth tests
├── payment/
│   ├── USR-002.md   # Payment processing
│   ├── SYS-002.md   # Payment gateway
│   └── TST-002.md   # Payment tests
└── reporting/
    ├── USR-003.md   # Report generation
    └── SYS-003.md   # Report engine

Advantages:

  • Groups related requirements
  • Mirrors feature structure
  • Good for feature-based development

Organize by Component

requirements/
├── config.toml
├── frontend/
│   ├── WEB-USR-001.md
│   ├── WEB-SYS-001.md
│   ├── MOBILE-USR-001.md
│   └── MOBILE-SYS-001.md
└── backend/
    ├── API-SYS-001.md
    ├── DB-SYS-001.md
    └── CACHE-SYS-001.md

Advantages:

  • Aligns with system architecture
  • Clear ownership boundaries
  • Natural for microservices

Note: Consider using namespaces in HRIDs (e.g., WEB-USR-001) to avoid conflicts.

Deep Hierarchies

Requiem supports arbitrary nesting:

requirements/
├── config.toml
└── product/
    ├── core/
    │   ├── auth/
    │   │   ├── USR-001.md
    │   │   └── SYS-001.md
    │   └── data/
    │       ├── USR-002.md
    │       └── SYS-002.md
    └── plugins/
        ├── export/
        │   └── USR-003.md
        └── import/
            └── USR-004.md

Caution: Deep hierarchies can be harder to navigate. Consider flat or shallow structures unless your project naturally requires depth.

Flat vs. Hierarchical

Flat Structure

requirements/
├── config.toml
├── USR-001.md
├── USR-002.md
├── ...
├── USR-050.md
├── SYS-001.md
├── SYS-002.md
├── ...
└── SYS-100.md

Advantages:

  • Simple and straightforward
  • Easy to understand
  • Works well for small/medium projects (< 100 requirements)

Disadvantages:

  • Directory listing can become unwieldy with many requirements
  • Harder to navigate in file browser with 100+ files

Best for: Small to medium projects, single-component systems.

Hierarchical Structure

requirements/
├── config.toml
├── user-requirements/
│   └── (50 files)
├── system-requirements/
│   └── (100 files)
└── test-requirements/
    └── (150 files)

Advantages:

  • Scalable to large projects (1000+ requirements)
  • Natural organization
  • Easier to navigate

Disadvantages:

  • Slightly more complex
  • Must decide on hierarchy scheme

Best for: Large projects, multi-component systems.

Best Practices

1. Start Flat, Refactor When Needed

Begin with a flat structure:

requirements/
├── config.toml
├── USR-001.md
└── SYS-001.md

Introduce subdirectories when you have 50+ requirements or natural groupings emerge.

2. Use Consistent Naming

If using subdirectories, name them consistently:

requirements/
├── 1-user-requirements/
├── 2-system-requirements/
├── 3-software-requirements/
└── 4-test-requirements/

Or:

requirements/
├── user/
├── system/
├── software/
└── test/

Avoid: Mixing naming schemes (user_reqs/, system-requirements/, Tests/).

3. Keep Shallow (2-3 Levels Max)

Prefer:

requirements/
└── user/
    └── USR-001.md

Over:

requirements/
└── level1/
    └── level2/
        └── level3/
            └── level4/
                └── USR-001.md

Deep hierarchies are hard to navigate and remember.

4. Align with Team Structure

Organize to match how your team works:

Team by feature:

requirements/
├── login-team/
├── payment-team/
└── reporting-team/

Team by layer:

requirements/
├── product-managers/  (USR requirements)
├── architects/        (SYS requirements)
└── developers/        (SWR requirements)

5. Don't Encode Information in Paths

Bad:

requirements/
└── high-priority/
    └── USR-001.md  # Priority encoded in directory

Good:

requirements/
└── USR-001.md

# USR-001.md content:
---
tags:
- high-priority
---
The requirement text...

Use tags or content for metadata, not directory structure. Directories are for organization only.

Special Cases

Mixed Content (Requirements + Documentation)

If requirements live alongside other documentation:

docs/
├── config.toml
├── introduction.md      ← Not a requirement
├── architecture.md      ← Not a requirement
├── requirements/
│   ├── USR-001.md      ← Requirement
│   └── SYS-001.md      ← Requirement
└── user-guide.md        ← Not a requirement

Set allow_unrecognised = true in config.toml to allow non-requirement markdown files.

Integration with MdBook

MdBook projects:

docs/
├── book.toml           ← MdBook config
├── src/
│   ├── SUMMARY.md      ← MdBook table of contents
│   ├── chapter1.md     ← Documentation
│   ├── USR-001.md      ← Requirement (can be in SUMMARY.md)
│   └── USR-002.md      ← Requirement
└── config.toml         ← Requiem config (allow_unrecognised = true)

See Integration > Using with MdBook for details.

Integration with Sphinx

Sphinx projects:

docs/
├── conf.py             ← Sphinx config
├── index.md
├── requirements/
│   ├── config.toml     ← Requiem config
│   ├── USR-001.md      ← Requirement
│   └── SYS-001.md      ← Requirement
└── other-content.md

See Integration > Using with Sphinx for details.

Monorepo Structure

Large monorepos with multiple products:

monorepo/
├── products/
│   ├── web-app/
│   │   └── requirements/
│   │       ├── config.toml
│   │       └── WEB-USR-001.md
│   └── mobile-app/
│       └── requirements/
│           ├── config.toml
│           └── MOBILE-USR-001.md
└── shared/
    └── requirements/
        ├── config.toml
        └── CORE-SYS-001.md

Each product/component has its own independent requirements directory with separate config.toml.

File System Considerations

Case Sensitivity

Linux/Mac: Filenames are case-sensitive

  • USR-001.md and usr-001.md are different files
  • Requiem only recognizes USR-001.md (uppercase HRID)

Windows: Filenames are case-insensitive

  • USR-001.md and usr-001.md refer to the same file
  • Use consistent casing to avoid issues

Recommendation: Always use uppercase HRIDs to avoid cross-platform issues.

Requiem follows symbolic links when scanning for requirements:

requirements/
├── current -> v2.0/     ← Symlink
├── v1.0/
│   └── USR-001.md
└── v2.0/
    └── USR-001.md

Caution: Ensure symlinks don't create cycles or duplicate requirements.

Hidden Files and Directories

Files and directories starting with . are typically ignored by Requiem (following standard Unix convention):

requirements/
├── .git/               ← Ignored
├── .DS_Store           ← Ignored (Mac)
├── config.toml
└── USR-001.md

Performance Considerations

Large Directories

Requiem uses parallel loading for performance:

requirements/
├── USR-001.md
├── USR-002.md
├── ...
└── USR-5000.md  # 5000 files loads quickly due to parallelism

Performance: Requiem can handle thousands of requirements efficiently. Directory structure has minimal performance impact.

Network File Systems

If requirements are on a network drive:

  • Initial loading may be slower
  • Consider using subdirectories to localize access patterns
  • Parallel loading helps mitigate network latency

Choosing Between Modes

When to Use Filename-Based Mode (Default)

Advantages:

  • Maximum flexibility - organize folders however you want
  • Easy to move files between folders without changing HRIDs
  • Works well with arbitrary organizational schemes (by feature, by team, etc.)
  • Explicit namespaces visible in every filename

Best for:

  • Projects where folder structure is organizational, not semantic
  • Teams that reorganize folders frequently
  • Mixed organizational schemes
  • When you want full control over namespaces

Example:

requirements/
├── team-a/
│   └── auth-USR-001.md      → HRID: auth-USR-001
└── team-b/
    └── auth-SYS-002.md      → HRID: auth-SYS-002

When to Use Path-Based Mode

Advantages:

  • Cleaner filenames (shorter, less redundant)
  • Folder structure enforces namespace consistency
  • Natural for hierarchical component structures
  • Automatic namespace creation from folders

Best for:

  • Projects with stable, hierarchical component structures
  • When folder structure mirrors system architecture
  • Microservices or multi-component systems
  • When you want enforced namespace-folder alignment

Example:

requirements/
├── auth/
│   ├── USR-001.md           → HRID: auth-USR-001
│   └── SYS-002.md           → HRID: auth-SYS-002
└── payment/
    ├── USR-001.md           → HRID: payment-USR-001
    └── SYS-002.md           → HRID: payment-SYS-002

Comparison Table

AspectFilename-BasedPath-Based
Filename containsFull HRIDKIND-ID only
Namespace fromFilenameFolder path
Folder flexibilityHighLow (tied to namespace)
File move impactNoneChanges HRID
Filename lengthLongerShorter
Default modeYesNo

Migration Between Modes

Converting from Filename-Based to Path-Based

  1. Update configuration:
# config.toml
_version = "1"
subfolders_are_namespaces = true
  1. Reorganize files to match namespace structure:
# Before (filename-based):
# requirements/
# ├── auth-USR-001.md
# └── payment-USR-002.md

# Create namespace folders
mkdir -p auth payment

# Move and rename files
mv auth-USR-001.md auth/USR-001.md
mv payment-USR-002.md payment/USR-002.md

# After (path-based):
# requirements/
# ├── auth/
# │   └── USR-001.md
# └── payment/
#     └── USR-002.md
  1. Verify:
req clean

Converting from Path-Based to Filename-Based

  1. Flatten files and encode namespace in filename:
# Before (path-based):
# requirements/
# ├── auth/
# │   └── USR-001.md        (HRID: auth-USR-001)
# └── payment/
#     └── USR-002.md        (HRID: payment-USR-002)

# Move and rename with full HRID
mv auth/USR-001.md auth-USR-001.md
mv payment/USR-002.md payment-USR-002.md

# Remove now-empty folders
rmdir auth payment

# After (filename-based):
# requirements/
# ├── auth-USR-001.md
# └── payment-USR-002.md
  1. Update configuration:
# config.toml
_version = "1"
subfolders_are_namespaces = false
  1. Verify:
req clean

Note: When converting between modes, the HRID (and thus UUID) remains the same, preserving all links and history.

Migration and Refactoring

Reorganizing Files

To reorganize directory structure in filename-based mode:

  1. Move requirement files:
mkdir system
mv SYS-*.md system/
  1. Verify:
req clean
  1. Commit:
git add -A
git commit -m "Organize system requirements into subdirectory"

Safe because: Requirements are identified by HRID (filename), not path. Moving files doesn't break links.

Splitting Directories

To split a large flat directory:

# Before
requirements/
├── USR-001.md (100 files)

# After
requirements/
├── user/
│   └── USR-001.md (100 files)
└── system/
    └── SYS-001.md (100 files)

Steps:

mkdir user system test
mv USR-*.md user/
mv SYS-*.md system/
mv TST-*.md test/
req clean  # Verify

Summary

Key Takeaways:

  1. Flexible: Flat or hierarchical, your choice
  2. Recursive: Subdirectories are automatically scanned
  3. Simple: Directory names don't affect requirement behavior
  4. Scalable: Supports small projects (10s) to large (1000s)
  5. Reorganizable: Safe to move files (links use UUIDs, not paths)

Recommendations:

  • Start flat, add structure as needed
  • Keep shallow (2-3 levels max)
  • Organize by kind, feature, or component
  • Use consistent naming conventions
  • Align with team structure

Next Steps