---
title: <Aspects>
description: Propagate token and latency budgets to descendant tasks.
---

```ts
import { Aspects } from "smithers-orchestrator";

type TokenBudgetConfig = {
  max: number;
  perTask?: number;
  onExceeded?: "fail" | "warn" | "skip-remaining"; // default "fail"
};

type LatencySloConfig = {
  maxMs: number;
  perTask?: number;
  onExceeded?: "fail" | "warn"; // default "fail"
};

type TrackingConfig = { tokens?: boolean; latency?: boolean };

type AspectsProps = {
  tokenBudget?: TokenBudgetConfig;
  latencySlo?: LatencySloConfig;
  tracking?: TrackingConfig; // default all true
  children?: ReactNode;
};
```

```tsx
<Workflow name="budgeted-workflow">
  <Aspects
    tokenBudget={{ max: 100_000, perTask: 25_000, onExceeded: "warn" }}
    latencySlo={{ maxMs: 30_000, onExceeded: "fail" }}
  >
    <Task id="analyze" output={outputs.analysis} agent={codeAgent}>
      Analyze the repository.
    </Task>
    <Task id="review" output={outputs.review} agent={reviewAgent}>
      Review the analysis.
    </Task>
  </Aspects>
</Workflow>
```

## Notes

- Nested `<Aspects>` inherit outer budget configs wholesale. If an inner `<Aspects>` sets `tokenBudget` or `latencySlo`, that field's entire parent config object is replaced (no per-field merge). The `tracking` config is the exception: `tokens` and `latency` each fall back to the parent value independently.
- Budgets enforce at task-dispatch time. Before each descendant task runs, the engine compares the run's accumulated token total (`tokenBudget.max`) and wall-clock since the run started (`latencySlo.maxMs`) against the budget and applies `onExceeded`: `fail` raises `ASPECT_BUDGET_EXCEEDED` and fails the run, `warn` logs and continues, `skip-remaining` skips the task. The per-task limits (`perTask`) are not enforced yet.
- Budgets enforce regardless of `tracking`; `tracking` controls metric emission only.
- Accumulated token usage is per run and survives resume (re-seeded from persisted token-usage events).
