Summary
Completed the firm-scoped IO path resolution system, enabling deals to be stored in `io/{firm}/deals/{deal}/` with automatic fallback to the legacy `data/` and `output/` directories. All agents now pass the `firm` parameter through the workflow.
Changelog: Firm-Scoped Path Resolution Implementation
Date: 2025-11-30 Type: Feature Implementation Scope: Path resolution, CLI, agents, state management Status: Complete
Summary
Completed the firm-scoped IO path resolution system, enabling deals to be stored in io/{firm}/deals/{deal}/ with automatic fallback to the legacy data/ and output/ directories. All agents now pass the firm parameter through the workflow.
Changes
New Files
src/paths.py - Centralized Path Resolution
New module with DealContext dataclass and resolution utilities:
@dataclass
class DealContext:
"""Encapsulates resolved paths for a deal."""
deal_name: str
firm: Optional[str] = None
io_root: Path = DEFAULT_IO_ROOT
deal_dir: Optional[Path] = None
inputs_dir: Optional[Path] = None
outputs_dir: Optional[Path] = None
exports_dir: Optional[Path] = None
deal_json_path: Optional[Path] = None
is_legacy: bool = FalseKey functions:
resolve_deal_context(deal_name, firm, io_root)- Main entry point with priority:Explicit
firmparameterMEMO_DEFAULT_FIRMenvironment variableAuto-detect from
io/directory structureLegacy fallback (
data/{deal}.json+output/{deal}-v*/)
get_latest_output_dir_for_deal(ctx)- Gets latest versioned output directory
Modified Files
src/main.py - CLI Enhancements
Added new CLI flags:
python -m src.main "Handle" --firm hypernova
python -m src.main --deal "Handle" --firm hypernova--firm: Specify firm name for io/{firm}/deals/{deal}/ structure--deal: Alternative to positional argument for deal nameFalls back to
MEMO_DEFAULT_FIRMenv var if no--firmspecified
src/state.py - MemoState Extension
Added firm field to MemoState TypedDict:
class MemoState(TypedDict):
# ... existing fields ...
firm: Optional[str] # Firm name for io/{firm}/deals/{deal}/ structureUpdated create_initial_state() to accept and store firm parameter.
src/workflow.py - Firm Parameter Flow
generate_memo()now acceptsfirmparameterPasses
firmtocreate_initial_state()finalize_memo()extractsfirmfrom state for output directory resolution
src/utils.py - Firm-Aware Output Resolution
Updated get_latest_output_dir() signature:
def get_latest_output_dir(
company_name: str,
firm: Optional[str] = None,
io_root: Optional[Path] = None
) -> Path:Resolution priority:
Firm-scoped:
io/{firm}/deals/{company}/outputs/{company}-v*/Legacy fallback:
output/{company}-v*/
src/artifacts.py - Firm-Scoped Artifact Creation
Updated create_artifact_directory():
def create_artifact_directory(
company_name: str,
version: str,
firm: str = None,
io_root: Path = None
) -> Path:Creates directories in io/{firm}/deals/{deal}/outputs/ when firm is specified.
All 10 Agents Updated
Each agent now extracts firm from state and passes to get_latest_output_dir():
| Agent | Change |
citation_enrichment.py | Added firm = state.get("firm") |
fact_checker.py | Added firm = state.get("firm") |
link_enrichment.py | Added firm = state.get("firm") |
perplexity_section_researcher.py | Added firm = state.get("firm") |
portfolio_listing_agent.py | Added firm = state.get("firm") |
scorecard_agent.py | Added firm = state.get("firm") |
scorecard_evaluator.py | Added firm = state.get("firm") |
socials_enrichment.py | Added firm = state.get("firm") |
toc_generator.py | Added firm = state.get("firm") |
trademark_enrichment.py | Added firm = state.get("firm") |
.env - Default Firm Configuration
Added environment variable:
# Default firm for io/{firm}/deals/{deal}/ structure
MEMO_DEFAULT_FIRM=hypernovaUsage
With Default Firm (from .env)
# Uses MEMO_DEFAULT_FIRM=hypernova from .env
python -m src.main "Handle"With Explicit Firm
python -m src.main "Handle" --firm hypernovaLegacy Mode (no firm)
# Falls back to data/{deal}.json and output/{deal}-v*/
python -m src.main "Fernstone"Testing Results
Verified path resolution for three scenarios:
# Test 1: Legacy deal (no firm)
get_latest_output_dir('Fernstone')
# ✅ Found: output/Fernstone-v0.0.2
# Test 2: Firm-scoped deal (explicit firm)
get_latest_output_dir('Harmonic', firm='hypernova')
# ✅ Found: io/hypernova/deals/Harmonic/outputs/Harmonic-v0.0.3
# Test 3: Firm auto-detection (no firm specified)
get_latest_output_dir('Harmonic')
# ✅ Found: io/hypernova/deals/Harmonic/outputs/Harmonic-v0.0.3Commits
ca54585- feat(agents): Add firm parameter support to all agents05caeda- docs(context-vigilance): Update firm-based IO implementation progress
Remaining Work
Phase 2: CLI Updates (Not Yet Started)
The following CLI scripts still need firm/deal resolution:
cli/improve-section.pycli/export_branded.pycli/score_memo.pycli/refocus_section.pycli/recompile_memo.py
Phase 4: Documentation
Update
README.mdwith new directory structureCreate
io/README.mdwith setup instructionsUpdate
CLAUDE.mdwith new paths
Contributors
Implementation by Claude Code (Anthropic) with user guidance.