# car-builder

Natural-language → validated [`car-workflow`](../car-workflow) manifest builder
for the Common Agent Runtime.

Describe what you want in plain English; the builder prompts a model to emit a
workflow manifest, **validates it with the runtime verifier**
(`car_workflow::verify_workflow`) instead of trusting the model, and feeds the
concrete validation errors back for a bounded number of repair attempts.

## Design: generation is injected

`build_workflow` is generic over an async `generate(prompt) -> text` closure, so
this crate has **no inference dependency**. The CLI / server / FFI wire the real
`car-inference` engine; tests inject a fake generator. The reusable,
deterministic part — prompt → parse → verify → repair-loop — is unit-tested
without a model.

```rust,no_run
use car_builder::{build_workflow, BuildRequest, ToolCatalog};

# async fn ex() {
let req = BuildRequest {
    goal: "research a stock, then have a human approve the summary".into(),
    catalog: ToolCatalog::default(),
    existing: None,        // Some(workflow) to edit instead of create
    feedback: None,        // human revision feedback from an approve/revise loop
    max_attempts: 3,
};

let result = build_workflow(|prompt| async move {
    // call your model and return its text
    your_model.generate(prompt).await
}, &req).await;

if result.valid {
    // result.workflow is a verified car_workflow::Workflow — save or run it
}
# }
```

## What it guarantees

- The returned workflow (when `valid`) passes `verify_workflow`: reachable
  stages, no dangling edge/compensation references, approval gates with a
  non-empty `output_key`, and proposal stages that pass `car-verify`. When a
  catalog of tools is supplied, it also references only known tool names.
  Semantic findings — edge-condition keys and state dependencies that no stage
  produces — are returned as non-blocking `warnings` (and fed back as repair
  hints); they don't flip `valid`, since they can false-positive on keys
  produced at runtime.
- Output parsing tolerates markdown fences, preamble, and trailing commas via
  `car_ir::json_extract`, and surfaces serde's error (e.g. the missing field)
  back to the repair loop.
- On failure after `max_attempts`, the last parseable-but-invalid workflow and
  the remaining issues are returned for inspection.

## CLI

```bash
car build "research a stock, then have a human approve the summary"
car build --update ~/.car/workflows/foo.json "add a verification stage before approval"
```

The CLI generates, validates, prints a summary, and (unless `--yes`) offers an
approve / revise / no loop before saving to `~/.car/workflows/<id>.json`.
