Index
strands_teams ¶
strands_teams — a domain-agnostic agent-teams framework on strands-agents.
This package hosts the generic team-dispatch, findings, artifact, scoring, hook, display, and UseCase-contract machinery shared across use cases. Concrete implementations (e.g. codebase analysis) live in separate workspace packages.
NO_CURRENT_REVISION module-attribute ¶
Sentinel expected_current_revision meaning "this logical_name has no current revision yet".
A first promotion of a logical_name passes this sentinel as expected_current_revision (spec 005 AC-2-4). It is deliberately a value no real revision_id (a hex content hash) can collide with.
Disposition module-attribute ¶
Disposition = Literal[
"open",
"acknowledged",
"remediated",
"accepted_risk",
"rejected",
"superseded",
]
Lifecycle states a finding moves through as it is triaged and resolved.
EpistemicStatus module-attribute ¶
EpistemicStatus = Literal[
"observed",
"inferred",
"hypothesized",
"disputed",
"accepted",
"rejected",
"superseded",
]
The epistemic standing of a TeamEvent's claim (AC-1-2).
observed— a directly recorded fact (e.g. a dispatch completed).inferred— derived from other events without direct observation.hypothesized— a tentative claim awaiting confirmation.disputed— contradicted by another event/actor.accepted/rejected— an adjudicated outcome.superseded— replaced by a later event (retained in the log, never deleted).
EvidenceType module-attribute ¶
Kinds of evidence a finding can cite (file:line, a test, a command exit, an artifact revision, a URL, or a log excerpt).
GateName module-attribute ¶
GateName = Literal[
"capability",
"separation_of_duties",
"required_approvals",
"open_blocking_finding",
"human_required",
]
The ordered gate stack the PolicyEngine runs; the name of the gate that failed is reported on a denying :class:PolicyVerdict (AC-3-1).
HumanDecisionStatus module-attribute ¶
Lifecycle of a :class:HumanDecision gate.
pending— awaiting a human; the runner suspends the transition (AC-4-3).resolved— approved by a human; the runner resumes and re-authorizes (AC-4-4).rejected— declined by a human; the runner abandons the transition (AC-4-6).
Severity module-attribute ¶
Ordered severity levels for a finding.
DEFAULT_NARRATIVE_RUBRIC module-attribute ¶
DEFAULT_NARRATIVE_RUBRIC = NarrativeRubric(
dimensions=(
RubricDimension(
name="specificity",
pattern=FILE_LINE_PATTERN,
thresholds=(
(0, 1.0),
(5, 2.0),
(10, 3.0),
(20, 4.0),
(30, 5.0),
),
suggestion="Add more file:line references (currently {count}).",
),
RubricDimension(
name="structure",
pattern=HEADING_PATTERN,
flags=re.MULTILINE,
thresholds=(
(0, 1.0),
(3, 2.0),
(5, 3.0),
(8, 4.0),
(11, 5.0),
),
suggestion="Add more section headings for structure (currently {count}).",
),
RubricDimension(
name="diagrams",
pattern=MERMAID_PATTERN,
flags=re.IGNORECASE,
thresholds=((0, 1.0), (1, 3.0), (2, 5.0)),
suggestion="Add at least one mermaid diagram for call flow or architecture.",
weak_score=1.0,
),
RubricDimension(
name="depth",
counter=count_lines,
thresholds=(
(0, 1.0),
(20, 2.0),
(50, 3.0),
(100, 4.0),
(200, 5.0),
),
suggestion="Expand content depth (currently {count} lines).",
),
RubricDimension(
name="cross_references",
pattern=FILE_PATH_PATTERN,
unique=True,
thresholds=(
(0, 1.0),
(3, 2.0),
(8, 3.0),
(15, 4.0),
(25, 5.0),
),
suggestion="Cross-reference more files/modules (currently {count} unique paths).",
),
)
)
The default five-dimension narrative rubric (revision threshold 3.5).
SpecialistDisposition module-attribute ¶
How a specialist harness run concluded.
completed— the harness finished its task successfully.partial— the harness ran to a limit (e.g. max turns) with usable but incomplete work.failed— the harness errored, timed out, or exceeded its budget without a usable result.refused— the harness declined the task (e.g. a safety refusal).
TEAM_TOOLS module-attribute ¶
TEAM_TOOLS = (
dispatch_team,
read_team_findings,
write_artifact,
score_narrative,
enrich_artifact,
)
The five coordinator team tools, in canonical order (consumed by the factory).
AsyncioDurableEngine ¶
In-process asyncio :class:DurableStep engine (AC-4-2..AC-4-5).
Runs each step's callable in the current event loop, emitting a result :class:~strands_teams.models.TeamEvent to the bound :class:~strands_teams.events.EventLog before returning (AC-4-3). Before running, it scans the log for an existing result event whose payload names the same step_id; if found, it returns that recorded result without re-running the callable — idempotent replay (AC-4-4). It never calls asyncio.run and awaits (rather than blocks on) its callables, so it is safe inside an already-running strands runtime (AC-4-5; research-coding-runtimes.yaml line 18).
Bind the engine to the run's :class:~strands_teams.events.EventLog.
Source code in packages/strands-teams/src/strands_teams/durable.py
run_step async ¶
run_step(
step_id,
step_type,
fn,
*,
goal_id="",
task_id="",
thread_id="",
actor="lead",
causal_parents=None,
)
Execute (or replay) one durable step (AC-4-3, AC-4-4, AC-4-5).
If a result event for step_id already exists in the log, returns it without re-running fn (idempotent replay, AC-4-4). Otherwise awaits fn (which may be sync or async — an async callable is awaited, a sync one is called directly; neither blocks the loop via asyncio.run, AC-4-5), emits a step.result :class:~strands_teams.models.TeamEvent recording the transition and result to the log (AC-4-3), and returns the fresh :class:StepResult.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
step_id | str | Stable idempotency key for the step within the goal run. | required |
step_type | str | The lead-loop transition (e.g. | required |
fn | Callable[[], Awaitable[dict[str, Any]] | dict[str, Any]] | A zero-arg callable producing the step's result payload dict; may be sync or async. | required |
goal_id | str | The goal this step belongs to. | '' |
task_id | str | The task this step belongs to. | '' |
thread_id | str | The thread this step belongs to. | '' |
actor | str | Identifier of the step's executor (defaults to | 'lead' |
causal_parents | list[str] | None |
| None |
Returns:
| Name | Type | Description |
|---|---|---|
A | StepResult | class: |
StepResult | event, else the freshly executed result. |
Source code in packages/strands-teams/src/strands_teams/durable.py
DurableStep ¶
Bases: Protocol
Engine-agnostic contract for executing one lead-loop transition (AC-4-1).
An implementation drives one durable step to completion and records its outcome as a :class:~strands_teams.models.TeamEvent so the step is replayable. The in-process :class:AsyncioDurableEngine satisfies this today; a Temporal or Restate worker can implement the same method later without changing run_goal's call sites (plan §4 Phase 5; AC-4-1). A runtime_checkable Protocol checks method presence only.
run_step async ¶
run_step(
step_id,
step_type,
fn,
*,
goal_id="",
task_id="",
thread_id="",
actor="lead",
causal_parents=None,
)
Execute one step and record its transition result; return the outcome.
Source code in packages/strands-teams/src/strands_teams/durable.py
StepResult ¶
Bases: FrozenModel
The recorded outcome of one durable step (AC-4-3, AC-4-4).
Attributes:
| Name | Type | Description |
|---|---|---|
step_id | str | Stable idempotency key for the step within a goal run — a step re-executed during replay with a matching recorded result is not re-run (AC-4-4). |
step_type | str | The lead-loop transition this step performed (e.g. |
payload | dict[str, Any] | The structured result of the step (no transcript/CoT). |
replayed | bool | True when this result was returned from a prior recorded event rather than freshly executed (AC-4-4). |
EventLog ¶
An append-only, replayable log of :class:~strands_teams.models.TeamEvent.
Bound to a single file path (resolved from :meth:~strands_teams.layout.TeamsLayout.event_log_path), writing one JSON-encoded event per line (AC-2-1). The API is deliberately append + read only — there is no update or delete method — so an already-written event is immutable (AC-2-5). Supersession is expressed by appending a new event, never by editing an old line (AC-3-4).
Bind the log to path (created lazily on first :meth:append).
Source code in packages/strands-teams/src/strands_teams/events.py
append ¶
Append exactly one JSON line for event; never raise (AC-2-2, AC-2-4).
Serializes event to a single line via :meth:~pydantic.BaseModel.model_dump_json and appends it, leaving every previously written line byte-for-byte unchanged. An OSError (e.g. a read-only filesystem) is logged and swallowed so a log-write failure never kills the coordinator or the lead loop (AC-2-4), matching the never-raises contract of the pre-split _write_debug_entry (teams.py).
Source code in packages/strands-teams/src/strands_teams/events.py
read ¶
Parse and return every valid event, skipping malformed lines.
A malformed line is skipped; use :func:replay when you need the malformed-line warnings surfaced structurally (AC-3-5).
Source code in packages/strands-teams/src/strands_teams/events.py
read_with_warnings ¶
Return (events, warnings) — one warning per skipped malformed line.
ReplanDecision ¶
Bases: FrozenModel
The structured outcome of :func:should_replan (AC-6-1).
Attributes:
| Name | Type | Description |
|---|---|---|
replan | bool | Whether any replan trigger fired. |
triggers | list[str] | The distinct triggers that fired, in canonical order (empty when |
reasons | list[str] | Human-readable reason per fired trigger. |
ReplayState ¶
Bases: FrozenModel
The deterministic reconstruction produced by :func:replay (AC-3-1, AC-3-2).
Immutable. :meth:to_canonical_json yields a byte-stable serialization so two replays of the same log compare byte-for-byte identical (AC-3-2, AC-7-1).
Attributes:
| Name | Type | Description |
|---|---|---|
applied | list[str] |
|
transitions | list[str] |
|
artifacts | dict[str, str] |
|
findings | dict[str, dict[str, Any]] | Finding payloads reconstructed from finding-bearing events, keyed by |
decisions | dict[str, dict[str, Any]] | Decision payloads reconstructed from decision-bearing events, keyed by |
superseded | list[str] |
|
warnings | list[str] | One entry per malformed log line skipped during replay (AC-3-5). |
to_canonical_json ¶
Return a byte-stable JSON serialization for cross-replay equality (AC-3-2).
EvidenceGateResult ¶
Bases: FrozenModel
Outcome of running the evidence gate over one or more findings.
Attributes:
| Name | Type | Description |
|---|---|---|
passed | bool | True when no |
flagged | list[str] | Statements of the |
checked | int | Total number of findings evaluated. |
GoalResult ¶
Bases: FrozenModel
The terminal outcome of a :func:run_goal run (AC-5-6).
Attributes:
| Name | Type | Description |
|---|---|---|
goal_id | str | The goal this run drove. |
status | str | Terminal status — |
iterations | int | How many lead-loop iterations executed. |
replans | int | How many times the loop re-entered decompose via |
event_log_path | str | The path the run's :class: |
transitions | list[str] | The ordered |
TeamsLayout dataclass ¶
TeamsLayout(
output_root,
artifact_prefix="BUNDLE",
artifact_suffix=".md",
artifacts_subdir="bundles",
teams_subdir="teams",
scratch_subdir="tmp",
findings_name="findings.md",
findings_json_name="findings.json",
contract_name="contract.json",
metadata_name="metadata.json",
debug_log_name="team_debug.jsonl",
event_log_name="events.jsonl",
executive_summary_name="CONTEXT.md",
planning_sentinel_name="heuristic_summary.json",
revisions_subdir="revisions",
alias_name="aliases.json",
approvals_subdir="approvals",
human_gates_subdir="human_gates",
decision_log_name="decisions.jsonl",
)
Owns all artifact paths for a run, derived from one output root.
Every path-producing function in dispatch/read/write/quality code must call a method here rather than re-deriving a literal, so the naming scheme lives in exactly one place.
Attributes:
| Name | Type | Description |
|---|---|---|
output_root | Path | The run's output-directory root (e.g., |
artifact_prefix | str | Prefix for per-area artifact files ( |
artifact_suffix | str | Extension for artifact files (default |
artifacts_subdir | str | Subdirectory under the root holding per-area artifacts. |
teams_subdir | str | Subdirectory (under a scratch dir) holding per-team output. |
scratch_subdir | str | Scratch directory under the root for transient team data. |
findings_name | str | Per-team human findings filename. |
findings_json_name | str | Per-team typed-findings sidecar filename. |
contract_name | str | Per-team task-contract sidecar filename (authority, budget, acceptance criteria, input revisions). |
metadata_name | str | Per-team metadata filename. |
debug_log_name | str | Team-dispatch debug JSONL filename. |
event_log_name | str | Typed append-only event-plane JSONL filename (Phase 5 / spec 006), co-located with the team-debug log under the teams dir. |
executive_summary_name | str | Filename for the top-level executive summary. |
planning_sentinel_name | str | Filename for the planning-context sentinel produced by a deterministic pre-run step. |
revisions_subdir | str | Subdirectory under the root holding the content-addressed immutable revision store (per- |
alias_name | str | Filename of the mutable |
approvals_subdir | str | Subdirectory (under the scratch dir) holding the per- |
human_gates_subdir | str | Subdirectory (under the scratch dir) holding pending :class: |
decision_log_name | str | Filename of the append-only decision log — one JSON-encoded :class: |
teams_dir ¶
team_dir ¶
findings_path ¶
findings_json_path ¶
Path to a team's typed findings.json sidecar.
Resolves under the same per-team directory as :meth:findings_path, so the human markdown and the machine-readable typed findings live side by side (AC-2-2).
Source code in packages/strands-teams/src/strands_teams/layout.py
contract_path ¶
Path to a team's task-contract sidecar (contract.json).
Resolves under the same per-team directory as :meth:findings_path, so a team's granted authority, budget, acceptance criteria, and input revisions are persisted next to its findings and metadata (AC-2-6). The :class:~strands_teams.hooks.ArtifactQualityHook reads every team's acceptance_criteria from these files to evaluate criteria coverage.
Source code in packages/strands-teams/src/strands_teams/layout.py
contract_glob ¶
metadata_path ¶
debug_log_path ¶
event_log_path ¶
Path to the typed append-only event-plane JSONL (Phase 5 / spec 006).
Co-located with :meth:debug_log_path under the teams dir so the typed event plane supersedes the untyped team_debug.jsonl without moving the run's scratch layout (AC-2-1). One JSON-encoded :class:~strands_teams.models.TeamEvent per line.
Source code in packages/strands-teams/src/strands_teams/layout.py
artifacts_dir ¶
artifact_path ¶
Path to a per-area artifact file (e.g., bundles/BUNDLE.auth.md).
artifact_glob ¶
area_from_artifact ¶
Extract the area identifier from an artifact file path.
Inverse of :meth:artifact_path — strips the prefix/suffix so the quality hook can name a weak artifact by its area.
Source code in packages/strands-teams/src/strands_teams/layout.py
executive_summary_path ¶
planning_sentinel_path ¶
Path to the planning-context sentinel produced by the pre-run step.
revisions_dir ¶
Directory holding the content-addressed immutable revision store (AC-1-3).
revision_path ¶
Resolve the on-disk path for one (logical_name, revision_id) revision (AC-1-3).
Every revision of a logical artifact is grouped under a per-artifact subdirectory of :meth:revisions_dir, keyed by revision_id (which is content-addressed). This is the ONLY place a revision path is derived, so dispatch/read/write/promotion code never duplicates the literal (AC-1-3).
Source code in packages/strands-teams/src/strands_teams/layout.py
alias_path ¶
Path to the mutable logical_name -> current revision_id alias map (AC-2-1).
Resolved directly under output_root in the same manner as :meth:planning_sentinel_path — a single durable JSON file that is the only mutable pointer into the content-addressed revision store.
Source code in packages/strands-teams/src/strands_teams/layout.py
persist_revision ¶
Persist a revision to its content-addressed path and return it (AC-1-4, AC-1-5).
Writes the revision keyed by revision_id under :meth:revision_path so it is addressable by later reads (AC-1-4). Idempotent for an identical re-write (same revision_id and content_hash). If the same revision_id was already persisted with a DIFFERENT content_hash, the write is rejected with :class:RevisionConflictError and the stored revision is left unchanged (AC-1-5) — the store is append-only and content-addressed.
Returns:
| Type | Description |
|---|---|
ArtifactRevision | The stored :class: |
ArtifactRevision | the already-stored record on an idempotent re-write). |
Raises:
| Type | Description |
|---|---|
RevisionConflictError | If |
Source code in packages/strands-teams/src/strands_teams/layout.py
load_revision ¶
Load a persisted revision, or None when it is not in the store.
Source code in packages/strands-teams/src/strands_teams/layout.py
current_revision_id ¶
Return the revision_id the alias currently points logical_name at.
Returns the :data:~strands_teams.models.NO_CURRENT_REVISION sentinel when logical_name has no current revision (AC-2-4).
Source code in packages/strands-teams/src/strands_teams/layout.py
promote_revision ¶
Durably compare-and-set the alias for logical_name (AC-2-2..AC-2-5).
The compare-and-set is serialized by an OS advisory lock on the alias file, so two concurrent promotions of the same logical_name with the same expected_current_revision cannot both win: whichever acquires the lock first flips the alias, and the other observes the new current and is rejected with :class:StaleArtifactError (AC-2-5). Because the CAS is a durable operation against this on-disk store — not a mutation of the by-reference invocation_state dict — it is correct even when the callers share that dict read-only (research-coding-runtimes.yaml lines 22, 30).
On a matching CAS the proposed revision is persisted (content-addressed) with the prior current revision recorded in its supersedes lineage, and the alias is atomically flipped to it (AC-2-2). A first promotion passes the :data:~strands_teams.models.NO_CURRENT_REVISION sentinel as expected_current_revision and sets the alias as the first revision (AC-2-4).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logical_name | str | The logical artifact to promote. | required |
expected_current_revision | str | The revision the caller believes is current (the sentinel for a first promotion). | required |
proposed_revision | ArtifactRevision | The revision to make current. Its | required |
Returns:
| Type | Description |
|---|---|
ArtifactRevision | The persisted, now-current :class: |
ArtifactRevision | revision recorded in |
Raises:
| Type | Description |
|---|---|
StaleArtifactError | If |
RevisionConflictError | If persisting the proposed revision conflicts with an already-stored revision of the same id (AC-1-5). |
Source code in packages/strands-teams/src/strands_teams/layout.py
approvals_dir ¶
Directory holding the per-token_id :class:ApprovalToken store (AC-3-7).
approval_path ¶
Resolve the on-disk path for one approval token, keyed by token_id.
persist_approval ¶
Persist an :class:ApprovalToken to the approvals store and return it (AC-1-1).
Source code in packages/strands-teams/src/strands_teams/layout.py
load_approval ¶
Load one persisted approval token, or None when absent/unreadable.
Source code in packages/strands-teams/src/strands_teams/layout.py
load_approvals ¶
Load every persisted approval token (skipping any that fail to parse — AC-3-7).
Source code in packages/strands-teams/src/strands_teams/layout.py
decision_log_path ¶
Path to the append-only decision log — one :class:Decision per line (AC-2-4).
append_decision ¶
Append one :class:Decision to the decision log (AC-2-4).
Raises on I/O failure rather than swallowing it, so a transition can never proceed with its decision unrecorded (AC-2-5). The caller decides how to react; unlike the debug log, this path is auth-critical.
Raises:
| Type | Description |
|---|---|
OSError | If the decision line cannot be written. |
Source code in packages/strands-teams/src/strands_teams/layout.py
human_gates_dir ¶
Directory holding pending :class:HumanDecision gate sentinels (AC-4-3, AC-4-5).
human_gate_path ¶
Resolve the on-disk path for one human-gate sentinel, keyed by decision_id.
persist_human_gate ¶
Persist a :class:HumanDecision gate to disk and return it (AC-4-5).
A pending gate persisted here is what lets a swarm node return control rather than block past its node_timeout (AC-4-5): the gate survives on disk and the runner resumes from it later.
Source code in packages/strands-teams/src/strands_teams/layout.py
load_human_gate ¶
Load one persisted human-gate sentinel, or None when absent/unreadable.
Source code in packages/strands-teams/src/strands_teams/layout.py
load_pending_human_gates ¶
Load every human gate still pending (the runner suspends on these — AC-4-3).
Source code in packages/strands-teams/src/strands_teams/layout.py
ApprovalToken ¶
Bases: FrozenModel
A revision-bound, signed, expiring approval of a consequential transition (ASTR §14.7).
An approval names the exact :class:ArtifactRevision it approves — by both artifact_revision_id and the revision's immutable revision_content_hash captured at grant time (AC-1-2) — so it goes stale the moment the artifact changes (AC-5-1). Its signature is an HMAC over the canonical serialization of its identity fields (:func:approval_signing_payload), so a forged or tampered token fails :meth:signature_valid and the PolicyEngine treats it as absent (AC-1-4). Past valid_until the engine rejects it as expired (AC-1-5). invalidation_rules names the artifact facets whose change sunsets the approval (AC-5-2, AC-5-3).
Build one with :meth:mint so the signature is computed with the configured signing key; constructing directly is supported for round-tripping a persisted token.
Attributes:
| Name | Type | Description |
|---|---|---|
token_id | str | Unique identity of this approval (auto UUID hex when minted). |
approved_transition_kind | str | The transition |
artifact_revision_id | str | The |
revision_content_hash | str | The approved revision's |
approver | str | Principal who granted the approval (the separation-of-duties and required-approvals gates read this — AC-3-3, AC-3-4). |
granted_at | datetime | UTC timestamp the approval was minted. |
valid_until | datetime | UTC expiry; at or after it the token is expired (AC-1-5). |
signature | str | HMAC-SHA256 hex over :func: |
invalidation_rules | list[str] | Facet names whose change sunsets the approval (AC-5-2); empty means any change to the bound artifact invalidates it. |
mint classmethod ¶
mint(
*,
approved_transition_kind,
artifact_revision_id,
revision_content_hash,
approver,
signing_key,
valid_until=None,
valid_for=None,
invalidation_rules=None,
token_id=None,
granted_at=None,
)
Mint a signed :class:ApprovalToken over its canonical payload (AC-1-3).
Computes the HMAC signature with signing_key so the token verifies against the same key later (AC-1-4). Supply the expiry either as an absolute valid_until or a relative valid_for (added to granted_at); when neither is given the token is valid for 24 hours (AC-1-5).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
approved_transition_kind | str | The transition kind approved. | required |
artifact_revision_id | str | The approved revision's id. | required |
revision_content_hash | str | The approved revision's content hash (AC-1-2). | required |
approver | str | The approving principal. | required |
signing_key | str | The configured signing key (from | required |
valid_until | datetime | None | Absolute UTC expiry (wins over | None |
valid_for | timedelta | None | Relative validity window from | None |
invalidation_rules | list[str] | None | Facet names whose change sunsets the approval. | None |
token_id | str | None | Explicit id; defaults to a fresh UUID hex. | None |
granted_at | datetime | None | Explicit grant time; defaults to now. | None |
Returns:
| Type | Description |
|---|---|
ApprovalToken | A signed, frozen :class: |
Source code in packages/strands-teams/src/strands_teams/models.py
signing_payload ¶
Return this token's canonical signing payload (AC-1-3).
Source code in packages/strands-teams/src/strands_teams/models.py
signature_valid ¶
Return whether signature verifies against signing_key (AC-1-4).
Uses :func:hmac.compare_digest for a constant-time comparison so a signature check cannot be timing-attacked. A token whose signature does not verify is treated as absent by the PolicyEngine.
Source code in packages/strands-teams/src/strands_teams/models.py
is_expired ¶
Return whether the token is at or past its valid_until (AC-1-5).
ArtifactRevision ¶
Bases: FrozenModel
An immutable, content-addressed revision of one logical artifact (ASTR §4.8, §6.4).
A lightweight metadata record — not the artifact blob itself, which lives at the layout-resolved path. Immutable and extra="forbid" (inherited from :class:FrozenModel): any attempt to assign a field after construction raises a pydantic.ValidationError (AC-1-1). Build one with :meth:from_content so content_hash and per-facet hashes are computed deterministically from the content (AC-1-2); constructing directly is supported for round-tripping a persisted revision.
Attributes:
| Name | Type | Description |
|---|---|---|
artifact_id | str | Stable identity of the logical artifact across all its revisions (defaults to |
revision_id | str | Identity of this specific revision. Content-addressed: defaults to |
content_hash | str | Deterministic hash of the revision's content alone (AC-1-2). |
artifact_type | str | The kind of artifact (e.g. |
logical_name | str | The name the alias pointer maps to a current revision. |
produced_by | str | Identifier of the team/agent/runtime that produced it. |
parents | list[str] |
|
supersedes | list[str] |
|
classification | str | Handling classification (e.g. |
facets | dict[str, str] | Per-facet content hashes ( |
created_at | datetime | UTC creation timestamp (not part of |
from_content classmethod ¶
from_content(
*,
logical_name,
facets=None,
body=None,
artifact_type="artifact",
produced_by="",
artifact_id=None,
revision_id=None,
parents=None,
supersedes=None,
classification="internal",
created_at=None,
)
Build a revision from content, computing content_hash deterministically (AC-1-2).
Supply the content either as facets (a {facet_name: content} mapping, enabling facet-level semantic_diff) or as a single body string (wrapped as one "body" facet). content_hash and revision_id (which defaults to content_hash — content addressing) are derived from the content alone; artifact_id defaults to logical_name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logical_name | str | The logical artifact's name. | required |
facets | Mapping[str, str] | None | Facet-name to facet-content mapping. Mutually exclusive with | None |
body | str | None | A single-blob content string (wrapped as facet | None |
artifact_type | str | Kind of artifact. | 'artifact' |
produced_by | str | Producer identifier. | '' |
artifact_id | str | None | Stable logical identity; defaults to | None |
revision_id | str | None | Explicit revision id; defaults to | None |
parents | list[str] | None | Input revision ids. | None |
supersedes | list[str] | None | Superseded revision ids. | None |
classification | str | Handling classification. | 'internal' |
created_at | datetime | None | Explicit timestamp; defaults to now. | None |
Returns:
| Type | Description |
|---|---|
ArtifactRevision | A frozen :class: |
Source code in packages/strands-teams/src/strands_teams/models.py
AuthorityGrant ¶
Bases: FrozenModel
What a dispatched team is permitted to do (ASTR §4.7).
A capability grant attached to a team's task contract. Every capability defaults to False (deny by default): a caller must explicitly widen a team's authority. The framework enforces may_create_blocking_finding in dispatch_team code — a team whose grant forbids blocking findings cannot persist one, regardless of what its agents' prompts say.
Attributes:
| Name | Type | Description |
|---|---|---|
may_create_blocking_finding | bool | Whether this team may persist a |
may_write | bool | Whether a later-phase specialist coding runtime granted to this team may modify files. A Codex |
may_approve | bool | Whether this team may approve/accept work (e.g. mark a finding remediated or sign off an artifact revision). |
Budget ¶
Bases: FrozenModel
How much a dispatched team may spend (ASTR §6.2).
The resource envelope attached to a team's task contract. All three limits are non-negative; a negative value is rejected at construction (FrozenModel validates assignments). A value of 0 means "no explicit limit supplied" — dispatch_team only overrides the run-default swarm execution_timeout when max_wall_clock_minutes is strictly positive.
Attributes:
| Name | Type | Description |
|---|---|---|
max_wall_clock_minutes | float | Wall-clock ceiling for the team, in minutes. |
max_cost_usd | float | Dollar ceiling for the team. This is the framework-contract value that a Bedrock |
max_retries | int | Retry ceiling. Bounds a Codex harness's retry count when a specialist coding runtime is granted (research-coding-runtimes.yaml codex_gpt56_bedrock; consumed in Phase 3 / spec 004-coding-runtime). |
Bundle ¶
CalibratedJudgment ¶
Decision ¶
Bases: FrozenModel
An auditable record of a consequential choice (ASTR §11).
Captures the full deliberation: the question, the options considered, what was selected, the rationale, the evidence (reusing the P1 :class:Evidence vocabulary — file:line / test / command exit / artifact / url / log, AC-2-2), any dissent, and the prior decision_id this record supersedes when it reverses or replaces an earlier decision (AC-2-3). The PolicyEngine appends one on every allow/deny verdict (AC-2-4).
Attributes:
| Name | Type | Description |
|---|---|---|
decision_id | str | Unique identity of this decision (auto UUID hex if omitted). |
question | str | The question the decision answers. |
options | list[str] | The options that were considered. |
selected | str | The option that was chosen. |
rationale | str | Why the selection was made. |
evidence | list[Evidence] | Evidence refs backing the decision (reuses the P1 type — AC-2-2). |
dissent | list[str] | Recorded dissenting views (empty when unanimous). |
supersedes | list[str] | Prior |
decided_at | datetime | UTC timestamp the decision was recorded. |
Evidence ¶
Bases: FrozenModel
A single evidence reference backing a finding.
Attributes:
| Name | Type | Description |
|---|---|---|
type | EvidenceType | The kind of evidence ( |
uri | str | A locator for the evidence — e.g. |
detail | str | None | Optional human-readable note about what this evidence shows. |
Finding ¶
Bases: FrozenModel
A typed, evidence-bearing finding produced by a team (ASTR §6.6, §8.3).
Immutable and extra="forbid" (inherited from :class:FrozenModel), so a finding is safe to pass by reference through invocation_state and any on-disk findings.json that carries unknown keys is rejected at the parse boundary rather than silently accepted.
Attributes:
| Name | Type | Description |
|---|---|---|
statement | str | The finding itself, stated in one or two sentences (non-empty). |
severity | Severity | One of |
blocking | bool | Whether this finding must be resolved before the work is accepted. A |
disposition | Disposition | Lifecycle state (defaults to |
affected_artifacts | list[str] | Paths/ids of artifacts this finding is about. |
evidence | list[Evidence] | Evidence refs backing the finding (file:line / test / command exit / artifact / url / log). |
confidence | float | Calibrated confidence in |
created_by | str | Identifier of the agent/team that authored the finding. |
created_at | datetime | UTC creation timestamp. |
updated_at | datetime | UTC timestamp of the last lifecycle update. |
FrozenModel ¶
Bases: BaseModel
Immutable model (like a frozen dataclass).
This model: - Prevents mutation (frozen=True) - Validates assignments - Forbids extra fields
Use for result objects and immutable data transfer.
GeneratedFile ¶
HumanDecision ¶
Bases: FrozenModel
A first-class human-gate protocol state (ASTR §14, §5.2).
Where a transition kind is human-gated, the PolicyEngine emits one of these as pending rather than letting the model self-approve (AC-4-1). The runner persists it to disk and suspends the outer loop for that transition until a human resolves it (AC-4-3, AC-4-5); an approving resolution resumes and re-authorizes the transition (AC-4-4), a rejecting one abandons it (AC-4-6).
Attributes:
| Name | Type | Description |
|---|---|---|
decision_id | str | Unique identity of this gate (auto UUID hex if omitted). |
transition | TransitionRequest | The :class: |
prompt | str | The human-readable question posed to the human. |
options | list[str] | The choices offered to the human. |
status | HumanDecisionStatus |
|
resolved_by | str | Principal who resolved the gate (empty while pending). |
resolved_at | datetime | None | UTC timestamp of resolution ( |
created_at | datetime | UTC timestamp the gate was emitted. |
resolve ¶
Return a resolved copy of this gate (frozen — never mutates in place).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
approved | bool |
| required |
resolved_by | str | The principal resolving the gate. | required |
resolved_at | datetime | None | Resolution timestamp; defaults to now. | None |
Returns:
| Type | Description |
|---|---|
HumanDecision | A new :class: |
Source code in packages/strands-teams/src/strands_teams/models.py
PhaseTiming ¶
PolicyVerdict ¶
Bases: FrozenModel
The PolicyEngine's final allow/deny on a transition (ASTR §14.7, AC-3-1).
The model never decides — this verdict, produced by PolicyEngine.authorize_transition, is the authority (AC-3-1). On a deny, failed_gate names which gate in the ordered stack refused and reason is human-readable. On an allow, failed_gate is None (AC-3-6). When the denying gate is human_required, pending_human_decision carries the gate the runner must suspend on (AC-4-1).
Attributes:
| Name | Type | Description |
|---|---|---|
allowed | bool | Whether the transition is authorized. |
failed_gate | GateName | None | The gate that refused ( |
reason | str | Human-readable explanation of the verdict. |
pending_human_decision | HumanDecision | None | The pending gate to suspend on, set only when |
PromotionResult ¶
Bases: FrozenModel
The structured outcome of a successful promote_artifact compare-and-set (AC-2-6).
Returned (as model_dump_json()) by the promote_artifact tool so the calling agent parses JSON per the strands tool norm (research-coding-runtimes line 26).
Attributes:
| Name | Type | Description |
|---|---|---|
logical_name | str | The promoted artifact's logical name. |
current_revision | str | The new current |
superseded_revision | str | The prior current |
RevisionConflictError ¶
Bases: Exception
Raised when a revision_id is re-persisted with content differing from the stored one (AC-1-5).
The revision store is content-addressed and append-only: a given revision_id binds to exactly one content_hash. Re-persisting the same revision_id with identical content is idempotent; re-persisting it with differing content is a conflict that leaves the stored revision unchanged.
Attributes:
| Name | Type | Description |
|---|---|---|
revision_id | The revision id that was re-persisted with differing content. | |
stored_hash | The content hash already on disk for that revision id. | |
incoming_hash | The content hash of the rejected write. |
Record the conflicting revision id and the stored vs. incoming content hashes.
Source code in packages/strands-teams/src/strands_teams/models.py
StaleArtifactError ¶
Bases: Exception
Raised by promote_artifact when the optimistic compare-and-set fails (AC-2-3).
Signals that expected_current_revision did not match the alias's stored current revision for logical_name — another promotion won the race, or the caller's view of "current" is stale. The alias pointer is left unchanged.
Attributes:
| Name | Type | Description |
|---|---|---|
logical_name | The artifact whose promotion was rejected. | |
expected | The revision the caller believed was current. | |
actual | The revision actually current in the alias store. |
Record the artifact, the expected revision, and the actually-current one.
Source code in packages/strands-teams/src/strands_teams/models.py
StrictModel ¶
Bases: BaseModel
Base model with strict validation.
This model: - Allows mutation (frozen=False) - Validates assignments - Forbids extra fields - Strips whitespace from strings
Use for internal mutable state.
TeamConfidence ¶
Bases: FrozenModel
Confidence metadata attached to any team judgment.
Renamed from AnalysisConfidence to keep the framework layer domain-agnostic.
TeamEvent ¶
Bases: FrozenModel
A typed, causal, replayable event on the team event plane (ASTR §6.5, §7).
Immutable and extra="forbid" (inherited from :class:FrozenModel): an unexpected field — notably a raw-transcript or chain-of-thought field — is rejected at construction rather than silently accepted (AC-1-4). Serializing one event to a single JSON line and re-parsing it yields an equal object, so the event log is a lossless round-trip substrate for replay (AC-1-5).
event_id, created_at, and correlation_id are auto-assigned when omitted: a fresh UUID event id, a UTC creation timestamp, and a correlation id defaulting to goal_id when present and otherwise to the assigned event_id (AC-1-3).
Attributes:
| Name | Type | Description |
|---|---|---|
event_id | str | Unique identity of this event (auto-assigned UUID hex if omitted). |
event_type | str | The kind of transition/claim (e.g. |
actor | str | Identifier of the agent/team/runtime that produced the event. |
recipients | list[str] | Identifiers this event is addressed to (empty = broadcast). |
thread_id | str | The conversation/thread this event belongs to. |
goal_id | str | The goal (durable lead loop) this event belongs to. |
task_id | str | The task within the goal this event belongs to. |
artifact_bindings | list[str] |
|
causal_parents | list[str] |
|
correlation_id | str | Groups related events; defaults to |
epistemic_status | EpistemicStatus | The claim's standing (AC-1-2). |
payload | dict[str, Any] | The structured outcome of the transition — NO transcript/CoT. |
evidence | list[Evidence] | Evidence refs backing the event (reuses the P1 type). |
created_at | datetime | UTC creation timestamp (auto-assigned if omitted). |
TransitionRequest ¶
Bases: FrozenModel
A proposed consequential state transition the PolicyEngine judges (ASTR §14.7).
The model constructs one of these and hands it to PolicyEngine.authorize_transition; the engine — never the model — issues the final verdict (AC-6-1). A consequential transition (e.g. a release or a merge) is refused unless a valid revision-bound approval is present and no open blocking finding remains (AC-6-2, AC-6-3).
Attributes:
| Name | Type | Description |
|---|---|---|
actor | str | The principal requesting the transition (the capability and separation-of-duties gates read this — AC-3-2, AC-3-3). |
kind | str | The transition kind (e.g. |
target_revision_id | str | The |
consequential | bool | Whether this transition is consequential (release path) and thus subject to the structural approval + blocking-finding refusal (AC-6-2, AC-6-3). |
presented_tokens | list[str] | The |
required_capability | Literal['may_write', 'may_approve', 'may_create_blocking_finding'] | The :class: |
target_artifact | str | Optional logical artifact name the transition targets, used to match findings that reference the artifact by name as well as by revision id (AC-3-5). |
PhaseSpec dataclass ¶
Describes the ordered phases of a run for progress display and tagging.
Attributes:
| Name | Type | Description |
|---|---|---|
names | Mapping[int, str] | Map of phase index (1-based) to human-readable phase name. |
descriptions | Mapping[int, str] | Map of phase index to a one-line description. |
tool_phase_map | Mapping[str, int] | Map of exact tool name to the phase index it belongs to. |
prefix_rules | Mapping[str, int] | Map of tool-name prefix to a phase index, applied when no exact match is found in |
name ¶
description ¶
resolve ¶
Resolve a tool name to its phase index.
Checks the exact tool_phase_map first, then prefix_rules.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool_name | str | The invoked tool's name. | required |
Returns:
| Type | Description |
|---|---|
int | None | The phase index, or |
Source code in packages/strands-teams/src/strands_teams/phases.py
PolicyEngine ¶
Runs the ordered authority-gate stack over a transition (AC-3-1).
Construct one with the run's signing_key, required_approvals threshold, and human_gated_kinds (all from :class:~strands_teams.TeamsSettings), then call :meth:authorize_transition with the transition and the invocation_state dict. The engine reads grants, the approval store, findings, and current revision hashes from that state by reference; it never writes to it (AC-3-7).
Attributes:
| Name | Type | Description |
|---|---|---|
signing_key | Key that approval signatures must verify against; a token that fails verification is treated as absent (AC-1-4). | |
required_approvals | Valid revision-bound approvals a consequential transition needs before the required-approvals gate passes (AC-3-4). | |
human_gated_kinds | Transition kinds that are human-gated (AC-4-1). |
Initialize the engine with the run's policy configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signing_key | str | The approval signing/verification key. | required |
required_approvals | int | Required valid approvals for a consequential transition. | 1 |
human_gated_kinds | Sequence[str] | Transition kinds that must go through a human gate. | () |
Source code in packages/strands-teams/src/strands_teams/policy.py
authorize_transition ¶
Return the final allow/deny verdict for transition (AC-3-1, AC-3-6).
Runs the gate stack in order and short-circuits on the first failure. When every gate passes for a non-human-gated transition, returns allowed=True (AC-3-6). Reads all state from invocation_state by reference and does not mutate it (AC-3-7).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transition | TransitionRequest | The proposed transition to judge. | required |
invocation_state | Mapping[str, Any] | The run state (grants/approvals/findings/revision hashes) read by reference. | required |
now | datetime | None | Clock override for expiry checks (defaults to real UTC now). | None |
Returns:
| Name | Type | Description |
|---|---|---|
A | PolicyVerdict | class: |
PolicyVerdict | the pending :class: |
Source code in packages/strands-teams/src/strands_teams/policy.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | |
Review ¶
Bases: FrozenModel
A lightweight revision-bound review (AC-3-1).
A minimal record for callers that want to bind a review to an artifact revision without producing a full :class:~strands_teams.models.Finding. Immutable; reviewed_revision is the revision_id the review was produced against and reviewed_facets are the facets it covers (empty = the whole artifact).
Attributes:
| Name | Type | Description |
|---|---|---|
review_id | str | Identifier of the review. |
reviewed_revision | str | The |
reviewed_facets | list[str] | The artifact facets this review covers (empty = whole artifact — any changed facet invalidates it). |
summary | str | Optional human-readable summary of the review. |
ReviewReconciliation ¶
Bases: FrozenModel
Result of reconciling a set of bound reviews against a promoted revision (AC-3-6).
Attributes:
| Name | Type | Description |
|---|---|---|
carried_forward | list[ReviewVerdict] | Reviews :func: |
reopened | list[ReviewVerdict] | Reviews reported as invalidated — must be recomputed against the new revision. |
errored | list[ReviewVerdict] | Reviews whose bound revision is not in the new revision's lineage (AC-3-5) — surfaced, never silently dropped. |
ReviewVerdict ¶
Bases: FrozenModel
The structured outcome of :func:invalidates_review (AC-3-3, AC-3-4, AC-3-5).
Attributes:
| Name | Type | Description |
|---|---|---|
status | ReviewStatus |
|
reason | str | Human-readable explanation of the verdict. |
changed_facets | list[str] | Facets |
intersecting_facets | list[str] | The changed facets that the review covers (the invalidation trigger; empty when |
NarrativeRubric dataclass ¶
The single rubric object: dimensions + revision threshold.
Attributes:
| Name | Type | Description |
|---|---|---|
dimensions | tuple[RubricDimension, ...] | Ordered scoring dimensions. |
revision_threshold | float | Average (and per-artifact) score below which the artifact needs a revision pass (default |
score ¶
Score text across every dimension.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text | str | The narrative artifact content to score. | required |
Returns:
| Name | Type | Description |
|---|---|---|
A | ScoreReport | class: |
ScoreReport | average, the | |
ScoreReport | threshold), and improvement suggestions for weak dimensions. |
Source code in packages/strands-teams/src/strands_teams/rubric.py
RubricDimension dataclass ¶
RubricDimension(
name,
thresholds,
suggestion,
pattern=None,
flags=0,
unique=False,
counter=None,
weak_score=2.0,
)
One scored dimension of a narrative artifact.
A dimension measures a count from the text (via a regex pattern or a counter callable), then maps that count to a 0-5 score using an ascending (min_count, score) threshold table: the score is the highest table entry whose min_count does not exceed the measured count.
Attributes:
| Name | Type | Description |
|---|---|---|
name | str | Dimension key (e.g., |
thresholds | tuple[tuple[int, float], ...] | Ascending |
suggestion | str | Improvement hint; may contain a |
pattern | str | None | Regex whose match count is the measure. Ignored if |
flags | int | Regex flags applied to |
unique | bool | If True, count distinct matches rather than all matches. |
counter | Callable[[str], int] | None | Callable measuring the count directly (overrides |
weak_score | float | Emit |
measure ¶
Return the raw count this dimension measures from text.
Source code in packages/strands-teams/src/strands_teams/rubric.py
score_count ¶
Map a measured count to its 0-5 score via the threshold table.
Source code in packages/strands-teams/src/strands_teams/rubric.py
ScoreReport dataclass ¶
Result of scoring a text against a :class:NarrativeRubric.
StreamResult ¶
Bases: BaseModel
Result of a coordinator run.
ResourceUsage ¶
Bases: FrozenModel
Cost and token accounting reported by a specialist harness run (ASTR §10.4).
Immutable and extra="forbid" (inherited from :class:FrozenModel). Every field defaults to a zero-ish value so an adapter can report a partial accounting (e.g. a Codex run that surfaces token counts but no dollar cost) without constructing an invalid object.
Attributes:
| Name | Type | Description |
|---|---|---|
cost_usd | float | Dollar cost of the run (Claude |
input_tokens | int | Total input tokens consumed. |
output_tokens | int | Total output tokens generated. |
num_turns | int | Number of agent turns (tool-use round trips) the harness took. |
duration_seconds | float | Wall-clock duration of the run, in seconds. |
SpecialistResult ¶
Bases: FrozenModel
The structured outcome of one specialist harness run (ASTR §10.4).
This is the ONLY thing that crosses the harness boundary back into the swarm's context. It carries a disposition, the artifacts the harness changed, typed findings, evidence refs, a residual-risk note, and resource usage — but never the raw transcript, private chain-of-thought, or full terminal command log (ASTR §10.4; plan §5 "Boundary discipline"). Immutable and extra="forbid" (inherited from :class:FrozenModel), so an out-of-range disposition or an unexpected extra field is rejected at construction rather than silently coerced (AC-2-7).
Attributes:
| Name | Type | Description |
|---|---|---|
disposition | SpecialistDisposition | How the run concluded — one of |
artifacts | list[str] | Worktree-relative path strings the harness created or modified (ground truth derivable from |
findings | list[Finding] | Typed :class: |
evidence | list[Evidence] | Standalone :class: |
residual_risk | str | A short prose note on risk the harness could not eliminate (empty string when none). |
resource_usage | ResourceUsage | Cost/token/turn/duration accounting for the run. |
SpecialistRuntime ¶
Bases: Protocol
Structural interface for an autonomous external coding harness (ASTR §10).
A SpecialistRuntime drives one bounded coding task in its own OS subprocess (a Claude Agent SDK query() subprocess, or codex exec) and reports back only a :class:SpecialistResult. This Protocol is defined in strands_teams core without importing any coding-agent SDK or subprocess — the concrete adapters live in strands_teams_runtimes and are injected into the coding tool by dependency injection, so core stays vendor-free (plan §3; research-coding-runtimes.yaml architecture).
Implementations are typically async because they await a subprocess; a runtime_checkable Protocol only checks method presence, not signatures, so both sync and async adapters satisfy it structurally.
The five methods model a submit/poll/collect lifecycle:
submit(task, *, workspace, model_id, capabilities)— start a harness run rooted atworkspace(its only writable root) and return an opaque run-handle/id.status(handle)— report the run's current lifecycle state.send_input(handle, text)— feed additional input to a running harness.cancel(handle)— cancel a running harness (e.g. on a wall-clock timeout).collect(handle)— return the :class:SpecialistResult. Returns the structured result only — never the harness raw transcript, private chain-of-thought, or full terminal command log (ASTR §10.4).
TeamsSettings ¶
Bases: BaseSettings
Base settings for a strands_teams use case.
Subclass this and override model_config to set the env prefix, and set output_dir_name to the use case's artifact directory name.
Attributes:
| Name | Type | Description |
|---|---|---|
output_dir_name | str | Directory name for run artifacts, relative to the target root (e.g., |
TeamInvocationState ¶
Bases: TypedDict
Shared state propagated to every coordinator tool via invocation_state.
Built by the coordinator factory (:mod:strands_teams.coordinator) and passed to coordinator.invoke_async(prompt, invocation_state=...) by the runner, which strands forwards to each tool's tool_context.invocation_state. This replaces the pre-split module-level _output_dir / _repo_path / _tool_registry globals (AC-8-4).
Keys
layout: The run's :class:~strands_teams.layout.TeamsLayout (all paths). tool_registry: Map of tool name -> tool object, for resolving the string tool names in team-agent specs to real tool objects. node_model_config: Kwargs passed to BedrockModel(**config) when constructing each fresh team-agent node. execution_timeout: Default max seconds for an entire team swarm. node_timeout: Default max seconds per agent node within a team. use_case_name: The active use case's name (for logging/debug). rubric: The :class:~strands_teams.rubric.NarrativeRubric used by score_narrative. authority: The active team's :class:~strands_teams.models.AuthorityGrant (what it may do). Present only inside a dispatched team's swarm invocation_state; the coordinator's own state omits it. Treat it as a read-only shared reference — never mutate it from within a concurrently-executing node tool (AC-5-3; research-coding-runtimes.yaml strands_tool_pattern lines 20-22, 30). budget: The active team's :class:~strands_teams.models.Budget (how much it may spend). Same read-only, dispatched-team-only contract as authority. acceptance_criteria: The acceptance criteria the active team must satisfy. input_revisions: Opaque revision-identifier strings the team should build on (resolved to Phase-4 ArtifactRevision objects in a later phase; treated as opaque strings here — AC-2-7).
MissingUseCaseMemberError ¶
Bases: TypeError
Raised when a UseCase omits a required member.
The message names the missing member so the failure is actionable rather than a silent default (AC-5-5).
Build the error, recording the use-case name and missing member.
Source code in packages/strands-teams/src/strands_teams/usecase.py
UseCase ¶
Bases: ABC
Abstract contract a domain implements to run on strands_teams.
Class attributes (a concrete subclass must set these): name: Stable identifier for the use case. structured_output_model: Pydantic model type for the coordinator's structured output. findings_format_directive: Text injected into a dispatched team's Required-Output block describing the findings format.
Instance attributes (set in __init__): settings: The use case's :class:~strands_teams.settings.TeamsSettings subclass instance (env prefix + output dir). layout: The :class:~strands_teams.layout.TeamsLayout describing artifact paths for this run. rubric: The :class:~strands_teams.rubric.NarrativeRubric for scoring. phases: The :class:~strands_teams.phases.PhaseSpec (tool→phase + names). reasoning_prompts: Map of tool name to a reasoning-checkpoint prompt. fail_fast_exempt: Tool names whose error results are non-fatal.
domain_tools abstractmethod ¶
prompt_template abstractmethod ¶
template_dir abstractmethod ¶
planning_context abstractmethod ¶
Load the planning context injected into the coordinator prompt.
Typically reads the planning sentinel via self.layout.planning_sentinel_path().
Source code in packages/strands-teams/src/strands_teams/usecase.py
kickoff_prompt abstractmethod ¶
Build the initial task prompt handed to the coordinator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bundles_only | bool | Skip indexing/dispatch and regenerate artifacts only. | required |
focus | str | None | Optional area the run should prioritize. | required |
extra_context | str | None | Optional free-form context to append. | required |
Returns:
| Type | Description |
|---|---|
str | The kickoff prompt string. |
Source code in packages/strands-teams/src/strands_teams/usecase.py
artifact_structure_spec abstractmethod ¶
pre_run ¶
Optional deterministic pre-run step (e.g., indexing).
Default implementation is a no-op. A use case overrides this to produce its planning sentinel before the coordinator runs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
repo_path | Path | The target root the run operates on. | required |
Source code in packages/strands-teams/src/strands_teams/usecase.py
create_coordinator ¶
Create the coordinator Agent and its per-run invocation state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
use_case | UseCase | The domain use case supplying tools, prompt, model, layout, rubric, and structured-output model. | required |
full_mode | bool | Select full-mode reasoning effort and timeouts when True. | False |
focus | str | None | Optional focus area (the use case bakes this into the kickoff prompt built by the runner; kept for signature symmetry). | None |
hooks | list[HookProvider] | None | Optional | None |
Returns:
| Type | Description |
|---|---|
Agent | A |
TeamInvocationState |
|
Raises:
| Type | Description |
|---|---|
MissingUseCaseMemberError | If the use case omits a required member (AC-5-5). |
Source code in packages/strands-teams/src/strands_teams/coordinator.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
replay ¶
Reconstruct run state from events with no live model call (AC-3-1..AC-3-5).
Applies each event only after all its causal parents (:func:_causal_order, AC-3-3), records the transition sequence, tracks the latest non-superseded event per artifact binding, reconstructs finding and decision payloads, and reflects supersession (an event bearing epistemic_status="superseded" or an event naming another in its causal_parents with an epistemic_status in {accepted, rejected, superseded} supersedes that parent) while retaining the originals in the log (AC-3-4).
Deterministic: given the same events (and malformed-line warnings), the returned :class:ReplayState is identical across calls (AC-3-2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events | Iterable[TeamEvent] | The parsed events to replay (typically | required |
warnings | Iterable[str] | Malformed-line warnings from parsing, folded into the result so :meth: | () |
Returns:
| Name | Type | Description |
|---|---|---|
A | ReplayState | class: |
Source code in packages/strands-teams/src/strands_teams/events.py
replay_log ¶
Replay an :class:EventLog end to end, surfacing malformed-line warnings (AC-3-5).
Source code in packages/strands-teams/src/strands_teams/events.py
should_replan ¶
Decide whether the lead loop should replan (AC-6-1..AC-6-7).
Scans the event log for any of the five ASTR triggers — requirement.changed, critical_finding.created, task.failed, budget.threshold_exceeded, artifact.interface_changed — matching on either an explicit trigger-typed event or the structured payload of a generic dispatch/finding/revision event. Cumulative recorded cost crossing budget_threshold fires the budget trigger (AC-6-4). Returns replan=False with no triggers on a trigger-free log (AC-6-7).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events | Iterable[TeamEvent] | The events to evaluate (typically | required |
budget_threshold | float | The configured cumulative-cost bound; | 0.0 |
Returns:
| Name | Type | Description |
|---|---|---|
A | ReplanDecision | class: |
Source code in packages/strands-teams/src/strands_teams/events.py
evaluate_evidence_gate ¶
Evaluate the evidence gate over a collection of findings (AC-5-1..5-3).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
findings | Iterable[Finding] | The typed findings to check. | required |
Returns:
| Name | Type | Description |
|---|---|---|
An | EvidenceGateResult | class: |
EvidenceGateResult |
| |
EvidenceGateResult | finding's statement so the coordinator can act on the gap. |
Source code in packages/strands-teams/src/strands_teams/evidence_gate.py
gate_findings ¶
Return the evidence-gate summary as a plain dict for embedding in tool JSON.
Convenience wrapper around :func:evaluate_evidence_gate producing the evidence_gate block used by the write and read tool results (AC-5-2, AC-5-3).
Source code in packages/strands-teams/src/strands_teams/evidence_gate.py
run_goal async ¶
run_goal(
goal,
*,
layout,
invocation_state=None,
dispatch=None,
engine=None,
max_iterations=8,
budget_threshold=0.0,
goal_id=None,
thread_id="",
)
Drive the durable lead loop for goal to a terminal status (AC-5-1, AC-5-3..AC-5-7).
Runs decompose → compose → assign → dispatch → integrate each iteration, each as a :class:~strands_teams.durable.DurableStep recording a :class:~strands_teams.models.TeamEvent (AC-5-3). After integrate it consults :func:~strands_teams.events.should_replan over the run's :class:EventLog; when a trigger fires it records a goal.replan event and re-enters decompose (AC-5-7). Terminates — with a final goal.terminated event — on convergence (no replan), on reaching max_iterations, or on crossing budget_threshold (AC-5-6). Never calls asyncio.run (AC-5-2 is the sync boundary).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
goal | str | The goal statement driving the loop. | required |
layout | TeamsLayout | The run's :class: | required |
invocation_state | dict[str, Any] | None | The by-reference dict propagated to dispatched teams; | None |
dispatch | Callable[[dict[str, Any], dict[str, Any]], Awaitable[dict[str, Any]]] | None | Injectable dispatch callable (AC-5-5); defaults to :func: | None |
engine | DurableStep | None | The :class: | None |
max_iterations | int | Hard cap on lead-loop iterations (AC-5-6). | 8 |
budget_threshold | float | Cumulative-cost bound; crossing it terminates the loop and fires the budget replan trigger (AC-5-6, AC-6-4). | 0.0 |
goal_id | str | None | Stable id for the goal (auto-assigned when omitted). | None |
thread_id | str | Optional conversation/thread id propagated to teams. | '' |
Returns:
| Name | Type | Description |
|---|---|---|
A | GoalResult | class: |
Source code in packages/strands-teams/src/strands_teams/goal_runner.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | |
run_goal_sync ¶
run_goal_sync(
goal,
*,
layout,
invocation_state=None,
dispatch=None,
engine=None,
max_iterations=8,
budget_threshold=0.0,
goal_id=None,
thread_id="",
)
Synchronous wrapper around :func:run_goal (AC-5-2).
Mirrors :func:~strands_teams.runner.run_teams_sync: the single asyncio.run boundary. Never call this from inside an already-running event loop — use the async :func:run_goal there (research-coding-runtimes.yaml line 18).
Source code in packages/strands-teams/src/strands_teams/goal_runner.py
compute_content_hash ¶
Return a deterministic content hash over a revision's facet contents (AC-1-2).
The hash is a function of the facet content alone — not of any metadata (logical_name, produced_by, created_at). Each facet's content is hashed independently, then those per-facet hashes are folded into one digest via :func:compute_content_hash_from_facet_hashes (so the whole-artifact hash and the per-facet hashes on the persisted record always agree). Two revisions built from byte-identical facet content therefore produce equal hashes; any differing byte produces a different hash (AC-1-2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
facets | Mapping[str, str] | Mapping of facet name to that facet's content string. An empty mapping hashes to the well-defined fold of | required |
Returns:
| Type | Description |
|---|---|
str | A 64-char lowercase hex SHA-256 digest. |
Source code in packages/strands-teams/src/strands_teams/models.py
denying_decision ¶
Build an auditable :class:Decision recording a denied transition (AC-4-6).
Used by the runner when a human rejects a gate or the engine refuses a transition, so the denial is captured as a first-class artifact rather than living only in a log line.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
verdict | PolicyVerdict | The denying verdict. | required |
transition | TransitionRequest | The transition that was refused. | required |
Returns:
| Type | Description |
|---|---|
Decision | A frozen :class: |
Source code in packages/strands-teams/src/strands_teams/policy.py
invalidates_review ¶
Decide whether new_revision invalidates a review bound to old_binding (AC-3-3..5).
Runs :func:semantic_diff between the revisions and intersects the changed facets with the facets the review covers:
- invalidated when the intersection is non-empty — a facet the review examined changed, so the review must be re-opened (AC-3-3).
- valid when the intersection is empty — the review's facets are untouched, so it is carried forward and reused rather than recomputed (AC-3-4). A review that covers no specific facets (empty
reviewed_facets) is treated as covering the WHOLE artifact, so any changed facet invalidates it. - error when
new_revision's lineage does not supersede the review's bound revision — the verdict cannot be trusted, so it is reported as an error rather than silently treated as valid or invalidated (AC-3-5).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
old_binding | ArtifactRevision | The revision the review was produced against. | required |
new_revision | ArtifactRevision | The candidate new revision. | required |
review | ReviewBinding | Any | A revision-bound review — a :class: | required |
Returns:
| Name | Type | Description |
|---|---|---|
A | ReviewVerdict | class: |
ReviewVerdict | intersecting facet sets. |
Source code in packages/strands-teams/src/strands_teams/revisions.py
promote_artifact ¶
Promote a new revision of a logical artifact by optimistic compare-and-set.
Makes proposed_revision the current revision of logical_name ONLY when expected_current_revision still matches the alias's stored current revision — a durable optimistic lock. If another promotion changed the current revision since you read it, this returns a status="stale" error and leaves the alias unchanged; re-read the current revision and retry. Pass the sentinel "∅" as expected_current_revision for the FIRST promotion of a logical name.
The proposed revision's content is content-addressed: supply its content as proposed_revision={"facets": {"<facet>": "<content>", ...}} (preferred, so facet-level review invalidation works) or {"body": "<content>"}; the revision id and content hash are computed from that content. On success the prior current revision is recorded in the new revision's supersedes lineage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logical_name | str | The logical artifact to promote (e.g. | required |
expected_current_revision | str | The revision id you believe is current, or the sentinel | required |
proposed_revision | dict[str, Any] | The new revision's content as a JSON dict — | required |
tool_context | ToolContext | Framework-injected run context (invocation state). | required |
Returns:
| Type | Description |
|---|---|
str | On success, a JSON object with |
str |
|
str | when this was the first revision). On a failed compare-and-set, |
str |
|
str | you can re-read and retry. |
Source code in packages/strands-teams/src/strands_teams/revisions.py
reconcile_reviews ¶
Partition bound reviews into carried-forward, re-opened, and errored (AC-3-6).
When a re-run promotes a new revision of a logical artifact, every bound review that :func:invalidates_review reports as still valid is carried forward (reused), only the invalidated reviews are re-opened, and any lineage-mismatch review is surfaced as an error (AC-3-5, AC-3-6).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
old_binding | ArtifactRevision | The revision the reviews were produced against. | required |
new_revision | ArtifactRevision | The newly promoted revision. | required |
reviews | Iterable[ReviewBinding | Any] | The bound reviews to reconcile. | required |
Returns:
| Name | Type | Description |
|---|---|---|
A | ReviewReconciliation | class: |
Source code in packages/strands-teams/src/strands_teams/revisions.py
semantic_diff ¶
Return the set of artifact facets whose content changed between two revisions (AC-3-2).
Compares the two revisions' per-facet content hashes (:attr:~strands_teams.models.ArtifactRevision.facets). A facet is changed when its hash differs between the revisions, when it exists in only one of them (added or removed), and unchanged when both hashes are equal. The comparison is over hashes, not raw content, so it is exact and cheap.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
old_revision | ArtifactRevision | The earlier revision. | required |
new_revision | ArtifactRevision | The later revision. | required |
Returns:
| Type | Description |
|---|---|
set[str] | The set of changed facet names. Empty when the two revisions carry |
set[str] | identical facet content. |
Source code in packages/strands-teams/src/strands_teams/revisions.py
run_teams async ¶
run_teams(
use_case,
*,
repo_path,
focus=None,
extra_context=None,
bundles_only=False,
full_mode=False,
quiet=False,
)
Run a use-case coordinator end to end.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
use_case | UseCase | The domain use case to run. | required |
repo_path | str | Path | The target root the run operates on (passed to | required |
focus | str | None | Optional focus area. | None |
extra_context | str | None | Optional free-form context for the kickoff prompt. | None |
bundles_only | bool | Skip dispatch and regenerate artifacts from existing findings. | False |
full_mode | bool | Use full-mode reasoning effort and timeouts. | False |
quiet | bool | Suppress the Rich display. | False |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | Dict with run status, duration, output paths, and the structured output. |
Source code in packages/strands-teams/src/strands_teams/runner.py
run_teams_sync ¶
run_teams_sync(
use_case,
*,
repo_path,
focus=None,
extra_context=None,
bundles_only=False,
full_mode=False,
quiet=False,
)
Synchronous wrapper around :func:run_teams.
Source code in packages/strands-teams/src/strands_teams/runner.py
dispatch_team async ¶
dispatch_team(
team_id,
mandate,
agents,
tool_context,
file_scope=None,
key_questions=None,
artifact_pointers=None,
acceptance_criteria=None,
authority=None,
budget=None,
input_revisions=None,
max_handoffs=10,
execution_timeout=None,
node_timeout=None,
)
Dispatch a specialist team to investigate one area and persist its findings.
Each team runs as a native Strands Swarm — a group of agents that hand off to one another to complete a mandate. The team's task is automatically augmented with a Required-Output block instructing the last agent to write its findings and metadata files (paths are supplied in the augmented task). A confined write_file tool is auto-added to every agent.
TASK CONTRACT — a team is dispatched under a typed authority + budget contract: - authority grants capabilities. A team whose grant has may_create_blocking_finding false CANNOT persist a blocking finding: this tool strips any such finding from the team's typed findings and returns an error. Enforcement is in this tool's code, not the agents' prompts. Omit authority to permit blocking findings (legacy behavior). - budget bounds resources. A positive max_wall_clock_minutes sets the swarm's execution timeout to max_wall_clock_minutes * 60. - acceptance_criteria are the conditions the team must satisfy; they are surfaced in the team task AND checked for coverage by the quality hook. - input_revisions are opaque revision-id strings the team builds on.
AGENT SPEC FORMAT — each entry in agents is a dict with: - name (str): unique node name (e.g. "analyst", "reader"). - system_prompt (str): role and instructions for this agent. - tools (list[str]): tool names for this agent, resolved from the coordinator's tool registry. Unknown names are dropped.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
team_id | str | Unique team identifier (e.g. | required |
mandate | str | What to investigate and why (1-3 sentences). | required |
agents | list[dict[str, Any]] | List of agent spec dicts (see AGENT SPEC FORMAT). | required |
tool_context | ToolContext | Framework-injected run context (invocation state). | required |
file_scope | list[str] | None | Optional file paths or directories to focus on. | None |
key_questions | list[str] | None | Optional questions the team should answer. | None |
artifact_pointers | list[str] | None | Optional pre-computed artifact paths to consult. | None |
acceptance_criteria | list[str] | None | Optional conditions the team's output must satisfy. | None |
authority | dict[str, Any] | None | Optional capability grant as a JSON dict with any of | None |
budget | dict[str, Any] | None | Optional resource envelope as a JSON dict with any of | None |
input_revisions | list[str] | None | Optional opaque revision-id strings the team builds on. | None |
max_handoffs | int | Max handoffs (and iterations) within the team. | 10 |
execution_timeout | float | None | Max seconds for the entire team. Omit for the run default. | None |
node_timeout | float | None | Max seconds per agent turn. Omit for the run default. | None |
Returns:
| Type | Description |
|---|---|
str | JSON with |
str |
|
str | rejected forbidden blocking finding — |
str |
|
Source code in packages/strands-teams/src/strands_teams/teams.py
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | |
enrich_artifact ¶
Read an existing artifact and prepare enrichment context.
Call when score_narrative reports needs_revision. Returns the current artifact content plus the feedback so you can rewrite it with improvements via write_artifact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
area | str | The artifact area to enrich (e.g. | required |
feedback | str | Specific feedback from | required |
tool_context | ToolContext | Framework-injected run context (invocation state). | required |
Returns:
| Type | Description |
|---|---|
str | JSON with the current artifact |
str |
|
Source code in packages/strands-teams/src/strands_teams/teams.py
read_team_findings ¶
Read findings from dispatched teams.
If team_id is None, lists all team directories with their status, metadata summary, and whether typed findings are present — use this to see which teams have completed. If team_id is given, returns that team's typed findings.json (parsed) when it exists and validates, AND the human findings.md narrative alongside it; when the typed sidecar is absent or invalid it falls back to the raw findings.md markdown.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tool_context | ToolContext | Framework-injected run context (invocation state). | required |
team_id | str | None | Specific team to read, or | None |
Returns:
| Name | Type | Description |
|---|---|---|
str | JSON listing all teams (when | |
str | content (when a | |
str | list of finding objects, | |
str | any blocking finding lacking evidence, | |
str | human | |
file | str | line prose, structured sections) when the file exists — this markdown |
str | is the rich input for bundle synthesis. For a fallback read, | |
str | is the markdown string and |
Source code in packages/strands-teams/src/strands_teams/teams.py
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 | |
score_narrative ¶
Score a per-area artifact's quality using the run's rubric.
Call after write_artifact to evaluate quality. If needs_revision is True (total below the rubric's revision threshold), call enrich_artifact and rewrite via write_artifact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
area | str | The artifact area to score (e.g. | required |
tool_context | ToolContext | Framework-injected run context (invocation state). | required |
Returns:
| Type | Description |
|---|---|
str | JSON with |
str | average, the |
Source code in packages/strands-teams/src/strands_teams/teams.py
write_artifact ¶
Write a per-area narrative artifact or the top-level executive summary.
All artifact paths come from the run's layout. Diagrams must use mermaid code-fenced blocks (never ASCII art). The artifact section structure the coordinator should follow is described in its system prompt, not here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
area | str | Artifact area identifier (e.g. | required |
content | str | The full markdown content to write. | required |
tool_context | ToolContext | Framework-injected run context (invocation state). | required |
is_executive_summary | bool | If True, write the executive summary instead of a per-area artifact. | False |
Returns:
| Type | Description |
|---|---|
str | JSON with |
Source code in packages/strands-teams/src/strands_teams/teams.py
validate_use_case ¶
Validate a concrete UseCase supplies every required member.
Called by the coordinator factory (Wave C) before constructing the coordinator. Raises with the missing member's name rather than proceeding with a silent default (AC-5-5).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
use_case | UseCase | The use-case instance to validate. | required |
Raises:
| Type | Description |
|---|---|
MissingUseCaseMemberError | If a required member is absent or |
Source code in packages/strands-teams/src/strands_teams/usecase.py
make_write_file ¶
Build a write_file tool confined to layout.output_root.
The returned tool is a normal strands @tool whose tool_name is write_file. It closes over layout so it needs no module-level state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
layout | TeamsLayout | The run's layout, whose | required |
Returns:
| Type | Description |
|---|---|
DecoratedFunctionTool | A decorated |
Source code in packages/strands-teams/src/strands_teams/write_file.py
make_write_findings ¶
Build a write_findings tool that persists typed findings for one team.
The returned tool validates its input against the :class:~strands_teams.models.Finding schema, serializes the collection to the team's findings.json (via :meth:~strands_teams.layout.TeamsLayout.findings_json_path), and flags any blocking=True finding that lacks evidence through the shared evidence gate (AC-3-2, AC-3-4, AC-5-2). It closes over layout and team_id so it needs no module-level state and writes only inside the run's team directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
layout | TeamsLayout | The run's layout; the sidecar path derives from it. | required |
team_id | str | The team whose | required |
Returns:
| Type | Description |
|---|---|
DecoratedFunctionTool | A decorated |