Skip to content

WIP DO NOT MERGE JUST FOR TEST Generate and edit prd - #348

Open
adiraju13 wants to merge 6 commits into
mainfrom
generate-and-edit-prd
Open

WIP DO NOT MERGE JUST FOR TEST Generate and edit prd#348
adiraju13 wants to merge 6 commits into
mainfrom
generate-and-edit-prd

Conversation

@adiraju13

@adiraju13 adiraju13 commented May 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces a new generate_prd / edit_prd two-phase workflow where a project-level PRD is generated once and then refined decision-by-decision as the PM resolves open questions. It also adds finalize_initial_prototype to apply a final PRD to a prototype and refactors shared utilities into the new context.py and generate_sketches.py modules.

  • generate_prd now writes the PRD to a temp-directory file and stores its path in project.spec; edit_prd reads that path and rewrites one decision section in-place after a decision is resolved.
  • generate_initial_prototype is redesigned to produce a single baseline clone of the existing app (using os.getcwd() as the source), replacing the previous 3-approach parallel PRD-backed prototype generation.
  • Sketch-generation logic and shared helpers (build_decision, next_decision_id, conversation_transcript, etc.) are extracted from generate_decisions.py into new generate_sketches.py and context.py modules, removing ~250 lines of duplication.

Confidence Score: 3/5

Not safe to merge; multiple unresolved correctness issues in the core PRD persistence and edit-PRD workflow.

The PRD is stored in /tmp and its path is persisted in project.spec. After a system restart or /tmp purge, edit_prd and finalize_initial_prototype will either raise or silently write the raw path string as PRD content, breaking the design workflow permanently for that project without re-running generate_prd. These issues were flagged in the previous review round and remain unresolved in this diff.

generate_prd.py (temp-file PRD persistence), finalize_initial_prototype.py (_read_prd_path silent fallback), and edit_prd.py (unresolved-decision guard).

Important Files Changed

Filename Overview
plugins/softlight/skills/softlight/workflows/generate_prd.py PRD now written to /tmp/softlight-prds/<project_id>/prd.md and its path stored in project.spec; previously-flagged temp-dir persistence issue remains unresolved.
plugins/softlight/skills/softlight/workflows/edit_prd.py New workflow that rewrites one PRD decision section; passes decisions to Claude without checking status == resolved (previously flagged), and relies on the temp PRD file still existing.
plugins/softlight/skills/softlight/workflows/finalize_initial_prototype.py New workflow; _read_prd_path silently falls back to treating a stale temp-file path string as spec content (previously flagged); otherwise correctly wraps core call in try/except BaseException with slot error reporting.
plugins/softlight/skills/softlight/workflows/generate_initial_prototype.py Redesigned to generate a single baseline clone using os.getcwd() as source_code_dir; _description_for_prototype always returns Baseline clone regardless of its conversations argument (dead ternary); generate_initial_prototype workflow lacks try/except error reporting to the slot (previously flagged).
plugins/softlight/skills/softlight/workflows/generate_sketches.py Extracts sketch logic from generate_decisions.py; DECISION_ITEM_SCHEMA is exported but never referenced by _DECISION_PLAN_SCHEMA (previously flagged; prd_anchor always empty).
plugins/softlight/skills/softlight/workflows/generate_decisions.py Refactored to delegate sketch/decision helpers to generate_sketches.py; _DECISION_PLAN_SCHEMA still lacks prd_anchor so every stored decision has prd_anchor: '' (previously flagged).
plugins/softlight/skills/softlight/scripts/call_claude.py Adds atomic session-ID persistence to /tmp/softlight-claude-sessions/<project_id>.json using a UUID-named temp file + os.replace; load/save are both called under config.lock preventing races.
plugins/softlight/skills/softlight/workflows/context.py New shared utility module; consolidates decision_text_only, decisions_text_only, session-ID helpers, and transcript_conversations that were previously duplicated across modules.
plugins/softlight/skills/softlight/workflows/generate_initial_prototypes.py Simplified from 3-slot parallel generation to a single baseline clone; now wraps generate_initial_prototype_slot in try/except with slot error reporting, which the singular workflow still lacks.
plugins/softlight/skills/softlight/workflows/edit_prototypes.py Minor change: both _edit_canvas_context and _project_context now strip sketch HTML via decisions_text_only before forwarding decisions to Claude.

Sequence Diagram

sequenceDiagram
    participant PM
    participant generate_prd
    participant edit_prd
    participant finalize_initial_prototype
    participant TmpFS as /tmp (PRD file)
    participant Claude

    PM->>generate_prd: trigger
    generate_prd->>Claude: generate_prd_spec (conversations + decisions)
    Claude-->>generate_prd: PRD markdown
    generate_prd->>TmpFS: write_project_prd → prd.md
    generate_prd-->>PM: "project_updated (spec = /tmp/.../prd.md)"

    PM->>edit_prd: trigger (decision_id)
    edit_prd->>TmpFS: read prd.md path from project.spec
    edit_prd->>Claude: _edit_prd_call (prd_file_path, decisions, hint)
    Claude->>TmpFS: Read + Edit prd.md directly
    Claude-->>edit_prd: confirmation
    edit_prd-->>PM: "project_updated (spec = same path)"

    PM->>finalize_initial_prototype: trigger (specPath / prototypeDir)
    finalize_initial_prototype->>TmpFS: _read_prd_path
    finalize_initial_prototype->>Claude: _edit_final_prototype_app
    Claude-->>finalize_initial_prototype: summary
    finalize_initial_prototype-->>PM: slot_updated (iframe prototype)
Loading

Comments Outside Diff (2)

  1. plugins/softlight/skills/softlight/workflows/generate_decisions.py, line 30-68 (link)

    P1 prd_anchor will always be an empty string

    build_decision() reads raw_decision.get("prd_anchor") and stores it on every decision, but _DECISION_PLAN_SCHEMA (the schema enforced on the Claude call in _generate_decision_plan) does not include prd_anchor and has "additionalProperties": False. The model can never return this field; it is silently discarded. Every stored decision will carry "prd_anchor": "", making the anchor feature inoperative — edit_prd locates sections only by the heading shape ### Decision <id>: <open_question> and never falls back to the anchor. To activate it, prd_anchor must be added to _DECISION_PLAN_SCHEMA.properties.decisions.items and the model prompt must ask for it.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: plugins/softlight/skills/softlight/workflows/generate_decisions.py
    Line: 30-68
    
    Comment:
    **`prd_anchor` will always be an empty string**
    
    `build_decision()` reads `raw_decision.get("prd_anchor")` and stores it on every decision, but `_DECISION_PLAN_SCHEMA` (the schema enforced on the Claude call in `_generate_decision_plan`) does not include `prd_anchor` and has `"additionalProperties": False`. The model can never return this field; it is silently discarded. Every stored decision will carry `"prd_anchor": ""`, making the anchor feature inoperative — `edit_prd` locates sections only by the heading shape `### Decision <id>: <open_question>` and never falls back to the anchor. To activate it, `prd_anchor` must be added to `_DECISION_PLAN_SCHEMA.properties.decisions.items` and the model prompt must ask for it.
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. plugins/softlight/skills/softlight/workflows/generate_sketches.py, line 852-888 (link)

    P2 DECISION_ITEM_SCHEMA is defined but never imported or used

    DECISION_ITEM_SCHEMA is exported from this module but is not imported by generate_decisions.py, edit_prd.py, or any other file touched by this PR. It appears intended as the per-item schema for _DECISION_PLAN_SCHEMA, but that schema still defines its own inline item shape (without prd_anchor). Either wire it in or remove it to avoid confusion about the authoritative decision schema.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: plugins/softlight/skills/softlight/workflows/generate_sketches.py
    Line: 852-888
    
    Comment:
    **`DECISION_ITEM_SCHEMA` is defined but never imported or used**
    
    `DECISION_ITEM_SCHEMA` is exported from this module but is not imported by `generate_decisions.py`, `edit_prd.py`, or any other file touched by this PR. It appears intended as the per-item schema for `_DECISION_PLAN_SCHEMA`, but that schema still defines its own inline item shape (without `prd_anchor`). Either wire it in or remove it to avoid confusion about the authoritative decision schema.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
plugins/softlight/skills/softlight/workflows/generate_initial_prototype.py:232-236
Both branches of the ternary return the exact same string, so the `conversations` parameter has no effect. The caption slot will always show "Baseline clone" regardless of whether conversation context exists. The old `generate_initial_prototypes.py` had elaborate caption-derivation logic; this looks like an incomplete simplification.

```suggestion
def _description_for_prototype(
    *,
    conversations: list[dict[str, Any]],
) -> str:
    return "Baseline clone"
```

Reviews (5): Last reviewed commit: "initial clone" | Re-trigger Greptile

Comment on lines +36 to +37
def project_prd_path(config: Config) -> pathlib.Path:
return pathlib.Path(tempfile.gettempdir()) / "softlight-prds" / config.project_id / "prd.md"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 PRD written to temp directory — lost on system restart

project_prd_path stores the PRD under tempfile.gettempdir() (typically /tmp on Linux), which is cleared on reboot. The project's spec field now persists this path, not the content. After a system restart, edit_prd will hit prd_path.is_file() == False and raise ValueError("edit-prd expected project spec to be a PRD file path, got ..."), making the edit workflow permanently broken for that project without regenerating the PRD.

Suggested change
def project_prd_path(config: Config) -> pathlib.Path:
return pathlib.Path(tempfile.gettempdir()) / "softlight-prds" / config.project_id / "prd.md"
def project_prd_path(config: Config) -> pathlib.Path:
return pathlib.Path(config.project_dir) / ".softlight" / "prd.md"
Prompt To Fix With AI
This is a comment left during a code review.
Path: plugins/softlight/skills/softlight/workflows/generate_prd.py
Line: 36-37

Comment:
**PRD written to temp directory — lost on system restart**

`project_prd_path` stores the PRD under `tempfile.gettempdir()` (typically `/tmp` on Linux), which is cleared on reboot. The project's `spec` field now persists this path, not the content. After a system restart, `edit_prd` will hit `prd_path.is_file() == False` and raise `ValueError("edit-prd expected project spec to be a PRD file path, got ...")`, making the edit workflow permanently broken for that project without regenerating the PRD.

```suggestion
def project_prd_path(config: Config) -> pathlib.Path:
    return pathlib.Path(config.project_dir) / ".softlight" / "prd.md"
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +157 to +170
resolved = _find_decision(decisions, decision_id)
other_decisions = [decision for decision in decisions if decision is not resolved]
transcript = conversation_transcript(project)
screenshots = conversation_screenshots(project)

_edit_prd_call(
config=config,
prd_file_path=str(prd_path),
resolved_decision=resolved,
other_decisions=other_decisions,
transcript=transcript,
screenshots=screenshots,
session_id=f"generate_prd:{run_id}",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 edit_prd passes an unresolved decision to Claude without guarding

_find_decision returns any decision by ID regardless of its status. The model prompt asserts "One decision has just been resolved" and instructs Claude to "choose the most consistent interpretation and proceed" when the resolution is ambiguous. If edit_prd is invoked before a decision is actually resolved (no resolved_text, status still "pending"), Claude will synthesise a plausible-sounding but fabricated resolution and rewrite that PRD section, silently corrupting the document with no error raised.

Prompt To Fix With AI
This is a comment left during a code review.
Path: plugins/softlight/skills/softlight/workflows/edit_prd.py
Line: 157-170

Comment:
**`edit_prd` passes an unresolved decision to Claude without guarding**

`_find_decision` returns any decision by ID regardless of its `status`. The model prompt asserts "One decision has just been resolved" and instructs Claude to "choose the most consistent interpretation and proceed" when the resolution is ambiguous. If `edit_prd` is invoked before a decision is actually resolved (no `resolved_text`, `status` still `"pending"`), Claude will synthesise a plausible-sounding but fabricated resolution and rewrite that PRD section, silently corrupting the document with no error raised.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +99 to +101
spec_text = project_spec
path = write_project_prd(config=config, spec=spec_text)
return path, spec_text

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 After this PR, project.spec always holds a file path (written by generate_prd), not raw spec text. If that temp file was deleted (reboot, /tmp purge), path.is_file() returns False and the fallback treats the path string itself as spec content — writing e.g. /tmp/softlight-prds/abc/prd.md as the body of a new PRD file. Claude then receives a one-line "PRD" that is just a path string and produces a meaningless prototype. The same bug exists in finalize_initial_prototype.py at lines 99-101. The fallback should raise rather than silently continue with corrupt content.

Suggested change
spec_text = project_spec
path = write_project_prd(config=config, spec=spec_text)
return path, spec_text
raise ValueError(
f"finalize_prototype PRD file no longer exists at {project_spec!r}; "
"re-run generate-prd to regenerate it",
)
Prompt To Fix With AI
This is a comment left during a code review.
Path: plugins/softlight/skills/softlight/workflows/finalize_prototype.py
Line: 99-101

Comment:
After this PR, `project.spec` always holds a file path (written by `generate_prd`), not raw spec text. If that temp file was deleted (reboot, `/tmp` purge), `path.is_file()` returns `False` and the fallback treats the path string itself as spec content — writing e.g. `/tmp/softlight-prds/abc/prd.md` as the body of a new PRD file. Claude then receives a one-line "PRD" that is just a path string and produces a meaningless prototype. The same bug exists in `finalize_initial_prototype.py` at lines 99-101. The fallback should raise rather than silently continue with corrupt content.

```suggestion
        raise ValueError(
            f"finalize_prototype PRD file no longer exists at {project_spec!r}; "
            "re-run generate-prd to regenerate it",
        )
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +99 to +103
spec_text = project_spec
path = write_project_prd(config=config, spec=spec_text)
return path, spec_text

raise ValueError("finalize_initial_prototype requires a final PRD file path or project spec")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Same fallback bug as in finalize_prototype.py: when project.spec holds a temp-file path that no longer exists, spec_text captures the path string itself and write_project_prd writes it as PRD content, silently producing a degenerate one-line spec. Raise an explicit error instead so callers know to re-run generate-prd.

Suggested change
spec_text = project_spec
path = write_project_prd(config=config, spec=spec_text)
return path, spec_text
raise ValueError("finalize_initial_prototype requires a final PRD file path or project spec")
raise ValueError(
f"finalize_initial_prototype PRD file no longer exists at {project_spec!r}; "
"re-run generate-prd to regenerate it",
)
raise ValueError("finalize_initial_prototype requires a final PRD file path or project spec")
Prompt To Fix With AI
This is a comment left during a code review.
Path: plugins/softlight/skills/softlight/workflows/finalize_initial_prototype.py
Line: 99-103

Comment:
Same fallback bug as in `finalize_prototype.py`: when `project.spec` holds a temp-file path that no longer exists, `spec_text` captures the path string itself and `write_project_prd` writes it as PRD content, silently producing a degenerate one-line spec. Raise an explicit error instead so callers know to re-run `generate-prd`.

```suggestion
        raise ValueError(
            f"finalize_initial_prototype PRD file no longer exists at {project_spec!r}; "
            "re-run generate-prd to regenerate it",
        )

    raise ValueError("finalize_initial_prototype requires a final PRD file path or project spec")
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +380 to +388
generate_initial_prototype_slot(
caption_slot_id=caption_slot_id,
config=config,
conversations=project.get("conversations", []),
run_id=run_id,
session_id=design_session_id(run_id),
slot_id=slot_id,
spec=spec,
spec_path=spec_path,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Missing slot error reporting on failure

finalize_prototype and finalize_initial_prototype both wrap their core call in try/except BaseException and call _post_slot_error so the UI slot shows an error state when the workflow fails. generate_initial_prototype calls generate_initial_prototype_slot with no such guard. If the prototype build fails (e.g., run_app or call_mcp raises), the create_exploration slot is silently left with no content or error indicator. The @workflow() decorator only handles retries/re-raise — it does not call _post_slot_error.

Prompt To Fix With AI
This is a comment left during a code review.
Path: plugins/softlight/skills/softlight/workflows/generate_initial_prototype.py
Line: 380-388

Comment:
**Missing slot error reporting on failure**

`finalize_prototype` and `finalize_initial_prototype` both wrap their core call in `try/except BaseException` and call `_post_slot_error` so the UI slot shows an error state when the workflow fails. `generate_initial_prototype` calls `generate_initial_prototype_slot` with no such guard. If the prototype build fails (e.g., `run_app` or `call_mcp` raises), the `create_exploration` slot is silently left with no content or error indicator. The `@workflow()` decorator only handles retries/re-raise — it does not call `_post_slot_error`.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants