Portfolio workflows
Portfolio commands turn source lanes into connected ODPC, ODPS, ODPG, HTML, localization, and version outputs. The recommended workflow is to inspect and build one lane first, then add the other lanes when the source extraction and generated shape look right.
Source lane layout
Each lane represents a different evidence type. Keep source files close to the lane they support so the portfolio prompt can distinguish business goals, user demand, external or operational signals, and actual product candidates.
source_docs/ objectives/ use-cases/ signals/ products/ generated/ portfolio/
Inspect one lane first
portfolio intake is the most important debugging command in the portfolio workflow. Start with one lane, not the whole bundled portfolio. It reads source files, detects file types, extracts text, masks personal data when enabled, applies prompt budgets, and reports what would be sent to the model. It does not call an LLM.
open-data-products portfolio intake \ --signals source_docs/signals/ \ --config generation.config.yaml \ --json
Use the lane that is easiest to verify manually. If you have product briefs, start with --products. If you have market evidence or operational observations, start with --signals. The goal is to confirm that the SDK sees the right files, extracts useful text, and reports the expected source count before any model call.
open-data-products portfolio intake \ --products source_docs/products/ \ --config generation.config.yaml \ --json open-data-products portfolio intake \ --objectives source_docs/objectives/ \ --config generation.config.yaml \ --json open-data-products portfolio intake \ --use-cases source_docs/use-cases/ \ --config generation.config.yaml \ --json
Build one lane first
After one-lane intake looks right, build a small workspace from that same lane. This is the safest first LLM-backed portfolio run because the output is easier to inspect. Use --strict-validation when invalid generated portfolio artifacts should fail the command instead of completing with warnings.
open-data-products portfolio build \ --signals source_docs/signals/ \ --config generation.config.yaml \ --output generated/portfolio-signals/ \ --strict-validation \ --json open-data-products portfolio explain generated/portfolio-signals/ --json open-data-products validate generated/portfolio-signals/odpc/catalog.yaml open-data-products validate generated/portfolio-signals/odpg/graph.yaml
Review the generated HTML and YAML before adding more lanes. Look for duplicated concepts, vague product names, weak source evidence, or relationships that do not match the source material. Fix the source folder or prompt configuration while the workspace is still small.
Build the combined workspace
Use the bundled all-lanes command only after one-lane intake and one-lane build have proved the workflow. The combined run is useful for the final connected portfolio, but it is harder to debug because objectives, use cases, signals, and products can all affect the generated catalog and graph.
open-data-products portfolio intake \ --objectives source_docs/objectives/ \ --use-cases source_docs/use-cases/ \ --signals source_docs/signals/ \ --products source_docs/products/ \ --config generation.config.yaml \ --json
open-data-products portfolio build \ --objectives source_docs/objectives/ \ --use-cases source_docs/use-cases/ \ --signals source_docs/signals/ \ --products source_docs/products/ \ --config generation.config.yaml \ --output generated/portfolio/ \ --strict-validation \ --json
Lifecycle commands
open-data-products portfolio refresh generated/portfolio/ open-data-products portfolio refresh generated/portfolio/ --all-sources open-data-products portfolio sync generated/portfolio/ open-data-products portfolio localize generated/portfolio/ \ --languages "fi,sv,ar,vi" \ --provider claude \ --model claude-sonnet-4-5 open-data-products portfolio render generated/portfolio/ open-data-products portfolio explain generated/portfolio/ --json
What gets created
| Output | Purpose | Review action |
|---|---|---|
index.html | Human review page for the portfolio workspace. | Open in a browser and review value narrative, product grouping, evidence, and gaps. |
portfolio.yaml | Structured portfolio state. | Use as the workspace-level source for refresh, sync, render, and explain. |
odpc/catalog.yaml | Catalog-level ODPC output. | Validate and inspect catalog contents before publishing or reuse. |
odpc/fragments/ | Generated objectives, use cases, signals, and product references. | Review IDs, names, evidence links, and duplicates. |
odpg/graph.yaml | Graph relationship context between objectives, products, use cases, signals, and KPIs. | Run graph summary, traversal, and agent-context commands. |
odps/products/ | ODPS product drafts created for portfolio candidates. | Validate product files and refine product details before handover. |
Supported source inputs
| Lane | Purpose | Supported inputs |
|---|---|---|
--objectives | Business objectives, outcomes, strategy notes, executive targets. | Markdown, text, YAML, JSON, EML, DOCX, PPTX, XLSX, PDF with embedded text, CSV, and Outlook MSG when installed with pip install "open-data-products[email]". |
--use-cases | Use cases, user journeys, decision needs, stakeholder workflows. | |
--signals | Market signals, operational signals, risks, quality evidence, usage evidence. | |
--products | Existing products, candidate products, product notes, product briefs. |
Debug intake first
When generated portfolio output looks incomplete, inspect the intake JSON before changing the prompt. Check sourceCounts, sourceExtraction.skippedSources, per-source status, sourceBudget.omittedChunkCount, sourcePrivacy.enabled, and warnings.
Important: image-only PDFs, images, hidden spreadsheet sheets, hidden slides, PowerPoint notes, and email attachments are not silently extracted by the base workflow. Put required evidence into supported text-bearing source files.
Common portfolio fixes
| Finding in intake JSON | Meaning | Practical fix |
|---|---|---|
status: skipped | The SDK detected the file but did not extract usable text. | Check the warning, install optional extras if needed, or convert the content into supported text-bearing input. |
status: empty | The file was readable but produced no extracted text. | Check whether the source contains only images, hidden data, comments, speaker notes, or attachments. |
status: reduced | Text was extracted but not all chunks fit into the configured prompt budget. | Split the source, reduce irrelevant content, or raise maxPromptChars only when the selected model can handle it. |
sourcePrivacy.enabled: true | Personal data masking changed values before prompt construction. | Review replacement counts and keep masking enabled for external providers unless the workflow is controlled and local-only. |