Core workflow: Parse Mode -> Define Perspectives -> Parallel Scan -> Dedup + Issue Creation
Dual mode:
- Default (no args): 8-perspective scan (security, performance, reliability, maintainability, scalability, ux, accessibility, compliance)
by-prompt "...": User-driven exploration decomposed into 3-5 search dimensions
+-------------------------------------------------------------------------+
| ISSUE DISCOVERY CSV WAVE WORKFLOW |
+-------------------------------------------------------------------------+
| |
| Phase 1: Mode Resolution -> CSV |
| +-- Parse mode from arguments (multi-perspective or by-prompt) |
| +-- Validate environment (.workflow/ exists) |
| +-- Initialize discovery session directory |
| +-- [multi] Generate 8 perspective rows + 1 dedup row |
| +-- [by-prompt] Decompose prompt into 3-5 dimensions + 1 dedup row |
| +-- Determine scope globs per perspective/dimension |
| +-- Generate tasks.csv |
| +-- User validates perspective breakdown (skip if -y) |
| |
| Phase 2: Wave Execution Engine |
| +-- Wave 1: Perspective/Dimension Scan (parallel) |
| | +-- Each agent scans codebase from its perspective |
| | +-- Agent identifies concrete issues with file:line evidence |
| | +-- Agent rates findings by severity (critical/high/medium/low) |
| | +-- Discoveries shared via board (cross-perspective patterns) |
| | +-- Results: issues_found + severity_distribution per agent |
| +-- Wave 2: Dedup + Issue Creation (single agent) |
| | +-- Aggregates all perspective findings |
| | +-- Deduplicates by file path + description similarity |
| | +-- Keeps higher-severity duplicate |
| | +-- Creates issue records (ISS-YYYYMMDD-NNN) |
| | +-- Appends to issues.jsonl |
| +-- discoveries.ndjson shared across all waves (append-only) |
| |
| Phase 3: Results Aggregation |
| +-- Export results.csv |
| +-- Generate context.md with all findings |
| +-- Update discovery-state.json |
| +-- Display summary with breakdown by perspective + severity |
| +-- Suggest next steps |
| |
+-------------------------------------------------------------------------+
Flags:
-y, --yes: Skip all confirmations (auto mode)-c, --concurrency N: Max concurrent agents within each wave (default: 8)--continue: Resume existing session
When --yes or -y: Auto-confirm perspective selection, skip interactive validation, use defaults for scope detection.
Output Directory: .workflow/.csv-wave/{session-id}/
Core Output: tasks.csv (master state) + results.csv (final) + discoveries.ndjson (shared exploration) + context.md (human-readable report) + issues appended to .workflow/issues/issues.jsonl
Output boundary: ALL file writes MUST target .workflow/issues/issues.jsonl or .workflow/issues/discoveries/{SESSION_ID}/ only. NEVER modify source code or files outside these paths.
<csv_schema>
tasks.csv (Master State)
id,title,description,perspective,scope_glob,deps,context_from,wave,status
"1","Security Scan","Scan codebase for security vulnerabilities: authentication bypass, injection flaws, XSS, CSRF, sensitive data exposure, insecure crypto, secrets in code. Rate each finding critical/high/medium/low with file:line references.","security","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"2","Performance Scan","Scan codebase for performance issues: N+1 queries, unbounded loops, missing caching, memory leaks, large payloads, blocking operations, unoptimized algorithms.","performance","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"3","Reliability Scan","Scan codebase for reliability issues: unhandled errors, missing retry logic, race conditions, data integrity gaps, missing graceful degradation, silent failures.","reliability","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"4","Maintainability Scan","Scan codebase for maintainability issues: code duplication, tight coupling, missing abstractions, unclear naming, dead code, overly complex functions.","maintainability","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"5","Scalability Scan","Scan codebase for scalability issues: hardcoded limits, single-threaded bottlenecks, stateful assumptions, schema rigidity, missing pagination.","scalability","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"6","UX Scan","Scan codebase for UX issues: confusing flows, missing user feedback, inconsistent behavior, missing loading states, poor error messages.","ux","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"7","Accessibility Scan","Scan codebase for accessibility issues: missing ARIA labels, keyboard navigation gaps, color contrast problems, missing alt text, focus management issues.","accessibility","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"8","Compliance Scan","Scan codebase for compliance issues: logging gaps, missing audit trails, data retention violations, privacy control gaps, regulatory requirement gaps.","compliance","src/**/*.{ts,tsx,js,jsx}","","","1","pending"
"9","Dedup + Issue Creation","Aggregate all perspective findings. Deduplicate by file path + description similarity (keep higher severity). Generate ISS-YYYYMMDD-NNN issue records. Append to .workflow/issues/issues.jsonl.","dedup","","1;2;3;4;5;6;7;8","1;2;3;4;5;6;7;8","2","pending"
Columns:
| Column | Phase | Description |
|---|---|---|
id |
Input | Unique task identifier (string) |
title |
Input | Short task title |
description |
Input | Detailed scan instructions for this perspective |
perspective |
Input | Scan perspective: security/performance/reliability/maintainability/scalability/ux/accessibility/compliance/dedup |
scope_glob |
Input | File scope glob for analysis (e.g., src/**/*.{ts,tsx}) |
deps |
Input | Semicolon-separated dependency task IDs |
context_from |
Input | Semicolon-separated task IDs whose findings this task needs |
wave |
Computed | Wave number (1 = perspective scans, 2 = dedup + issue creation) |
status |
Lifecycle | Task lifecycle status, initialized to pending. Updated to completed/failed/skipped after wave merge via result_status mapping |
result_status |
Output | completed / failed / skipped (mapped to master status on merge) |
findings |
Output | Key scan findings summary (max 500 chars) |
issues_found |
Output | JSON array of discovered issues: [{"title":"...","severity":"critical","description":"...","location":"file:line","fix_direction":"...","affected_components":["..."]}] |
severity_distribution |
Output | JSON: {"critical":N,"high":N,"medium":N,"low":N} |
error |
Output | Error message if failed |
Column separation rule: Input columns and Output columns MUST NOT share names. Wave CSV only contains Input columns + prev_context. Output columns are returned exclusively via output_schema.
Per-Wave CSV (Temporary)
Each wave generates wave-{N}.csv with extra prev_context column.
Output Artifacts
| File | Purpose | Lifecycle |
|---|---|---|
tasks.csv |
Master state -- all tasks with status/findings | Updated after each wave |
wave-{N}.csv |
Per-wave input (temporary) | Created before wave, deleted after |
results.csv |
Final export of all task results | Created in Phase 3 |
discoveries.ndjson |
Shared exploration board | Append-only, carries across waves |
context.md |
Human-readable discovery report | Created in Phase 3 |
discovery-state.json |
Session metadata and progress | Updated throughout |
.workflow/issues/issues.jsonl |
Issues appended here | Append-only |
Session Structure
.workflow/.csv-wave/{YYYYMMDD}-discover-{mode}/
+-- tasks.csv
+-- results.csv
+-- discoveries.ndjson
+-- context.md
+-- discovery-state.json
+-- wave-{N}.csv (temporary)
Also writes to:
.workflow/issues/discoveries/{SESSION_ID}/
+-- discovery-state.json (copy)
+-- discovery-issues.jsonl
+-- {perspective}-findings.json (per perspective raw output)
</csv_schema>
Session Initialization
// Parse from $ARGUMENTS:
// AUTO_YES <- --yes | -y
// continueMode <- --continue
// maxConcurrency <- --concurrency N | -c N (default: 8)
// mode <- "by-prompt" if clean args start with "by-prompt", else "multi"
// userPrompt <- text after "by-prompt" (stripped of quotes)
// Session IDs (UTC+8):
// sessionId = DBP-{YYYYMMDD}-{HHmmss}
// csvSessionId = {YYYYMMDD}-discover-{mode}
// sessionFolder = .workflow/.csv-wave/{csvSessionId}
// discoveryDir = .workflow/issues/discoveries/{sessionId}
// Create: sessionFolder, discoveryDir, .workflow/issues/
// Touch: .workflow/issues/issues.jsonl
Initialize discovery-state.json:
{
"id": "{sessionId}",
"mode": "{mode}",
"status": "in_progress",
"started_at": "{ISO}",
"completed_at": null,
"perspectives_completed": [],
"issues_found": 0,
"issues_deduplicated": 0
}
Phase 1: Mode Resolution -> CSV
Objective: Determine mode, define perspectives/dimensions, determine scope, generate tasks.csv.
Multi-Perspective Mode (default)
8 fixed perspectives:
| # | Perspective | Focus | Guiding Question |
|---|---|---|---|
| 1 | security | Auth, authz, input validation, secrets, injection | What security vulnerabilities or unsafe patterns exist? |
| 2 | performance | N+1 queries, loops, caching, memory, payloads | What performance bottlenecks or inefficiencies exist? |
| 3 | reliability | Error handling, retry, race conditions, data integrity | What failure modes are unhandled or could cause data loss? |
| 4 | maintainability | Duplication, coupling, abstractions, naming, dead code | What makes this codebase harder to understand or change? |
| 5 | scalability | Hardcoded limits, single-thread, stateful, schema rigidity | What will break or degrade as load/data/users increase? |
| 6 | ux | Confusing flows, feedback, consistency, loading states | What creates friction or confusion for end users? |
| 7 | accessibility | Screen reader, keyboard nav, contrast, ARIA, focus | What barriers exist for users with disabilities? |
| 8 | compliance | Logging, audit trails, retention, privacy, regulatory | What regulatory or policy requirements are not met? |
CSV generation: 8 perspective rows (wave 1) + 1 dedup row (wave 2).
Scope detection: Default src/**/*.{ts,tsx,js,jsx}. Refine by reading .workflow/project.md for tech stack hints.
By-Prompt Mode
- Parse
userPrompt-- if empty, ask user interactively - Decompose prompt into 3-5 exploration dimensions (use analysis to break down the user's intent into searchable dimensions)
- For each dimension: define name, description, search patterns, file patterns, finding criteria
- Store dimensions in
{discoveryDir}/exploration-plan.json - Generate N dimension rows (wave 1) + 1 dedup row (wave 2)
Specs loading: specs_content = maestro load --type spec --category coding -- pass to agents for severity calibration.
User validation: Display perspective/dimension breakdown (skip if AUTO_YES).
Phase 2: Wave Execution Engine
Objective: Execute perspective scans wave-by-wave via spawn_agents_on_csv.
Wave 1: Perspective/Dimension Scans (Parallel)
- Read master
tasks.csv - Filter rows where
wave == 1ANDstatus == pending - No prev_context needed (wave 1 has no predecessors)
- Write
wave-1.csv - Execute:
spawn_agents_on_csv({
csv_path: `${sessionFolder}/wave-1.csv`,
id_column: "id",
instruction: DISCOVER_PERSPECTIVE_INSTRUCTION, // see "Perspective Worker Contract" below
max_concurrency: maxConcurrency,
max_runtime_seconds: 3600,
output_csv_path: `${sessionFolder}/wave-1-results.csv`,
output_schema: {
type: "object",
properties: {
id: { type: "string" },
result_status: { type: "string", enum: ["completed", "failed"] },
findings: { type: "string", maxLength: 500 },
issues_found: { type: "string", description: "JSON array string" },
severity_distribution: { type: "string", description: "JSON object string {critical, high, medium, low}" },
error: { type: "string" }
},
required: ["id", "result_status", "findings"]
}
})
- Merge
wave-1-results.csvinto mastertasks.csv(mapresult_status-> masterstatuscolumn; copyfindings,issues_found,severity_distribution,error) - Save per-perspective findings to
{discoveryDir}/{perspective}-findings.json - Update
discovery-state.jsonwith completed perspectives - Delete temporary files:
wave-1.csvandwave-1-results.csv
Perspective Worker Contract (DISCOVER_PERSPECTIVE_INSTRUCTION)
You are a perspective scanner for ONE dimension. Your perspective, scope_glob, and description come from your CSV row.
REQUIRED STEPS:
1. Read shared discoveries: {sessionFolder}/discoveries.ndjson (may be empty)
2. Scan all files matching scope_glob using Read/Grep/Glob (read-only)
3. For each finding: capture title, severity (critical|high|medium|low), description, file:line location, fix_direction, affected_components[]
4. Append cross-cutting patterns to discoveries.ndjson (dedup by type+key)
5. Call report_agent_job_result EXACTLY ONCE
TERMINATION CONTRACT (mandatory — NO worker may end without calling report_agent_job_result):
- Success path → result_status=completed (issues_found may be empty array if nothing found)
- Timeout path → near max_runtime_seconds, STOP and report completed with partial issues_found (do NOT report failed for timeout — partial work is valuable)
- Failure path → unrecoverable error (cannot read scope, parse failure) → result_status=failed with error message
- NEVER continue indefinitely. NEVER exit silently. NEVER omit the call.
OUTPUT (return via report_agent_job_result; must match output_schema):
{
"id": "<your row id>",
"result_status": "completed" | "failed",
"findings": "<one-sentence summary, max 500 chars>",
"issues_found": "<JSON array string: [{\"title\":\"...\",\"severity\":\"...\",\"description\":\"...\",\"location\":\"file:line\",\"fix_direction\":\"...\",\"affected_components\":[...]}]>",
"severity_distribution": "<JSON object string: {\"critical\":N,\"high\":N,\"medium\":N,\"low\":N}>",
"error": "<message if failed, else empty>"
}
CONSTRAINTS:
- Every finding MUST have a concrete file:line reference. No speculative issues.
- Do NOT write to tasks.csv, wave-*.csv, results.csv, or issues.jsonl (orchestrator owns those).
- Do NOT call spawn_agents_on_csv (no recursion).
Wave 2: Dedup + Issue Creation (Single Agent)
- Read master
tasks.csv - Filter rows where
wave == 2ANDstatus == pending - Check deps -- if all wave 1 agents failed, skip dedup (invariant 6)
- Build
prev_contextfrom completed wave 1 rows only. Excludefailed/skippedrows. For excluded rows, inject[GAP: {perspective} scan failed — findings incomplete]note. Setevidence_incomplete: trueif any perspective failed:[Task 1: Security Scan] Found 3 issues: SQL injection in query builder (critical), missing CSRF token (high)... [Task 2: Performance Scan] Found 5 issues: N+1 query in user listing (high), missing pagination (medium)... ... - Write
wave-2.csvwithprev_contextcolumn - Execute:
spawn_agents_on_csv({
csv_path: `${sessionFolder}/wave-2.csv`,
id_column: "id",
instruction: DEDUP_INSTRUCTION, // see "Dedup Worker Contract" below
max_concurrency: 1,
max_runtime_seconds: 1800,
output_csv_path: `${sessionFolder}/wave-2-results.csv`,
output_schema: {
type: "object",
properties: {
id: { type: "string" },
result_status: { type: "string", enum: ["completed", "failed"] },
findings: { type: "string", maxLength: 500 },
issues_found: { type: "string", description: "JSON array of deduplicated issues with ISS-* IDs" },
severity_distribution: { type: "string" },
error: { type: "string" }
},
required: ["id", "result_status", "findings"]
}
})
- Merge results into master
tasks.csv(mapresult_status-> masterstatuscolumn) - Delete temporary files:
wave-2.csvandwave-2-results.csv
Dedup Worker Contract (DEDUP_INSTRUCTION)
You are the dedup + issue creation worker. Your prev_context contains all wave-1 perspective findings.
REQUIRED STEPS:
1. Parse prev_context — extract every issues_found JSON from upstream rows
2. Deduplicate: group by file path, compare descriptions (>80% overlap or same file:line → keep higher severity)
3. Assign collision-safe ID per unique issue: ISS-YYYYMMDD-NNN
4. Build full issue record (severity→priority: critical→1/high→2/medium→3/low→4; source="discover"; tags=[perspective])
5. Append deduplicated records to .workflow/issues/issues.jsonl AND {discoveryDir}/discovery-issues.jsonl
6. Call report_agent_job_result EXACTLY ONCE
TERMINATION CONTRACT (mandatory):
- Success → result_status=completed with issues_found = final deduped JSON array
- Timeout → near max_runtime_seconds, persist partial dedup, report completed with note in findings
- Failure → file write error, parse error → result_status=failed
- NEVER skip report_agent_job_result.
OUTPUT (must match output_schema):
{
"id": "<your row id>",
"result_status": "completed" | "failed",
"findings": "<pre-dedup count → post-dedup count summary>",
"issues_found": "<JSON array of final deduplicated issues>",
"severity_distribution": "<JSON object: {critical, high, medium, low}>",
"error": "<message if failed, else empty>"
}
CONSTRAINTS:
- Append-only writes to issues.jsonl. Never overwrite existing records.
- Every record MUST include source: "discover".
- Do NOT call spawn_agents_on_csv (no recursion).
Dedup agent protocol:
- Merge all perspective findings from prev_context into single list
- Deduplicate: group by file path, compare descriptions (>80% overlap or same file:line → keep higher severity)
- For each unique finding: generate
ISS-YYYYMMDD-NNNID (collision-safe), build full issue record- Severity-to-priority: critical→1, high→2, medium→3, low→4; source = "discover", tags = ["{perspective}"]
- Append to
.workflow/issues/issues.jsonland{discoveryDir}/discovery-issues.jsonl - Report: pre-dedup count, post-dedup count, severity_distribution
Phase 3: Results Aggregation
Objective: Generate final results and human-readable report.
- Read final master
tasks.csv - Export as
results.csv - Update discovery-state.json:
{
"id": "{sessionId}",
"mode": "{mode}",
"status": "completed",
"started_at": "{ISO}",
"completed_at": "{ISO}",
"perspectives_completed": ["security", "performance", "..."],
"issues_found": 42,
"issues_deduplicated": 31
}
-
Copy
discovery-state.jsonto{discoveryDir}/discovery-state.json -
Generate context.md:
# Issue Discovery Report
## Summary
- Session: {sessionId}
- Mode: {mode}
- Perspectives: {perspective_count}
- Raw findings: {issues_found}
- Unique issues: {issues_deduplicated}
## Breakdown by Perspective
| Perspective | Findings | Critical | High | Medium | Low |
|-------------|----------|----------|------|--------|-----|
| Security | {N} | {N} | {N} | {N} | {N} |
| Performance | {N} | {N} | {N} | {N} | {N} |
| ... | | | | | |
## Severity Distribution
| Severity | Count |
|----------|-------|
| Critical | {N} |
| High | {N} |
| Medium | {N} |
| Low | {N} |
## Perspective Details
### {perspective_name}
{findings_summary}
**Top Issues:**
{top_issues_list}
## Issues Created
{list of ISS-YYYYMMDD-NNN IDs with titles}
-
Display summary: Session ID, mode, perspective count, raw vs unique finding counts, per-perspective breakdown, severity breakdown, and output file paths.
-
Next step routing:
| Result | Suggestion |
|---|---|
| Critical issues found | $manage-issue "list --severity critical" |
| Issues created | $manage-issue "list" |
| Specific area needs deeper look | $manage-issue-discover "by-prompt '...'" |
| Full scan complete | $manage-issue "list --source discovery" |
Shared Discovery Board Protocol
Standard Discovery Types
| Type | Dedup Key | Data Schema | Description |
|---|---|---|---|
code_pattern |
data.name |
{name, file, description} |
Reusable code pattern found |
integration_point |
data.file |
{file, description, exports[]} |
Module connection point |
convention |
singleton | {naming, imports, formatting} |
Project code conventions |
blocker |
data.issue |
{issue, severity, impact} |
Blocking issue found |
tech_stack |
singleton | {framework, language, tools[]} |
Technology stack info |
Domain Discovery Types
| Type | Dedup Key | Data Schema | Description |
|---|---|---|---|
vulnerability |
data.location |
{location, type, severity, cwe} |
Security vulnerability |
code_smell |
data.location |
{location, type, severity, description} |
Code quality issue |
performance_hotspot |
data.location |
{location, type, impact} |
Performance issue |
reliability_risk |
data.location |
{location, failure_mode, impact} |
Reliability concern |
scalability_limit |
data.location |
{location, constraint, threshold} |
Scalability bottleneck |
Protocol
- Read
{session_folder}/discoveries.ndjsonbefore own scan - Skip covered: If discovery of same type + dedup key exists, skip
- Write immediately: Append findings as found
- Append-only: Never modify or delete
- Deduplicate: Check before writing
echo '{"ts":"<ISO>","worker":"{id}","type":"vulnerability","data":{"location":"src/auth/login.ts:42","type":"sql_injection","severity":"critical","cwe":"CWE-89"}}' >> {session_folder}/discoveries.ndjson
<error_codes>
| Error | Resolution |
|---|---|
.workflow/ does not exist |
Abort: "No project initialized. Run maestro-init first." |
by-prompt with empty prompt |
Interactive prompt with suggested options |
| Perspective agent timeout | Mark as failed, continue remaining perspectives |
| All perspective agents failed | Skip dedup, report no findings |
| Dedup agent failed | Do NOT write to issues.jsonl — preserve raw findings in context.md and {discoveryDir}/ for manual review or retry. Mark session incomplete. |
| issues.jsonl write failure | Retry once, then report error with findings in context.md |
| CSV parse error | Validate format, show line number |
| discoveries.ndjson corrupt | Ignore malformed lines |
| Continue mode: no session found | List available sessions |
| ID collision in issues.jsonl | Re-read file, recalculate next sequence number |
| </error_codes> |
<success_criteria>
- Session initialized with discovery-state.json
- tasks.csv generated with correct perspective/wave assignments
- All perspective agents executed in parallel (wave 1)
- Dedup agent aggregates and deduplicates findings (wave 2)
- Issues appended to .workflow/issues/issues.jsonl with unique IDs
- results.csv and context.md generated with full breakdown
- Temporary wave-{N}.csv files cleaned up after merge
- discoveries.ndjson maintained as append-only
- Per-perspective findings saved to discovery directory </success_criteria>