feat: add symphony workflow preview command#95
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new CLI subcommand to preview the fully assembled base-issue agent prompt from a local WORKFLOW.md, using deterministic sample issue data and the same prompt-building path as runtime to avoid drift.
Changes:
- Add
symphony workflow previewCLI subcommand to print the rendered base-issue prompt (with sample issue context) without needing Linear/network/orchestrator. - Introduce
SymphonyElixir.WorkflowPreviewand a:workflowseam inPromptBuilder.build_prompt/2to reuse the runtime prompt assembly code path. - Add tests for preview behavior and update docs (
README.md,WORKFLOW.md) to advertise the command.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| WORKFLOW.md | Adds a front-matter tip about the new preview command without affecting rendered prompt content. |
| README.md | Documents symphony workflow preview usage and intent as a lint/preview tool. |
| lib/symphony_elixir/workflow_preview.ex | New module that loads a workflow file and renders the assembled prompt with sample issue data. |
| lib/symphony_elixir/prompt_builder.ex | Adds :workflow opt handling so preview can reuse the same prompt assembly logic as runtime. |
| lib/symphony_elixir/cli.ex | Adds workflow preview command wiring and usage text. |
| test/symphony_elixir/workflow_preview_test.exs | New unit tests for preview rendering and error handling. |
| test/symphony_elixir/prompt_builder_test.exs | Verifies PromptBuilder.build_prompt/2 supports pre-loaded workflows via :workflow. |
| test/symphony_elixir/cli_test.exs | Adds CLI-level tests for preview output and usage/error behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| defp resolved_workflow(opts, workflow_source) do | ||
| case Keyword.get(opts, :workflow) do | ||
| {:ok, _workflow} = loaded -> loaded | ||
| %{} = workflow -> {:ok, workflow} | ||
| nil -> workflow_for_prompt(workflow_source) | ||
| end | ||
| end |
There was a problem hiding this comment.
Fixed in 2d5a8e5. resolved_workflow/2 now matches {:error, _reason} and propagates it, so a Workflow.load/1 error flows to prompt_template!/2 and raises the existing workflow_unavailable: ... error instead of a CaseClauseError. Added tests covering the {:ok, workflow} and {:error, reason} shapes.
| defp load_error_message(file, {:missing_workflow_file, _path, posix}) do | ||
| "Workflow file not found: `#{file}` (#{:file.format_error(posix)})" | ||
| end | ||
|
|
||
| defp load_error_message(file, reason) do | ||
| "Could not read workflow file `#{file}`: #{inspect(reason)}" | ||
| end |
There was a problem hiding this comment.
Fixed in 2d5a8e5. load_error_message/2 now uses :file.format_error/1 for the POSIX reason, so :enoent and :eacces read differently ("no such file or directory" vs "permission denied"), and adds a dedicated {:workflow_parse_error, _} clause that reports a readable "Could not parse front matter" message. The generic fallback is clearly labeled "Could not load workflow file". Added tests for missing-file, malformed-YAML, and non-map front matter.
Context
Authors editing
WORKFLOW.mdhad no way to see the final prompt an agent receives; partials and variables were only resolved at runtime, so template mistakes surfaced mid-run.TL;DR
Add
symphony workflow previewto print the assembled base-issue prompt from a localWORKFLOW.md.Summary
symphony workflow preview [--file WORKFLOW.md] [--agent codex|claude]escript subcommand.PromptBuilder.build_prompt/2via a new optional:workflowopt so preview can't drift from runtime.SymphonyElixir.WorkflowPreview(render/1,sample_issue/0); surface bad partials/vars as errors (lint).README.md; add a non-rendering front-matter tip inWORKFLOW.md.Alternatives
Test Plan
make allmix test test/symphony_elixir/workflow_preview_test.exs test/symphony_elixir/cli_test.exs test/symphony_elixir/prompt_builder_test.exs./bin/symphony workflow previewrenders the repoWORKFLOW.md; unknown{% render %}partial reports an error