[Canonical page](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/suggest-options/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# SuggestOptions

Options passed to [`Project::suggest_assignments`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#suggest_assignments>). `SuggestOptions::default()` targets empty slots only, fixes no assignment, adds no new-resource penalty, scores the scheduled stage, allows one rebalance pass, keeps stored leveling delays and skips the baseline check. Override single fields with struct update syntax.

## Declaration

```rust
#[derive(Clone, Debug)]
pub struct SuggestOptions {
    pub baseline_id: Option<String>,
    pub targets: Vec<AssignTarget>,
    pub fixed: Vec<Id>,
    pub new_resource_penalty: f64,
    pub level: Option<LevelingOptions>,
    pub passes: u32,
    pub clear_first: bool,
}

impl Default for SuggestOptions
```

## Fields

| Field | Type | Default | Description |
|---|---|---|---|
| `baseline_id` | `Option<String>` | `None` | Expected baseline token. `Some` fails the call with [`ProjectError::StaleBaseline`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/project-error.md>) unless it names the current baseline. Take it from the latest [`ScheduleResult::baseline_id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/schedule-result.md>). |
| `targets` | `Vec<`[`AssignTarget`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/assign-target.md>)`>` | `vec![AssignTarget::Empty]` | Slot categories to act on, in any combination. An empty `Vec` changes no assignment and only reports [`SuggestResult::invalid`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/suggest-result.md>). A category listed twice fails with [`Error::Input`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>) at path `targets[i]`. |
| `fixed` | `Vec<`[`Id`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/id.md>)`>` | empty | Assignment ids that are never changed. A slot bound to one of them is never visited; its resource still counts as in use, and the slot is still reported in `invalid` when broken. An unknown, inactive or repeated id fails with [`Error::Input`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>) at path `fixed[i]`. An id bound to no slot is accepted. |
| `new_resource_penalty` | `f64` | `0.0` | Cost added per counted resource in use that the reference state doesn't use. `0.0` scores pure balance; a large value favors the fewest people. Included in [`SuggestProposal::cost`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/suggest-proposal.md>) and [`StepCost`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/step-cost.md>). A negative or non-finite value fails with [`Error::Input`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>). |
| `level` | `Option<`[`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-options.md>)`>` | `None` | `Some` levels every candidate with these options and scores the leveled stage; it also fills [`SuggestProposal::leveled`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/suggest-proposal.md>). `None` scores the scheduled stage. Options that are invalid for the accepted state fail with [`Error::Input`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>). |
| `passes` | `u32` | `1` | Maximum number of rebalance passes over [`AssignTarget::Valid`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/assign-target.md>) slots. Has no effect unless `targets` contains `Valid`. `0` fails with [`Error::Input`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>). |
| `clear_first` | `bool` | `false` | `true` builds and measures the proposal on a copy of the accepted state with `leveling_delay` and [`pauses`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/pause.md>) cleared on in-scope tasks. See [`clear_first`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/suggest-options.md#clear_first>). |

### clear_first

The scope is `level.scope.tasks` when `level` sets it, otherwise every task, also when `level` is `None`.

- [`SuggestResult::changes`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/suggest-result.md#changes>) gets one task update `{id, leveling_delay: 0, pauses: []}` per cleared task, ahead of the assignment edits. The clears are returned whenever something was cleared, also with `targets: vec![]` or no slots.
- `SuggestResult::baseline` and `SuggestResult::proposed` describe the cleared state.
- It's independent of [`LevelingOptions::clear_first`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-options.md#clear_first>), so it also applies to scheduled-stage scoring.
- It adds no errors: validation, `fixed` and slot states are checked against the accepted state.
- When nothing in scope has a delay or pause, the output is identical to `clear_first: false`.

For how targets, passes and the penalty drive the search, see [Suggesting assignments](<https://docs.dhtmlx.com/planning-engine/rust/resources-and-assignment/suggesting-assignments.md>).

## Example

```rust
use plen_core::{
    AssignTarget, DateTime, Project, ProjectData, ResourceData, Slot, SolveOptions,
    SuggestOptions, TaskData,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 8, 10, 8, 0).ok_or("invalid date")?;
    let mut tasks = Vec::new();
    for id in ["A", "B"] {
        let mut task = TaskData::new(id);
        task.start_date = Some(monday);
        task.duration = Some(2.0);
        tasks.push(task);
    }
    let resource = |id: &str| ResourceData { id: id.into(), capacity: None, calendar_id: None };

    let mut project = Project::default();
    let solved = project.solve(
        Some(ProjectData {
            tasks,
            resources: vec![resource("dev1"), resource("dev2")],
            ..Default::default()
        }),
        &SolveOptions::default(),
    )?;

    let slots = [
        Slot::new("A#1", "A", vec!["dev1".into(), "dev2".into()]),
        Slot::new("B#1", "B", vec!["dev1".into(), "dev2".into()]),
    ];
    let options = SuggestOptions {
        baseline_id: solved.baseline_id.clone(),
        targets: vec![AssignTarget::Empty, AssignTarget::Broken, AssignTarget::Valid],
        new_resource_penalty: 0.5,
        passes: 2,
        ..SuggestOptions::default()
    };
    let result = project.suggest_assignments(&slots, &options)?;
    println!("unfilled {:?}, cost {}", result.unfilled, result.proposed.cost);

    project.apply(&result.changes)?;
    Ok(())
}
```

## Related

- [`AssignTarget`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/assign-target.md>) - the slot categories listed in `targets`
- [`SuggestResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/suggest/suggest-result.md>) - the proposal the call returns with these options
- [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-options.md>) - the options type taken by `level`
- [`EvaluateOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/evaluate-options.md>) - the counterpart options for scoring hand-built candidates
- [Suggesting assignments](<https://docs.dhtmlx.com/planning-engine/rust/resources-and-assignment/suggesting-assignments.md#options>) - shows rebalancing, fixing, repairing and leveled scoring with these options
