ExecutionPlanCompiler treated the plan's single 'produces' string as a
registry kind id, while the architect prompt described it as a unique
artifact id referenced by needs/edges — the model followed the prompt,
invented descriptive ids (files_created), and every freestyle plan
failed to compile. Collapsing both onto one string is also unsound:
two stages producing the same kind would collide on slot name and make
artifact_validated edge conditions ambiguous.
Plan stages now carry an optional 'kind' selecting the registered kind
(mirroring TOML's produces = { name, kind }); 'produces' stays the
unique slot name. Missing 'kind' falls back to the old produces-as-kind
reading so existing plans still compile. Vocabulary entry, architect
prompt, and execution_plan schemas updated to match.
qa_ping is a minimal single-stage file_write workflow used for live QA smoke
runs (writes 'pong' into the qa/ scratch repo). The qa/ workspace itself is a
nested git repo and stays untracked; the compiled tui-go binary is ignored.
Add docs/schemas/execution_plan.json (goal/stages/edges), the
architect_freestyle prompt that instructs emitting the execution pipeline as
JSON, and register the execution_plan llm-emitted kind in both
artifacts.config.toml and sample-config.toml. Validated via
ExecutionPlanSchemaValidationTest (minimal plan passes; missing stages rejected).
- LlamaCppInferenceProvider: check HTTP status and surface the real error body instead of masking it as a ChatCompletionResponse deserialization failure
- PromptRenderer: render the live conversation layer (L1) last so the user turn is the final message (fixes Qwen 'No user query found' 500 when L3 recall is present)
- TomlWorkflowLoader: resolve stage prompts relative to the workflow file's own dir (bundle), CWD-independent; config-dir fallback for globals
- SessionOrchestrator: hard-fail a stage whose declared prompt can't resolve (was a silent user-less request)
- move healthcheck prompts next to the example workflow (examples/workflows/prompts/)