Firm-Scoped IO System: Complete Implementation
This release completes the firm-scoped IO system, enabling private, firm-specific configurations, inputs, outputs, and exports. The system allows each firm (e.g.
Changelog - 2025-12-02 (#1)
Firm-Scoped IO System: Complete Implementation
Overview
This release completes the firm-scoped IO system, enabling private, firm-specific configurations, inputs, outputs, and exports. The system allows each firm (e.g., Hypernova Capital) to maintain their own branded templates, scorecards, outlines, and deal data isolated from the shared codebase—critical for multi-tenant deployments and keeping client data private.
Architecture: Firm-Scoped Directory Structure
The firm-scoped IO system uses the following directory structure:
io/
└── {firm}/ # e.g., "hypernova"
├── configs/
│ └── brand-{firm}-config.yaml # Firm-specific brand styling
├── templates/
│ ├── outlines/ # Firm-specific content outlines
│ │ ├── direct-early-stage-12Ps.yaml
│ │ └── lpcommit-emerging-manager.yaml
│ └── scorecards/ # Firm-specific evaluation scorecards
│ └── direct-early-stage-12Ps/
│ └── hypernova-early-stage-12Ps.yaml
└── deals/
└── {deal}/ # e.g., "Blinka"
├── {deal}.json # Deal configuration
├── inputs/ # Pitch decks, datarooms
├── outputs/ # Versioned memo artifacts
│ └── {Deal}-v0.0.x/
│ ├── 0-deck-analysis.json
│ ├── 1-research.json
│ ├── 2-sections/
│ ├── 4-final-draft.md
│ └── state.json
├── exports/ # Branded HTML/PDF exports
│ ├── dark/
│ └── light/
└── assets/ # Deal-specific assets (logos)Key Benefits
Privacy: Firm-specific configs and deal data stay in
io/(gitignored or private submodule)Multi-Tenant: Multiple firms can use the same codebase with isolated configurations
Backward Compatible: Legacy
output/,data/,templates/paths still workAuto-Detection: System auto-detects firm context from input file paths
Changes by Module
1. Brand Configuration (src/branding.py)
Purpose: Load brand configs from firm-scoped paths first.
Changes:
Added
firmparameter toBrandConfig.load()methodNew priority order for brand config lookup:
config_pathif explicitly providedio/{firm}/configs/brand-{name}-config.yaml(firm-scoped)templates/brand-configs/brand-{name}-config.yaml(shared)brand-{name}-config.yaml(root directory, legacy)Default Hypernova config (fallback)
Updated
list_available_brands()to search firm-scoped configs first
Example:
# Now checks io/hypernova/configs/ first
brand = BrandConfig.load(brand_name="hypernova", firm="hypernova")2. Scorecard Loader (src/scorecard_loader.py)
Purpose: Load evaluation scorecards from firm-scoped paths first.
Changes:
Added
firmparameter toget_scorecards_dir(),find_scorecard_file(),load_scorecard()New priority order for scorecard lookup:
io/{firm}/templates/scorecards/(firm-scoped)templates/scorecards/(shared)
Updated cache key to include firm for proper isolation
Updated
load_scorecard_for_state()to extract firm from state
Example:
# Checks io/hypernova/templates/scorecards/ first
scorecard = load_scorecard("hypernova-early-stage-12Ps", firm="hypernova")3. Export Branded CLI (cli/export_branded.py)
Purpose: Export memos to firm-scoped exports directory with auto-detection.
Major Changes:
Added
--firm,--deal,--versionCLI argumentsAuto-detects firm from input file path pattern:
io/{firm}/deals/{deal}/...Exports to
io/{firm}/deals/{deal}/exports/{mode}/when firm-scopedPasses
firmtoBrandConfig.load()for firm-scoped brand lookupUpdated company data lookup to check firm-scoped paths first
New CLI Usage:
# Explicit firm/deal (recommended)
python cli/export_branded.py --firm hypernova --deal Blinka --mode dark --pdf
# Auto-detection from path (just as good)
python cli/export_branded.py io/hypernova/deals/Blinka/outputs/Blinka-v0.0.2/4-final-draft.md --brand hypernova
# Legacy still works
python cli/export_branded.py output/Company-v0.0.1/4-final-draft.mdAuto-Detection Output:
Auto-detected firm-scoped path: hypernova/Blinka
Exporting to: io/hypernova/deals/Blinka/exports/dark4. Workflow (src/workflow.py)
Purpose: Ensure human_review() saves artifacts to firm-scoped paths.
Changes:
Updated
human_review()function to use firm-aware path resolutionUses
resolve_deal_context()when firm is providedCreates output directory in firm-scoped location
5. Artifacts (src/artifacts.py)
Purpose: Save/load artifacts from firm-scoped paths.
Changes:
Added
firmparameter tosave_deck_analysis_artifacts()Added
firmparameter toload_existing_section_drafts()Uses
resolve_deal_context()for firm-aware path resolutionPasses
firmtocreate_artifact_directory()
6. Agent Updates
All agents now support firm-scoped output paths:
src/agents/deck_analyst.py
Extracts
firmfrom statePasses
firmtosave_deck_analysis_artifacts()
src/agents/writer.py
Uses
resolve_deal_context()for firm-aware output directoryCreates artifact directory with
create_artifact_directory(company, version, firm=firm)
src/agents/research_enhanced.py
Uses firm-aware
VersionManagerinitializationCreates artifact directory with firm parameter
src/agents/validator.py
Simplified to use
get_latest_output_dir(company, firm=firm)Removed redundant version manager logic
src/agents/perplexity_section_researcher.py
Added firm-aware fallback when creating new output directories
Uses
create_artifact_directory()with firm parameter
src/agents/dataroom/analyzer.py
Updated
_get_or_create_output_dir()to acceptfirmparameterUses firm-aware path resolution throughout
7. Other CLI Tools Updated
All CLI tools now support --firm and --deal flags:
| CLI Tool | Changes |
cli/improve_section.py | Added --firm, --deal flags with auto-detection |
cli/score_memo.py | Added --firm, --deal flags with auto-detection |
cli/refocus_section.py | Added --firm, --deal flags with path resolution |
cli/recompile_memo.py | Added --firm, --deal flags with auto-detection |
Files Changed Summary
Modified Files (16)
| File | Purpose |
src/branding.py | Firm-scoped brand config loading |
src/scorecard_loader.py | Firm-scoped scorecard loading |
src/artifacts.py | Firm-scoped artifact saving/loading |
src/workflow.py | Firm-aware human_review() |
src/agents/deck_analyst.py | Pass firm to artifact saving |
src/agents/writer.py | Firm-aware output directory |
src/agents/research_enhanced.py | Firm-aware artifact creation |
src/agents/validator.py | Simplified firm-aware path resolution |
src/agents/perplexity_section_researcher.py | Firm-aware fallback directory creation |
src/agents/dataroom/analyzer.py | Firm-aware output directory |
cli/export_branded.py | Auto-detection, firm-scoped exports |
cli/improve_section.py | Added --firm/--deal flags |
cli/score_memo.py | Added --firm/--deal flags |
cli/refocus_section.py | Added --firm/--deal flags |
cli/recompile_memo.py | Added --firm/--deal flags |
context-vigilance/Firm-and-Deal-based-File-Organization-System.md | Updated progress |
New Files (2)
| File | Purpose |
context-vigilance/Fix-Firm-Scoped-Output-Paths.md | Planning document for this work |
context-vigilance/MemoPop-Landing-Page-Sepcification.md | Product landing page spec |
Deleted Files (Moved to io/hypernova/)
These firm-specific files were moved from shared templates to io/hypernova/:
| Original Location | New Location |
templates/brand-configs/brand-hypernova-config.yaml | io/hypernova/configs/brand-hypernova-config.yaml |
templates/outlines/direct-early-stage-12Ps.yaml | io/hypernova/templates/outlines/direct-early-stage-12Ps.yaml |
templates/outlines/lpcommit-emerging-manager.yaml | io/hypernova/templates/outlines/lpcommit-emerging-manager.yaml |
templates/scorecards/direct-early-stage-12Ps/hypernova-early-stage-12Ps.yaml | io/hypernova/templates/scorecards/... |
templates/scorecards/lp-commits_emerging-managers/hypernova-scorecard.yaml | io/hypernova/templates/scorecards/... |
templates/hypernova-reference.docx | io/hypernova/templates/hypernova-reference.docx |
Usage Examples
Complete Workflow with Firm-Scoped IO
# 1. Generate memo (firm-scoped outputs)
python -m src.main "Blinka" --firm hypernova
# 2. Improve a section
python cli/improve_section.py --firm hypernova --deal Blinka "Team"
# 3. Export to branded PDF
python cli/export_branded.py --firm hypernova --deal Blinka --mode dark --pdf
# 4. Score the memo
python cli/score_memo.py --firm hypernova --deal BlinkaAuto-Detection (No --firm needed)
When input path contains io/{firm}/deals/{deal}/, the system auto-detects:
# Auto-detects hypernova/Blinka from path
python cli/export_branded.py io/hypernova/deals/Blinka/outputs/Blinka-v0.0.2/4-final-draft.md --brand hypernova
# Output:
# Auto-detected firm-scoped path: hypernova/Blinka
# Exporting to: io/hypernova/deals/Blinka/exports/darkTesting & Validation
Tested Scenarios
Export auto-detects firm from io/ path structure
Exports go to
io/{firm}/deals/{deal}/exports/{mode}/Brand config loads from
io/{firm}/configs/Scorecard loads from
io/{firm}/templates/scorecards/Legacy paths (
output/,data/,templates/) still workFull pipeline generates to firm-scoped outputs
PDF export works with firm-scoped paths
Test Results
# Blinka memo export test
Auto-detected firm-scoped path: hypernova/Blinka
Exporting to: io/hypernova/deals/Blinka/exports/dark
✓ Loading brand config: io/hypernova/configs/brand-hypernova-config.yaml
✓ Brand: Hypernova Capital
✓ HTML (dark): Blinka-v0.0.2-draft.html (87.8 KB)
✓ PDF: Blinka-v0.0.2-draft.pdf (91.3 KB)
Output directory: io/hypernova/deals/Blinka/exports/darkRemaining Work
Documentation Updates Needed
Update
README.mdwith firm-scoped IO structureCreate
io/README.mdwith setup instructionsUpdate
CLAUDE.mdwith new path patterns
Future Enhancements
src/outline_loader.py- Checkio/{firm}/templates/outlines/firstEnvironment variable
MEMO_DEFAULT_FIRMsupport in CLI toolsFirm-specific prompt templates in
io/{firm}/templates/prompts/
Breaking Changes
None. All changes are backward compatible:
Legacy
output/,data/,templates/paths continue to work--firmflag is optional; omitting it uses legacy behaviorAuto-detection only activates for
io/path patterns
Contributors
Implementation by Claude Code (Anthropic) with user guidance.