How Requiem Supports These Principles
Now that you understand requirements management principles, let's explore how Requiem's design choices support these practices.
Plain Text: The Foundation
Requiem's most fundamental decision is storing requirements as plain text (Markdown with YAML frontmatter).
Benefits
Human Readable: Anyone with a text editor can read and edit requirements. No specialized tools required.
---
uuid: 4bfeb7d5-d168-44a7-b0f1-e292c1c89b9a
---
Users shall be able to export data in CSV format.
This is instantly understandable to developers, managers, and stakeholders alike.
Version Control Native: Plain text integrates seamlessly with Git, providing:
- Line-by-line diffs showing exactly what changed
- Complete history with blame and log
- Pull request workflows for review
- Branching and merging for parallel development
Tool Agnostic: Requirements aren't locked into proprietary formats. You can:
- Search with grep/ripgrep
- Process with scripts (Python, Bash, etc.)
- View in any text editor or IDE
- Preview as rendered Markdown
- Process with static site generators
Future Proof: Plain text files from 1970 are still readable today. Your requirements will outlive any proprietary tool.
Trade-offs
No GUI: Requiem doesn't provide a graphical interface. Users must be comfortable with text editors and the command line.
No Real-time Collaboration: Unlike cloud-based tools, Requiem doesn't support simultaneous editing. Use Git workflows instead.
Dual Identifiers: Stability and Usability
Requiem uses both UUIDs and Human-Readable IDs (HRIDs).
UUIDs: Stable References
uuid: 4bfeb7d5-d168-44a7-b0f1-e292c1c89b9a
Purpose: Permanent, globally unique identifier that never changes.
Enables:
- Renumbering requirements without breaking links
- Merging requirement sets from different sources
- Machine processing and indexing
Example: You can rename USR-001 to AUTH-001 without breaking any parent references, because they use the UUID.
HRIDs: Human Communication
hrid: USR-001
Purpose: Short, memorable identifier for human use.
Enables:
- Easy verbal communication: "Did you implement USR-042?"
- Clear code comments:
// Satisfies SYS-078 - Intuitive filenames:
USR-001.md
Example: In a meeting, saying "UUID 4bfeb7d5-d168-44a7-b0f1-e292c1c89b9a" is impractical. "USR-001" is clear and concise.
Best of Both Worlds
Parent relationships use UUIDs but store HRIDs for convenience:
parents:
- uuid: 4bfeb7d5-d168-44a7-b0f1-e292c1c89b9a # For machine processing
fingerprint: e533784ff58c16cbf08e436cb06f09e0076880fd707baaf55aa0f45dc4a6ccda
hrid: USR-001 # For human readers
The req clean command corrects HRIDs if requirements are renumbered, maintaining human-readability while UUIDs ensure correctness.
Content Fingerprinting: Change Detection
Every requirement's content is hashed to create a fingerprint:
fingerprint: e533784ff58c16cbf08e436cb06f09e0076880fd707baaf55aa0f45dc4a6ccda
How It Works
The fingerprint is a SHA256 hash of:
- The requirement text (markdown body)
- Any tags
This means:
- ✓ Changing the requirement text → new fingerprint
- ✓ Adding/removing tags → new fingerprint
- ✗ Changing HRID → same fingerprint (HRID is just a label)
- ✗ Adding parents → same fingerprint (relationships are separate)
Enables Change Detection
When a parent requirement changes:
- Parent's fingerprint updates
- Children still have old fingerprint
- Children are "suspect" - they might need review
Note: Automatic detection is planned but not yet implemented. Currently, you detect stale fingerprints manually or via scripts.
Future: Review Workflows
Planned features:
- Automatically flag requirements with stale parent fingerprints
- Assign reviews to stakeholders
- Track review status (current, suspect, under review, approved)
- Generate reports of suspect requirements
Multiple Parents: Modeling Reality
Many requirements management tools force a strict tree hierarchy. Requiem supports multiple parents because that's how real systems work.
Why Multiple Parents Matter
Example: A logging system might satisfy:
- USR-042: "Debugging capability"
- USR-078: "Audit trail for compliance"
- USR-091: "Performance monitoring"
Representing this as a tree forces artificial choices:
# Tree (artificial)
USR-042 (Debugging)
└─ SYS-123 (Logging) # Also satisfies USR-078 and USR-091, but structure doesn't show this
With multiple parents:
SYS-123 (Logging)
├─ USR-042 (Debugging)
├─ USR-078 (Audit trail)
└─ USR-091 (Performance monitoring)
This accurately models the requirement's purpose.
Implementation
parents:
- uuid: <uuid-1>
hrid: USR-042
- uuid: <uuid-2>
hrid: USR-078
- uuid: <uuid-3>
hrid: USR-091
Trade-off: Cycles
Multiple parents enable cycles (requirement A depends on B depends on A). Cycles are usually errors.
Note: Cycle detection is planned but not yet implemented.
Namespace Support: Scaling to Large Projects
HRIDs support optional namespaces:
USR-001 # Simple
COMPONENT-USR-001 # One namespace level
AUTH-LOGIN-SYS-042 # Multiple namespace levels
Use Cases
Large projects: Partition requirements by subsystem
AUTH-USR-001 # Authentication user requirements
AUTH-SYS-001
PAYMENT-USR-001 # Payment user requirements
PAYMENT-SYS-001
Product families: Distinguish product-specific vs. shared requirements
CORE-SYS-001 # Shared across all products
MOBILE-USR-001 # Mobile app specific
WEB-USR-001 # Web app specific
Acquisitions/Mergers: Integrate requirement sets without renumbering
LEGACY-SYS-001 # From acquired company
NEW-SYS-001 # Newly created
Implementation
Namespaces are part of the HRID format:
#![allow(unused)] fn main() { // Format: {NAMESPACE*}-{KIND}-{ID} NAMESPACE-NAMESPACE-KIND-042 }
Configure allowed namespaces in config.toml (optional).
Configuration and Flexibility
Requiem provides sane defaults but allows customization:
config.toml
_version = "1"
# Restrict to specific requirement kinds
allowed_kinds = ["USR", "SYS", "SWR", "TST"]
# Digits in HRID numbering (e.g., 001 vs 0001)
digits = 3
# Allow markdown files that aren't requirements
allow_unrecognised = false
# Allow requirements with invalid format
allow_invalid = false
This balances flexibility (customize as needed) with safety (defaults prevent common errors).
Integration Philosophy: Compose, Don't Replace
Requiem integrates with existing tools rather than replacing them:
Documentation Tools
Use with MdBook or Sphinx to embed requirements in user documentation:
# User Guide - Data Export
---
_version: '1'
uuid: 4bfeb7d5-d168-44a7-b0f1-e292c1c89b9a
created: 2025-07-22T12:19:56.950194157Z
---
# USR-001 Plain Text Storage
## Statement
The tool shall store requirements as plain-text files that can be read and edited with any text editor.
## Rationale
Plain text storage enables:
- Version control integration with Git and other VCS tools
- Human review without specialized software
- Long-term archival and accessibility
- Integration with existing text-based workflows
## Acceptance Criteria
- Requirements are stored as `.md` (Markdown) files
- Files can be opened and edited in any text editor
- No proprietary or binary formats are required
- Files are compatible with standard version control systems
To export data, click the Export button...
Requirements stay synchronized with documentation automatically.
Version Control
Works naturally with Git workflows:
- Feature branches for requirement changes
- Pull requests for review
- Merge commits for approval
- Tags for releases/versions
Static Analysis
Plain-text enables custom tooling:
# Find all USR requirements not linked by any SYS requirement
comm -23 \
<(ls USR-*.md | sort) \
<(grep -oh "USR-[0-9]*" SYS-*.md | sort -u)
CI/CD Integration
Add requirement validation to CI:
# .github/workflows/requirements.yml
- name: Validate requirements
run: req clean --dry-run # Check HRIDs are correct
Performance: Built for Scale
Requiem is written in Rust and uses parallelism for operations on large requirement sets.
Parallel Loading
When loading a directory with thousands of requirements:
#![allow(unused)] fn main() { // Uses rayon for parallel iteration let requirements: Vec<_> = md_paths .par_iter() .map(|path| load_requirement(path)) .collect(); }
This means Requiem scales to large projects (1000s of requirements) without becoming sluggish.
Efficient Indexing
Requirements are indexed by UUID in a HashMap, enabling O(1) lookups:
#![allow(unused)] fn main() { let req = tree.requirement(uuid); // Constant time }
Design Trade-offs
Every design involves trade-offs. Requiem prioritizes:
Over graphical interfaces: Plain text and CLI
- Pro: Version control, scripting, no vendor lock-in
- Con: Steeper learning curve for non-technical users
Over centralized databases: Distributed files
- Pro: Works offline, natural with Git, simple deployment
- Con: No real-time collaboration, requires file system access
Over strict tree hierarchies: Multiple parents (DAGs)
- Pro: Models reality accurately
- Con: Enables cycles (requires detection)
Over comprehensive built-in features: Composability
- Pro: Integrate with existing tools, stay focused
- Con: Some features require external tools or scripts
Summary: Why Requiem?
Requiem's design supports requirements management principles through:
- Plain text - Readable, versionable, future-proof
- Dual identifiers - Stable UUIDs + usable HRIDs
- Fingerprinting - Detect changes, enable reviews
- Multiple parents - Model complex dependencies accurately
- Namespace support - Scale to large, multi-component projects
- Composable - Works with Git, MdBook, Sphinx, custom tools
- Fast - Parallel processing for large requirement sets
These choices make Requiem a powerful tool for teams that value:
- Version control integration
- Plain-text workflows
- Speed and scalability
- Flexibility and composability
Ready to dive deeper into practical usage? Continue to Working with Requirements.